diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-12-30 17:48:12 +1030 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2011-12-30 17:48:12 +1030 |
commit | 85bf3b798f6d52c374c35f7fbe47df132891d3b2 (patch) | |
tree | 39b0da8e6d6536cdd90038547a985559102962de | |
parent | 2416b145073211b840781da6abf4b6d97f4657a6 (diff) | |
download | lua-cjson-85bf3b798f6d52c374c35f7fbe47df132891d3b2.tar.gz lua-cjson-85bf3b798f6d52c374c35f7fbe47df132891d3b2.tar.bz2 lua-cjson-85bf3b798f6d52c374c35f7fbe47df132891d3b2.zip |
Add support for Lua 5.2 and cjson.new
Update all Lua scripts to use new module init style everywhere:
local json = require "cjson"
Lua CJSON does not register a global table under Lua 5.2. The global
table can be disabled under Lua 5.1 with DISABLE_CJSON_GLOBAL.
Other changes:
- Store CJSON configuration as an upvalue for each function.
- Add "cjson.new" function to create another module table with a
separate configuration.
- Add _NAME and _VERSION variables.
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | lua_cjson.c | 73 | ||||
-rw-r--r-- | manual.txt | 61 | ||||
-rwxr-xr-x | tests/bench.lua | 2 | ||||
-rw-r--r-- | tests/common.lua | 6 | ||||
-rwxr-xr-x | tests/decode.lua | 4 | ||||
-rwxr-xr-x | tests/encode.lua | 4 | ||||
-rwxr-xr-x | tests/test.lua | 16 |
8 files changed, 122 insertions, 47 deletions
@@ -2,7 +2,8 @@ LUA_VERSION = 5.1 | |||
2 | 2 | ||
3 | ## Available defines for CJSON_CFLAGS | 3 | ## Available defines for CJSON_CFLAGS |
4 | # | 4 | # |
5 | # USE_INTERNAL_ISINF: Workaround for Solaris platforms missing isinf(). | 5 | # USE_INTERNAL_ISINF: Workaround for Solaris platforms missing isinf(). |
6 | # DISABLE_CJSON_GLOBAL: Do not store module is "cjson" global | ||
6 | 7 | ||
7 | ## Build defaults | 8 | ## Build defaults |
8 | PREFIX = /usr/local | 9 | PREFIX = /usr/local |
diff --git a/lua_cjson.c b/lua_cjson.c index 8e9b237..be5cdc2 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
@@ -45,6 +45,10 @@ | |||
45 | #include "strbuf.h" | 45 | #include "strbuf.h" |
46 | #include "fpconv.h" | 46 | #include "fpconv.h" |
47 | 47 | ||
48 | #ifndef CJSON_MODNAME | ||
49 | #define CJSON_MODNAME "cjson" | ||
50 | #endif | ||
51 | |||
48 | #ifndef CJSON_VERSION | 52 | #ifndef CJSON_VERSION |
49 | #define CJSON_VERSION "1.0devel" | 53 | #define CJSON_VERSION "1.0devel" |
50 | #endif | 54 | #endif |
@@ -175,22 +179,16 @@ static const char *char2escape[256] = { | |||
175 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | 179 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
176 | }; | 180 | }; |
177 | 181 | ||
178 | static int json_config_key; | ||
179 | |||
180 | /* ===== CONFIGURATION ===== */ | 182 | /* ===== CONFIGURATION ===== */ |
181 | 183 | ||
182 | static json_config_t *json_fetch_config(lua_State *l) | 184 | static json_config_t *json_fetch_config(lua_State *l) |
183 | { | 185 | { |
184 | json_config_t *cfg; | 186 | json_config_t *cfg; |
185 | 187 | ||
186 | lua_pushlightuserdata(l, &json_config_key); | 188 | cfg = lua_touserdata(l, lua_upvalueindex(1)); |
187 | lua_gettable(l, LUA_REGISTRYINDEX); | ||
188 | cfg = lua_touserdata(l, -1); | ||
189 | if (!cfg) | 189 | if (!cfg) |
190 | luaL_error(l, "BUG: Unable to fetch CJSON configuration"); | 190 | luaL_error(l, "BUG: Unable to fetch CJSON configuration"); |
191 | 191 | ||
192 | lua_pop(l, 1); | ||
193 | |||
194 | return cfg; | 192 | return cfg; |
195 | } | 193 | } |
196 | 194 | ||
@@ -1246,7 +1244,27 @@ static int json_decode(lua_State *l) | |||
1246 | 1244 | ||
1247 | /* ===== INITIALISATION ===== */ | 1245 | /* ===== INITIALISATION ===== */ |
1248 | 1246 | ||
1249 | int luaopen_cjson(lua_State *l) | 1247 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 |
1248 | /* Compatibility for Lua 5.1. | ||
1249 | * | ||
1250 | * luaL_setfuncs() is used to create a module table where the functions have | ||
1251 | * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ | ||
1252 | static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup) | ||
1253 | { | ||
1254 | int i; | ||
1255 | |||
1256 | luaL_checkstack(l, nup, "too many upvalues"); | ||
1257 | for (; reg->name != NULL; reg++) { /* fill the table with given functions */ | ||
1258 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ | ||
1259 | lua_pushvalue(l, -nup); | ||
1260 | lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ | ||
1261 | lua_setfield(l, -(nup + 2), reg->name); | ||
1262 | } | ||
1263 | lua_pop(l, nup); /* remove upvalues */ | ||
1264 | } | ||
1265 | #endif | ||
1266 | |||
1267 | static int lua_cjson_new(lua_State *l) | ||
1250 | { | 1268 | { |
1251 | luaL_Reg reg[] = { | 1269 | luaL_Reg reg[] = { |
1252 | { "encode", json_encode }, | 1270 | { "encode", json_encode }, |
@@ -1257,28 +1275,51 @@ int luaopen_cjson(lua_State *l) | |||
1257 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, | 1275 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, |
1258 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, | 1276 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, |
1259 | { "update_locale", json_update_locale }, | 1277 | { "update_locale", json_update_locale }, |
1278 | { "new", lua_cjson_new }, | ||
1260 | { NULL, NULL } | 1279 | { NULL, NULL } |
1261 | }; | 1280 | }; |
1262 | 1281 | ||
1263 | /* Update the current locale for g_fmt/strtod */ | 1282 | /* Update the current locale for g_fmt/strtod. |
1283 | * Using different locales per-thread is not supported. */ | ||
1264 | fpconv_update_locale(); | 1284 | fpconv_update_locale(); |
1265 | 1285 | ||
1266 | /* Use json_config_key as a pointer. | 1286 | /* cjson module table */ |
1267 | * It's faster than using a config string, and more unique */ | 1287 | lua_newtable(l); |
1268 | lua_pushlightuserdata(l, &json_config_key); | ||
1269 | json_create_config(l); | ||
1270 | lua_settable(l, LUA_REGISTRYINDEX); | ||
1271 | 1288 | ||
1272 | luaL_register(l, "cjson", reg); | 1289 | /* Register functions with config data as upvalue */ |
1290 | json_create_config(l); | ||
1291 | luaL_setfuncs(l, reg, 1); | ||
1273 | 1292 | ||
1274 | /* Set cjson.null */ | 1293 | /* Set cjson.null */ |
1275 | lua_pushlightuserdata(l, NULL); | 1294 | lua_pushlightuserdata(l, NULL); |
1276 | lua_setfield(l, -2, "null"); | 1295 | lua_setfield(l, -2, "null"); |
1277 | 1296 | ||
1278 | /* Set cjson.version */ | 1297 | /* Set module name / version fields */ |
1298 | lua_pushliteral(l, CJSON_MODNAME); | ||
1299 | lua_setfield(l, -2, "_NAME"); | ||
1300 | lua_pushliteral(l, CJSON_VERSION); | ||
1301 | lua_setfield(l, -2, "_VERSION"); | ||
1279 | lua_pushliteral(l, CJSON_VERSION); | 1302 | lua_pushliteral(l, CJSON_VERSION); |
1280 | lua_setfield(l, -2, "version"); | 1303 | lua_setfield(l, -2, "version"); |
1281 | 1304 | ||
1305 | return 1; | ||
1306 | } | ||
1307 | |||
1308 | int luaopen_cjson(lua_State *l) | ||
1309 | { | ||
1310 | lua_cjson_new(l); | ||
1311 | |||
1312 | #if !defined(DISABLE_CJSON_GLOBAL) && (!defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502) | ||
1313 | /* Register a global "cjson" table to maintain compatibility with earlier | ||
1314 | * versions of Lua CJSON which used luaL_register() under Lua 5.1. | ||
1315 | * | ||
1316 | * From Lua 5.2 onwards, Lua CJSON does not automatically register a global | ||
1317 | * table. | ||
1318 | */ | ||
1319 | lua_pushvalue(l, -1); | ||
1320 | lua_setglobal(l, CJSON_MODNAME); | ||
1321 | #endif | ||
1322 | |||
1282 | /* Return cjson table */ | 1323 | /* Return cjson table */ |
1283 | return 1; | 1324 | return 1; |
1284 | } | 1325 | } |
@@ -16,8 +16,6 @@ Lua CJSON provides fast JSON parsing and encoding support for Lua. | |||
16 | 16 | ||
17 | .Caveats | 17 | .Caveats |
18 | - UTF-16 and UTF-32 are not supported. | 18 | - UTF-16 and UTF-32 are not supported. |
19 | - Multi-threading within a single Lua state is not supported | ||
20 | (+lua_lock+ / +lua_unlock+). | ||
21 | 19 | ||
22 | Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for | 20 | Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for |
23 | details. | 21 | details. |
@@ -32,7 +30,7 @@ comments. | |||
32 | Installation Methods | 30 | Installation Methods |
33 | -------------------- | 31 | -------------------- |
34 | 32 | ||
35 | Lua CJSON requires either http://www.lua.org[Lua] or | 33 | Lua CJSON requires either http://www.lua.org[Lua] 5.1, Lua 5.2, or |
36 | http://www.luajit.org[LuaJIT] to build. | 34 | http://www.luajit.org[LuaJIT] to build. |
37 | 35 | ||
38 | There are 4 build methods available: | 36 | There are 4 build methods available: |
@@ -44,11 +42,13 @@ RPM:: Linux | |||
44 | LuaRocks:: Unix, Windows | 42 | LuaRocks:: Unix, Windows |
45 | 43 | ||
46 | 44 | ||
47 | Build options (#define) | 45 | Build Options (#define) |
48 | ~~~~~~~~~~~~~~~~~~~~~~~ | 46 | ~~~~~~~~~~~~~~~~~~~~~~~ |
49 | 47 | ||
50 | [horizontal] | 48 | [horizontal] |
51 | USE_INTERNAL_ISINF:: Workaround for Solaris platforms missing isinf(). | 49 | USE_INTERNAL_ISINF:: Workaround for Solaris platforms missing isinf(). |
50 | DISABLE_CJSON_GLOBAL:: Do not store module table in global "cjson" | ||
51 | variable. | ||
52 | 52 | ||
53 | 53 | ||
54 | Make | 54 | Make |
@@ -125,9 +125,9 @@ Synopsis | |||
125 | 125 | ||
126 | [source,lua] | 126 | [source,lua] |
127 | ------------ | 127 | ------------ |
128 | require "cjson" | 128 | -- Module initalisation methods |
129 | -- Or: | ||
130 | local cjson = require "cjson" | 129 | local cjson = require "cjson" |
130 | local cjson2 = cjson.new() | ||
131 | 131 | ||
132 | -- Translate Lua value to/from JSON | 132 | -- Translate Lua value to/from JSON |
133 | text = cjson.encode(value) | 133 | text = cjson.encode(value) |
@@ -141,6 +141,34 @@ keep = cjson.encode_keep_buffer([keep]) | |||
141 | ------------ | 141 | ------------ |
142 | 142 | ||
143 | 143 | ||
144 | Module Instantiation | ||
145 | ~~~~~~~~~~~~~~~~~~~~ | ||
146 | |||
147 | [source,lua] | ||
148 | ------------ | ||
149 | local cjson = require "cjson" | ||
150 | local cjson2 = cjson.new() | ||
151 | ------------ | ||
152 | |||
153 | Lua CJSON can be loaded via +require+. A global +cjson+ table is | ||
154 | registered under Lua 5.1 to maintain backward compatibility. Lua CJSON | ||
155 | does not register a global table under Lua 5.2 since this practice is | ||
156 | discouraged. | ||
157 | |||
158 | +cjson.new+ can be used to instantiate an independent copy of the Lua | ||
159 | CJSON module. The new module has a separate persistent encoding | ||
160 | buffer, and default settings. | ||
161 | |||
162 | Lua CJSON can support Lua implementations using multiple pre-emptive | ||
163 | threads within a single Lua state provided the persistent encoding | ||
164 | buffer is not shared. This can be achieved by one of the following | ||
165 | methods: | ||
166 | |||
167 | - Disabling the persistent encoding buffer with +encode_keep_buffer+. | ||
168 | - Ensuring only a single thread calls +encode+ at a time. | ||
169 | - Using a separate +cjson+ instantiation per pre-emptive thread. | ||
170 | |||
171 | |||
144 | decode | 172 | decode |
145 | ~~~~~~ | 173 | ~~~~~~ |
146 | 174 | ||
@@ -423,6 +451,18 @@ Disabled for decoding:: All numbers supported by +strtod+(3) will be parsed. | |||
423 | API (Variables) | 451 | API (Variables) |
424 | --------------- | 452 | --------------- |
425 | 453 | ||
454 | _NAME | ||
455 | ~~~~~ | ||
456 | |||
457 | The name of the Lua CJSON module (+"cjson"+). | ||
458 | |||
459 | |||
460 | _VERSION | ||
461 | ~~~~~~~~ | ||
462 | |||
463 | The version number of the Lua CJSON module (Eg, +"1.0devel"+). | ||
464 | |||
465 | |||
426 | null | 466 | null |
427 | ~~~~ | 467 | ~~~~ |
428 | 468 | ||
@@ -430,13 +470,6 @@ Lua CJSON decodes JSON +null+ as a Lua +lightuserdata+ NULL pointer. | |||
430 | +cjson.null+ is provided for comparison. | 470 | +cjson.null+ is provided for comparison. |
431 | 471 | ||
432 | 472 | ||
433 | version | ||
434 | ~~~~~~~ | ||
435 | |||
436 | The version number of the Lua CJSON module in use can be found in | ||
437 | +cjson.version+. | ||
438 | |||
439 | |||
440 | [sect1] | 473 | [sect1] |
441 | References | 474 | References |
442 | ---------- | 475 | ---------- |
@@ -445,4 +478,4 @@ References | |||
445 | - http://www.json.org/[JSON website] | 478 | - http://www.json.org/[JSON website] |
446 | 479 | ||
447 | 480 | ||
448 | // vi:tw=70: | 481 | // vi:ft=asciidoc tw=70: |
diff --git a/tests/bench.lua b/tests/bench.lua index fdd0bb0..c81213d 100755 --- a/tests/bench.lua +++ b/tests/bench.lua | |||
@@ -72,7 +72,7 @@ function bench_file(filename) | |||
72 | return benchmark(tests, 0.1, 5) | 72 | return benchmark(tests, 0.1, 5) |
73 | end | 73 | end |
74 | 74 | ||
75 | cjson.encode_keep_buffer(true) | 75 | json.encode_keep_buffer(true) |
76 | 76 | ||
77 | for i = 1, #arg do | 77 | for i = 1, #arg do |
78 | local results = bench_file(arg[i]) | 78 | local results = bench_file(arg[i]) |
diff --git a/tests/common.lua b/tests/common.lua index f3dc6f7..7472a10 100644 --- a/tests/common.lua +++ b/tests/common.lua | |||
@@ -1,4 +1,4 @@ | |||
1 | require "cjson" | 1 | local json = require "cjson" |
2 | 2 | ||
3 | -- Misc routines to assist with CJSON testing | 3 | -- Misc routines to assist with CJSON testing |
4 | -- | 4 | -- |
@@ -77,8 +77,8 @@ function serialise_value(value, indent, depth) | |||
77 | if indent == nil then indent = "" end | 77 | if indent == nil then indent = "" end |
78 | if depth == nil then depth = 0 end | 78 | if depth == nil then depth = 0 end |
79 | 79 | ||
80 | if value == cjson.null then | 80 | if value == json.null then |
81 | return "cjson.null" | 81 | return "json.null" |
82 | elseif type(value) == "string" then | 82 | elseif type(value) == "string" then |
83 | return string.format("%q", value) | 83 | return string.format("%q", value) |
84 | elseif type(value) == "nil" or type(value) == "number" or | 84 | elseif type(value) == "nil" or type(value) == "number" or |
diff --git a/tests/decode.lua b/tests/decode.lua index cac29e6..89354cd 100755 --- a/tests/decode.lua +++ b/tests/decode.lua | |||
@@ -7,8 +7,8 @@ | |||
7 | -- ./decode.lua test.json | 7 | -- ./decode.lua test.json |
8 | 8 | ||
9 | require "common" | 9 | require "common" |
10 | require "cjson" | 10 | local json = require "cjson" |
11 | 11 | ||
12 | local json_text = file_load(arg[1]) | 12 | local json_text = file_load(arg[1]) |
13 | local t = cjson.decode(json_text) | 13 | local t = json.decode(json_text) |
14 | print(serialise_value(t)) | 14 | print(serialise_value(t)) |
diff --git a/tests/encode.lua b/tests/encode.lua index f13787c..a8d749a 100755 --- a/tests/encode.lua +++ b/tests/encode.lua | |||
@@ -7,7 +7,7 @@ | |||
7 | -- ./encode.lua lua_data.lua | 7 | -- ./encode.lua lua_data.lua |
8 | 8 | ||
9 | require "common" | 9 | require "common" |
10 | require "cjson" | 10 | local json = require "cjson" |
11 | 11 | ||
12 | function get_lua_table(file) | 12 | function get_lua_table(file) |
13 | local func = loadstring("data = " .. file_load(file)) | 13 | local func = loadstring("data = " .. file_load(file)) |
@@ -23,6 +23,6 @@ function get_lua_table(file) | |||
23 | end | 23 | end |
24 | 24 | ||
25 | local t = get_lua_table(arg[1]) | 25 | local t = get_lua_table(arg[1]) |
26 | print(cjson.encode(t)) | 26 | print(json.encode(t)) |
27 | 27 | ||
28 | -- vi:ai et sw=4 ts=4: | 28 | -- vi:ai et sw=4 ts=4: |
diff --git a/tests/test.lua b/tests/test.lua index bdae6ea..99ac73a 100755 --- a/tests/test.lua +++ b/tests/test.lua | |||
@@ -112,8 +112,8 @@ local decode_numeric_tests = { | |||
112 | 112 | ||
113 | local encode_table_tests = { | 113 | local encode_table_tests = { |
114 | function() | 114 | function() |
115 | cjson.encode_sparse_array(true, 2, 3) | 115 | json.encode_sparse_array(true, 2, 3) |
116 | cjson.encode_max_depth(5) | 116 | json.encode_max_depth(5) |
117 | return "Setting sparse array (true, 2, 3) / max depth (5)" | 117 | return "Setting sparse array (true, 2, 3) / max depth (5)" |
118 | end, | 118 | end, |
119 | { json.encode, { { [3] = "sparse test" } }, | 119 | { json.encode, { { [3] = "sparse test" } }, |
@@ -211,19 +211,19 @@ local escape_tests = { | |||
211 | local locale_tests = { | 211 | local locale_tests = { |
212 | function () | 212 | function () |
213 | os.setlocale("cs_CZ") | 213 | os.setlocale("cs_CZ") |
214 | cjson.update_locale() | 214 | json.update_locale() |
215 | return "Setting locale to cs_CZ (comma separator)" | 215 | return "Setting locale to cs_CZ (comma separator)" |
216 | end, | 216 | end, |
217 | { json.encode, { 1.5 }, true, { '1.5' } }, | 217 | { json.encode, { 1.5 }, true, { '1.5' } }, |
218 | { json.decode, { "[ 10, \"test\" ]" }, true, { { 10, "test" } } }, | 218 | { json.decode, { "[ 10, \"test\" ]" }, true, { { 10, "test" } } }, |
219 | function () | 219 | function () |
220 | os.setlocale("C") | 220 | os.setlocale("C") |
221 | cjson.update_locale() | 221 | json.update_locale() |
222 | return "Reverting locale to POSIX" | 222 | return "Reverting locale to POSIX" |
223 | end | 223 | end |
224 | } | 224 | } |
225 | 225 | ||
226 | print(string.format("Testing Lua CJSON version %s\n", cjson.version)) | 226 | print(string.format("Testing Lua CJSON version %s\n", json.version)) |
227 | 227 | ||
228 | run_test_group("decode simple value", decode_simple_tests) | 228 | run_test_group("decode simple value", decode_simple_tests) |
229 | run_test_group("encode simple value", encode_simple_tests) | 229 | run_test_group("encode simple value", encode_simple_tests) |
@@ -232,7 +232,7 @@ run_test_group("decode numeric", decode_numeric_tests) | |||
232 | -- INCLUDE: | 232 | -- INCLUDE: |
233 | -- - Sparse array exception.. | 233 | -- - Sparse array exception.. |
234 | -- - .. | 234 | -- - .. |
235 | -- cjson.encode_sparse_array(true, 2, 3) | 235 | -- json.encode_sparse_array(true, 2, 3) |
236 | 236 | ||
237 | run_test_group("encode table", encode_table_tests) | 237 | run_test_group("encode table", encode_table_tests) |
238 | run_test_group("decode error", decode_error_tests) | 238 | run_test_group("decode error", decode_error_tests) |
@@ -240,8 +240,8 @@ run_test_group("encode error", encode_error_tests) | |||
240 | run_test_group("escape", escape_tests) | 240 | run_test_group("escape", escape_tests) |
241 | run_test_group("locale", locale_tests) | 241 | run_test_group("locale", locale_tests) |
242 | 242 | ||
243 | cjson.refuse_invalid_numbers(false) | 243 | json.refuse_invalid_numbers(false) |
244 | cjson.encode_max_depth(20) | 244 | json.encode_max_depth(20) |
245 | for i = 1, #arg do | 245 | for i = 1, #arg do |
246 | run_test("decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, | 246 | run_test("decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, |
247 | true, { true }) | 247 | true, { true }) |