Skip to content

Commit

Permalink
Add USE_POSIX_SETLOCALE option
Browse files Browse the repository at this point in the history
Add USE_POSIX_SETLOCALE option for platforms missing uselocale().
Document locale options in README, Makefile & rockspec.

Also:
- Rename USE_POSIX_LOCALE define to USE_POSIX_USELOCALE.
- Use uselocale() by default through Makefile (Linux, OSX).
- Use setlocale() by default through rockspec (other platforms).
  • Loading branch information
mpx committed Oct 7, 2011
1 parent 48c5cf1 commit 049691c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 13 deletions.
8 changes: 6 additions & 2 deletions Makefile
Expand Up @@ -23,8 +23,12 @@ override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -DVERSION=\"$(CJSON_VERSION)\"
# Handle Solaris platforms that are missing isinf().
#override CFLAGS += -DUSE_INTERNAL_ISINF
# Handle locales that use comma as a decimal separator on locale aware
# platforms. Requires POSIX-1.2008 support.
override CFLAGS += -DUSE_POSIX_LOCALE
# platforms (optional, but recommended).
# USE_POSIX_USELOCALE: Linux, OSX. Thread safe. Recommended option.
# USE_POSIX_SETLOCALE: Works on all ANSI C platforms. May be used when
# thread-safety isn't required.
override CFLAGS += -DUSE_POSIX_USELOCALE
#override CFLAGS += -DUSE_POSIX_SETLOCALE

INSTALL ?= install

Expand Down
12 changes: 12 additions & 0 deletions README
Expand Up @@ -309,6 +309,18 @@ Lua CJSON will generate an error if asked to serialise Lua functions,
userdata, lightuserdata or threads.


Locale handling
---------------

Lua CJSON uses strtod() and snprintf() to perform numeric conversion
as they are usually well supported, fast and bug free.

To ensure JSON encoding/decoding works correctly for locales using
comma decimal separators, Lua CJSON must be compiled with either
USE_POSIX_USELOCALE or USE_POSIX_SETLOCALE. See the Makefile or the
rockspec for details.


References
==========

Expand Down
2 changes: 0 additions & 2 deletions TODO
Expand Up @@ -2,5 +2,3 @@
- Optionally create an object for settings. Clone function.

- Convert documentation into structured source format

- Add setlocale() support for non-POSIX 2008 operating systems
5 changes: 4 additions & 1 deletion lua-cjson-1.0.3-1.rockspec
Expand Up @@ -25,9 +25,12 @@ build = {
cjson = {
sources = { "lua_cjson.c", "strbuf.c" },
-- Optional workarounds:
-- USE_POSIX_USELOCALE: Linux, OSX. Thread safe. Recommended.
-- USE_POSIX_SETLOCALE: Works on all ANSI C platforms. May be used when
-- thread-safety isn't required.
-- USE_INTERNAL_ISINF: Provide internal isinf() implementation. Required
-- on some Solaris platforms.
defines = { "VERSION=\"1.0.3\"" }
defines = { "VERSION=\"1.0.3\"", "USE_POSIX_SETLOCALE" }
}
},
copy_directories = { "tests" }
Expand Down
38 changes: 30 additions & 8 deletions lua_cjson.c
Expand Up @@ -44,26 +44,46 @@

#include "strbuf.h"

#ifdef USE_POSIX_LOCALE
/* Reset locale to POSIX for strtod() / sprintf().
/* Support to reset locale to POSIX for strtod() / sprintf().
* Some locales use comma as a decimal separator. This breaks JSON. */
#ifdef USE_POSIX_USELOCALE

#ifdef USE_POSIX_SETLOCALE
#error Must not define USE_POSIX_USELOCALE and USE_POSIX_SETLOCALE simultaneously.
#endif

/* unistd.h defines _POSIX_VERSION */
#include <unistd.h>

#if _POSIX_VERSION >= 200809L
/* POSIX.1-2008 adds threadsafe locale support */
#include <locale.h>
#elif defined(_POSIX_VERSION)
/* Some pre-POSIX.1-2008 operating systems use xlocale.h instead */
/* Some pre-POSIX.1-2008 operating systems offer xlocale.h instead */
#include <xlocale.h>
#else
#error Missing _POSIX_VERSION define
#endif
#endif /* _POSIX_VERSION */

#define LOCALE_SET_POSIX(x) (x)->saved_locale = uselocale((x)->posix_locale)
#define LOCALE_RESTORE(x) uselocale((x)->saved_locale)
#else

#elif defined(USE_POSIX_SETLOCALE)
/* ANSI C / ISO C90 implementation. Not thread-safe, affects entire process. */
#include <locale.h>

#define LOCALE_SET_POSIX(x) \
do { \
(x)->saved_locale = setlocale(LC_NUMERIC, NULL); \
setlocale(LC_NUMERIC, "C"); \
} while(0)
#define LOCALE_RESTORE(x) setlocale(LC_NUMERIC, (x)->saved_locale)

#else /* Do not work around locale support in strtod() / sprintf() */

#define LOCALE_SET_POSIX(x) do { } while(0)
#define LOCALE_RESTORE(x) do { } while(0)

#endif

/* Some Solaris platforms are missing isinf(). */
Expand Down Expand Up @@ -122,9 +142,11 @@ typedef struct {
char *char2escape[256]; /* Encoding */
#endif
strbuf_t encode_buf;
#if USE_POSIX_LOCALE
#if defined(USE_POSIX_USELOCALE)
locale_t saved_locale;
locale_t posix_locale;
#elif defined(USE_POSIX_SETLOCALE)
const char *saved_locale;
#endif
char number_fmt[8]; /* "%.XXg\0" */
int current_depth;
Expand Down Expand Up @@ -369,7 +391,7 @@ static int json_destroy_config(lua_State *l)
json_config_t *cfg;

cfg = lua_touserdata(l, 1);
#ifdef USE_POSIX_LOCALE
#ifdef USE_POSIX_USELOCALE
if (cfg->posix_locale)
freelocale(cfg->posix_locale);
#endif
Expand All @@ -394,7 +416,7 @@ static void json_create_config(lua_State *l)
lua_setmetatable(l, -2);

strbuf_init(&cfg->encode_buf, 0);
#if USE_POSIX_LOCALE
#ifdef USE_POSIX_USELOCALE
cfg->saved_locale = NULL;
/* Must not lua_error() before cfg->posix_locale has been initialised */
cfg->posix_locale = newlocale(LC_ALL_MASK, "C", NULL);
Expand Down

0 comments on commit 049691c

Please sign in to comment.