diff options
| author | Mark Pulford <mark@kyne.com.au> | 2011-10-05 23:30:27 +1030 |
|---|---|---|
| committer | Mark Pulford <mark@kyne.com.au> | 2011-10-05 23:30:27 +1030 |
| commit | 0f3ab84a261292d16f684551e67f2f007199936a (patch) | |
| tree | 5ece4652a08b968232b417f5cf4ceaf234f2be2f /lua_cjson.c | |
| parent | 03fa2b508aee4cdf2eac41d53834412ac757feef (diff) | |
| download | lua-cjson-0f3ab84a261292d16f684551e67f2f007199936a.tar.gz lua-cjson-0f3ab84a261292d16f684551e67f2f007199936a.tar.bz2 lua-cjson-0f3ab84a261292d16f684551e67f2f007199936a.zip | |
Support locales which use comma decimal separators
Some locales (cs_CZ, de_DE,..) use a comma as their decimal separator.
This causes CJSON to generate incorrect JSON (Eg, [10,1]), and fail when
parsing some valid JSON (Eg, [10,"test"]).
Added USE_POSIX_LOCALE #define which harnesses the thread-safe
POSIX.1-2008 locale support (newlocale(), uselocale(), freelocale())
to temporarily use the POSIX locale during JSON conversion.
Some older POSIX operating systems with xlocale.h (MacOSX) are also
supported.
Diffstat (limited to '')
| -rw-r--r-- | lua_cjson.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index f765883..151fa39 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
| @@ -44,7 +44,30 @@ | |||
| 44 | 44 | ||
| 45 | #include "strbuf.h" | 45 | #include "strbuf.h" |
| 46 | 46 | ||
| 47 | #ifdef USE_POSIX_LOCALE | ||
| 48 | /* Reset locale to POSIX for strtod() / sprintf(). | ||
| 49 | * Some locales use comma as a decimal separator. This breaks JSON. */ | ||
| 50 | |||
| 51 | /* unistd.h defines _POSIX_VERSION */ | ||
| 52 | #include <unistd.h> | ||
| 53 | #if _POSIX_VERSION >= 200809L | ||
| 54 | /* POSIX.1-2008 adds threadsafe locale support */ | ||
| 55 | #include <locale.h> | ||
| 56 | #elif defined(_POSIX_VERSION) | ||
| 57 | /* Some pre-POSIX.1-2008 operating systems use xlocale.h instead */ | ||
| 58 | #include <xlocale.h> | ||
| 59 | #else | ||
| 60 | #error Missing _POSIX_VERSION define | ||
| 61 | #endif | ||
| 62 | #define LOCALE_SET_POSIX(x) (x)->saved_locale = uselocale((x)->posix_locale) | ||
| 63 | #define LOCALE_RESTORE(x) uselocale((x)->saved_locale) | ||
| 64 | #else | ||
| 65 | #define LOCALE_SET_POSIX(x) do { } while(0) | ||
| 66 | #define LOCALE_RESTORE(x) do { } while(0) | ||
| 67 | #endif | ||
| 68 | |||
| 47 | #ifdef MISSING_ISINF | 69 | #ifdef MISSING_ISINF |
| 70 | /* Some Solaris platforms are missing isinf(). Define here. */ | ||
| 48 | #define isinf(x) (!isnan(x) && isnan((x) - (x))) | 71 | #define isinf(x) (!isnan(x) && isnan((x) - (x))) |
| 49 | #endif | 72 | #endif |
| 50 | 73 | ||
| @@ -99,6 +122,10 @@ typedef struct { | |||
| 99 | char *char2escape[256]; /* Encoding */ | 122 | char *char2escape[256]; /* Encoding */ |
| 100 | #endif | 123 | #endif |
| 101 | strbuf_t encode_buf; | 124 | strbuf_t encode_buf; |
| 125 | #if USE_POSIX_LOCALE | ||
| 126 | locale_t saved_locale; | ||
| 127 | locale_t posix_locale; | ||
| 128 | #endif | ||
| 102 | char number_fmt[8]; /* "%.XXg\0" */ | 129 | char number_fmt[8]; /* "%.XXg\0" */ |
| 103 | int current_depth; | 130 | int current_depth; |
| 104 | 131 | ||
| @@ -342,6 +369,10 @@ static int json_destroy_config(lua_State *l) | |||
| 342 | json_config_t *cfg; | 369 | json_config_t *cfg; |
| 343 | 370 | ||
| 344 | cfg = lua_touserdata(l, 1); | 371 | cfg = lua_touserdata(l, 1); |
| 372 | #ifdef USE_POSIX_LOCALE | ||
| 373 | if (cfg->posix_locale) | ||
| 374 | freelocale(cfg->posix_locale); | ||
| 375 | #endif | ||
| 345 | if (cfg) | 376 | if (cfg) |
| 346 | strbuf_free(&cfg->encode_buf); | 377 | strbuf_free(&cfg->encode_buf); |
| 347 | cfg = NULL; | 378 | cfg = NULL; |
| @@ -363,6 +394,13 @@ static void json_create_config(lua_State *l) | |||
| 363 | lua_setmetatable(l, -2); | 394 | lua_setmetatable(l, -2); |
| 364 | 395 | ||
| 365 | strbuf_init(&cfg->encode_buf, 0); | 396 | strbuf_init(&cfg->encode_buf, 0); |
| 397 | #if USE_POSIX_LOCALE | ||
| 398 | cfg->saved_locale = NULL; | ||
| 399 | /* Must not lua_error() before cfg->posix_locale has been initialised */ | ||
| 400 | cfg->posix_locale = newlocale(LC_ALL_MASK, "C", NULL); | ||
| 401 | if (!cfg->posix_locale) | ||
| 402 | luaL_error(l, "Failed to create POSIX locale for JSON"); | ||
| 403 | #endif | ||
| 366 | 404 | ||
| 367 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; | 405 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; |
| 368 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; | 406 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; |
| @@ -452,6 +490,7 @@ static void json_encode_exception(lua_State *l, json_config_t *cfg, int lindex, | |||
| 452 | { | 490 | { |
| 453 | if (!cfg->encode_keep_buffer) | 491 | if (!cfg->encode_keep_buffer) |
| 454 | strbuf_free(&cfg->encode_buf); | 492 | strbuf_free(&cfg->encode_buf); |
| 493 | LOCALE_RESTORE(cfg); | ||
| 455 | luaL_error(l, "Cannot serialise %s: %s", | 494 | luaL_error(l, "Cannot serialise %s: %s", |
| 456 | lua_typename(l, lua_type(l, lindex)), reason); | 495 | lua_typename(l, lua_type(l, lindex)), reason); |
| 457 | } | 496 | } |
| @@ -542,6 +581,7 @@ static void json_encode_descend(lua_State *l, json_config_t *cfg) | |||
| 542 | if (cfg->current_depth > cfg->encode_max_depth) { | 581 | if (cfg->current_depth > cfg->encode_max_depth) { |
| 543 | if (!cfg->encode_keep_buffer) | 582 | if (!cfg->encode_keep_buffer) |
| 544 | strbuf_free(&cfg->encode_buf); | 583 | strbuf_free(&cfg->encode_buf); |
| 584 | LOCALE_RESTORE(cfg); | ||
| 545 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", | 585 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", |
| 546 | cfg->current_depth); | 586 | cfg->current_depth); |
| 547 | } | 587 | } |
| @@ -701,9 +741,13 @@ static int json_encode(lua_State *l) | |||
| 701 | else | 741 | else |
| 702 | strbuf_init(&cfg->encode_buf, 0); | 742 | strbuf_init(&cfg->encode_buf, 0); |
| 703 | 743 | ||
| 744 | LOCALE_SET_POSIX(cfg); | ||
| 745 | |||
| 704 | json_append_data(l, cfg, &cfg->encode_buf); | 746 | json_append_data(l, cfg, &cfg->encode_buf); |
| 705 | json = strbuf_string(&cfg->encode_buf, &len); | 747 | json = strbuf_string(&cfg->encode_buf, &len); |
| 706 | 748 | ||
| 749 | LOCALE_RESTORE(cfg); | ||
| 750 | |||
| 707 | lua_pushlstring(l, json, len); | 751 | lua_pushlstring(l, json, len); |
| 708 | 752 | ||
| 709 | if (!cfg->encode_keep_buffer) | 753 | if (!cfg->encode_keep_buffer) |
| @@ -1084,6 +1128,8 @@ static void json_throw_parse_error(lua_State *l, json_parse_t *json, | |||
| 1084 | else | 1128 | else |
| 1085 | found = json_token_type_name[token->type]; | 1129 | found = json_token_type_name[token->type]; |
| 1086 | 1130 | ||
| 1131 | LOCALE_RESTORE(json->cfg); | ||
| 1132 | |||
| 1087 | /* Note: token->index is 0 based, display starting from 1 */ | 1133 | /* Note: token->index is 0 based, display starting from 1 */ |
| 1088 | luaL_error(l, "Expected %s but found %s at character %d", | 1134 | luaL_error(l, "Expected %s but found %s at character %d", |
| 1089 | exp, found, token->index + 1); | 1135 | exp, found, token->index + 1); |
| @@ -1095,6 +1141,7 @@ static void json_decode_checkstack(lua_State *l, json_parse_t *json, int n) | |||
| 1095 | return; | 1141 | return; |
| 1096 | 1142 | ||
| 1097 | strbuf_free(json->tmp); | 1143 | strbuf_free(json->tmp); |
| 1144 | LOCALE_RESTORE(json->cfg); | ||
| 1098 | luaL_error(l, "Too many nested data structures"); | 1145 | luaL_error(l, "Too many nested data structures"); |
| 1099 | } | 1146 | } |
| 1100 | 1147 | ||
| @@ -1224,6 +1271,8 @@ static void lua_json_decode(lua_State *l, const char *json_text, int json_len) | |||
| 1224 | * string must be smaller than the entire json string */ | 1271 | * string must be smaller than the entire json string */ |
| 1225 | json.tmp = strbuf_new(json_len); | 1272 | json.tmp = strbuf_new(json_len); |
| 1226 | 1273 | ||
| 1274 | LOCALE_SET_POSIX(json.cfg); | ||
| 1275 | |||
| 1227 | json_next_token(&json, &token); | 1276 | json_next_token(&json, &token); |
| 1228 | json_process_value(l, &json, &token); | 1277 | json_process_value(l, &json, &token); |
| 1229 | 1278 | ||
| @@ -1233,6 +1282,8 @@ static void lua_json_decode(lua_State *l, const char *json_text, int json_len) | |||
| 1233 | if (token.type != T_END) | 1282 | if (token.type != T_END) |
| 1234 | json_throw_parse_error(l, &json, "the end", &token); | 1283 | json_throw_parse_error(l, &json, "the end", &token); |
| 1235 | 1284 | ||
| 1285 | LOCALE_RESTORE(json.cfg); | ||
| 1286 | |||
| 1236 | strbuf_free(json.tmp); | 1287 | strbuf_free(json.tmp); |
| 1237 | } | 1288 | } |
| 1238 | 1289 | ||
