aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--NEWS3
-rw-r--r--TODO2
-rw-r--r--lua_cjson.c51
-rwxr-xr-xtests/test.lua16
5 files changed, 79 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index d34ff6d..5731440 100644
--- a/Makefile
+++ b/Makefile
@@ -15,13 +15,17 @@ LDFLAGS += -shared
15LUA_INCLUDE_DIR ?= $(PREFIX)/include 15LUA_INCLUDE_DIR ?= $(PREFIX)/include
16LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) 16LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION)
17 17
18# Some versions of Solaris are missing isinf(). Add -DMISSING_ISINF to
19# CFLAGS to work around this bug.
20
21#CFLAGS ?= -g -Wall -pedantic -fno-inline 18#CFLAGS ?= -g -Wall -pedantic -fno-inline
22CFLAGS ?= -g -O3 -Wall -pedantic 19CFLAGS ?= -g -O3 -Wall -pedantic
23override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -DVERSION=\"$(CJSON_VERSION)\" 20override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -DVERSION=\"$(CJSON_VERSION)\"
24 21
22## Conditional work arounds
23# Handle Solaris platforms that are missing isinf().
24#override CFLAGS += -DMISSING_ISINF
25# Handle locales that use comma as a decimal separator on locale aware
26# platforms. Requires POSIX-1.2008 support.
27override CFLAGS += -DUSE_POSIX_LOCALE
28
25INSTALL ?= install 29INSTALL ?= install
26 30
27.PHONY: all clean install package 31.PHONY: all clean install package
diff --git a/NEWS b/NEWS
index 3527b04..634d9af 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
1Version 1.0.4 (?)
2* Handle locales with a comma decimal separator
3
1Version 1.0.3 (Sep 15 2011) 4Version 1.0.3 (Sep 15 2011)
2* Fixed detection of objects with numeric string keys 5* Fixed detection of objects with numeric string keys
3* Provided work around for missing isinf() on Solaris 6* Provided work around for missing isinf() on Solaris
diff --git a/TODO b/TODO
index 1345448..9dbde9c 100644
--- a/TODO
+++ b/TODO
@@ -2,3 +2,5 @@
2 - Optionally create an object for settings. Clone function. 2 - Optionally create an object for settings. Clone function.
3 3
4- Convert documentation into structured source format 4- Convert documentation into structured source format
5
6- Add setlocale() support for non-POSIX 2008 operating systems
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
diff --git a/tests/test.lua b/tests/test.lua
index 7a75243..d80dcf0 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -210,6 +210,21 @@ local escape_tests = {
210 { json.decode, { utf16_escaped }, true, { utf8_raw } } 210 { json.decode, { utf16_escaped }, true, { utf8_raw } }
211} 211}
212 212
213-- The standard Lua interpreter is ANSI C online doesn't support locales
214-- by default. Force a known problematic locale to test strtod()/sprintf().
215local locale_tests = {
216 function ()
217 os.setlocale("cs_CZ")
218 return "Setting locale to cs_CZ (comma separator)"
219 end,
220 { json.encode, { 1.5 }, true, { '1.5' } },
221 { json.decode, { "[ 10, \"test\" ]" }, true, { { 10, "test" } } },
222 function ()
223 os.setlocale("C")
224 return "Reverting locale to POSIX"
225 end
226}
227
213print(string.format("Testing CJSON v%s\n", cjson.version)) 228print(string.format("Testing CJSON v%s\n", cjson.version))
214 229
215run_test_group("decode simple value", decode_simple_tests) 230run_test_group("decode simple value", decode_simple_tests)
@@ -225,6 +240,7 @@ run_test_group("encode table", encode_table_tests)
225run_test_group("decode error", decode_error_tests) 240run_test_group("decode error", decode_error_tests)
226run_test_group("encode error", encode_error_tests) 241run_test_group("encode error", encode_error_tests)
227run_test_group("escape", escape_tests) 242run_test_group("escape", escape_tests)
243run_test_group("locale", locale_tests)
228 244
229cjson.refuse_invalid_numbers(false) 245cjson.refuse_invalid_numbers(false)
230cjson.encode_max_depth(20) 246cjson.encode_max_depth(20)