├── .gitignore ├── GNUmakefile ├── Makefile ├── README ├── buffer.c ├── buffer.h ├── luajson.c ├── null.lua ├── shlib_version └── test.lua /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | SRCS= luajson.c buffer.c 2 | MODULE= json 3 | 4 | CFLAGS+= -D_GNU_SOURCE 5 | 6 | include lua.module.mk 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRCS= luajson.c 2 | LIB= json 3 | 4 | OS!= uname 5 | LUA_VERSION?= 5.2 6 | 7 | .if ${OS} == "NetBSD" 8 | LOCALBASE?= /usr/pkg 9 | LDADD+= -R/usr/lib -R${LOCALBASE}/lib 10 | .else 11 | LOCALBASE= /usr/local 12 | .endif 13 | 14 | NOLINT= 1 15 | CFLAGS+= -I${LOCALBASE}/include 16 | LDADD+= -L${XDIR}/lib -L${LOCALBASE}/lib 17 | 18 | LIBDIR= ${LOCALBASE}/lib/lua/${LUA_VERSION} 19 | 20 | libinstall: 21 | 22 | install: 23 | ${INSTALL} -d ${DESTDIR}${LIBDIR} 24 | ${INSTALL} lib${LIB}.so ${DESTDIR}${LIBDIR}/${LIB}.so 25 | 26 | .include 27 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A Lua Binding for JSON 2 | 3 | Copyright (C) Micro Systems Marc Balmer. 4 | You can reach the author at marc@msys.ch 5 | 6 | Makefile is for BSD systems 7 | GNUmakefile is for Linux systems 8 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 - 2024 Micro Systems Marc Balmer, CH-5073 Gipf-Oberfrick. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "buffer.h" 30 | 31 | int 32 | buf_init(struct buffer *b) 33 | { 34 | if ((b->data = malloc(BUFFER_SIZE)) == NULL) 35 | return -1; 36 | b->capacity = BUFFER_SIZE; 37 | b->size = 0; 38 | return 0; 39 | } 40 | 41 | static void 42 | buf_resize(struct buffer *b, size_t size) 43 | { 44 | size_t enlargement = BUFFER_SIZE; 45 | 46 | while (enlargement < size) 47 | enlargement += BUFFER_SIZE; 48 | b->capacity += enlargement; 49 | b->data = realloc(b->data, b->capacity); 50 | } 51 | 52 | void 53 | buf_addstring(struct buffer *b, const char *s) 54 | { 55 | size_t len; 56 | 57 | len = strlen(s); 58 | if (b->size + len >= b->capacity) 59 | buf_resize(b, len); 60 | strcpy(b->data + b->size, s); 61 | b->size += len; 62 | } 63 | 64 | void 65 | buf_addchar(struct buffer *b, char c) 66 | { 67 | if (b->size + 1 >= b->capacity) 68 | buf_resize(b, 1); 69 | *(b->data + b->size++) = c; 70 | } 71 | 72 | void 73 | buf_printf(struct buffer *b, const char *fmt, ...) 74 | { 75 | va_list ap; 76 | int len; 77 | char *s; 78 | 79 | va_start(ap, fmt); 80 | len = vasprintf(&s, fmt, ap); 81 | va_end(ap); 82 | if (len > 0) 83 | buf_addstring(b, s); 84 | free(s); 85 | } 86 | 87 | void 88 | buf_push(struct buffer *b, lua_State *L) 89 | { 90 | lua_pushlstring(L, b->data, b->size); 91 | } 92 | 93 | void 94 | buf_free(struct buffer *b) 95 | { 96 | free(b->data); 97 | } 98 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 - 2024 Micro Systems Marc Balmer, CH-5073 Gipf-Oberfrick. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | 26 | #ifndef __BUFFER_H__ 27 | #define __BUFFER_H__ 28 | 29 | #define BUFFER_SIZE 8196 30 | 31 | struct buffer { 32 | char *data; 33 | size_t capacity; 34 | size_t size; 35 | }; 36 | 37 | extern int buf_init(struct buffer *); 38 | extern void buf_addstring(struct buffer *, const char *); 39 | extern void buf_addchar(struct buffer *, char); 40 | extern void buf_printf(struct buffer *, const char *, ...); 41 | extern void buf_push(struct buffer *, lua_State *); 42 | extern void buf_free(struct buffer *); 43 | 44 | #endif /* __BUFFER_H__ */ 45 | -------------------------------------------------------------------------------- /luajson.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 - 2022 Micro Systems Marc Balmer, CH-5073 Gipf-Oberfrick. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* JSON interface for Lua */ 25 | 26 | /* 27 | * This code has been derived from the public domain LuaJSON Library 1.1 28 | * written by Nathaniel Musgrove (proton.zero@gmail.com), for the original 29 | * code see http://luaforge.net/projects/luajsonlib/ 30 | */ 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "buffer.h" 43 | 44 | #define JSON_NULL_METATABLE "JSON null object" 45 | #define JSON_GCMEM_METATABLE "JSON garbage collected memory" 46 | 47 | static void decode_value(lua_State *, char **, int); 48 | static void decode_string(lua_State *, char **); 49 | static void encode(lua_State *, struct buffer *); 50 | 51 | static jmp_buf env; 52 | 53 | /* 54 | * Garbage collected memory 55 | */ 56 | static void * 57 | gcmalloc(lua_State *L, size_t size) 58 | { 59 | void **p; 60 | p = lua_newuserdata(L, size); 61 | *p = NULL; 62 | luaL_setmetatable(L, JSON_GCMEM_METATABLE); 63 | return p; 64 | } 65 | 66 | /* Memory can be free'ed immediately or left to the garbage collector */ 67 | static void 68 | gcfree(void *p) 69 | { 70 | void **mem = (void **)p; 71 | free(*mem); 72 | *mem = NULL; 73 | } 74 | 75 | static int 76 | gcmem_clear(lua_State *L) 77 | { 78 | void **p = luaL_checkudata(L, 1, JSON_GCMEM_METATABLE); 79 | 80 | free(*p); 81 | *p = NULL; 82 | return 0; 83 | } 84 | 85 | static int 86 | json_error(lua_State *L, const char *fmt, ...) 87 | { 88 | va_list ap; 89 | int len; 90 | char **msg; 91 | 92 | msg = gcmalloc(L, sizeof(char *)); 93 | va_start(ap, fmt); 94 | len = vasprintf((char **)msg, fmt, ap); 95 | va_end(ap); 96 | 97 | lua_pushnil(L); 98 | if (len != -1) { 99 | lua_pushstring(L, *msg); 100 | gcfree(msg); 101 | } else 102 | lua_pushstring(L, "internal error: vasprintf failed"); 103 | longjmp(env, 0); 104 | } 105 | 106 | static unsigned int 107 | digit2int(lua_State *L, const unsigned char digit) 108 | { 109 | unsigned int val; 110 | 111 | if (digit >= '0' && digit <= '9') 112 | val = digit - '0'; 113 | else if (digit >= 'a' || digit <= 'f') 114 | val = digit - 'a' + 10; 115 | else if (digit >= 'A' || digit <= 'F') 116 | val = digit - 'A' + 10; 117 | else 118 | json_error(L, "Invalid hex digit"); 119 | return val; 120 | } 121 | 122 | static unsigned int 123 | fourhex2int(lua_State *L, const unsigned char *code) 124 | { 125 | unsigned int utf = 0; 126 | 127 | utf += digit2int(L, code[0]) * 4096; 128 | utf += digit2int(L, code[1]) * 256; 129 | utf += digit2int(L, code[2]) * 16; 130 | utf += digit2int(L, code[3]); 131 | return utf; 132 | } 133 | 134 | static const char * 135 | code2utf8(lua_State *L, const unsigned char *code, char buf[4]) 136 | { 137 | unsigned int utf = 0; 138 | 139 | utf = fourhex2int(L, code); 140 | if (utf < 128) { 141 | buf[0] = utf & 0x7F; 142 | buf[1] = buf[2] = buf[3] = 0; 143 | } else if (utf < 2048) { 144 | buf[0] = ((utf >> 6) & 0x1F) | 0xC0; 145 | buf[1] = (utf & 0x3F) | 0x80; 146 | buf[2] = buf[3] = 0; 147 | } else if (utf < 65536) { 148 | buf[0] = ((utf >> 12) & 0x0F) | 0xE0; 149 | buf[1] = ((utf >> 6) & 0x3F) | 0x80; 150 | buf[2] = (utf & 0x3F) | 0x80; 151 | buf[3] = 0; 152 | } else { 153 | buf[0] = ((utf >> 18) & 0x07) | 0xF0; 154 | buf[1] = ((utf >> 12) & 0x3F) | 0x80; 155 | buf[2] = ((utf >> 6) & 0x3F) | 0x80; 156 | buf[3] = (utf & 0x3F) | 0x80; 157 | } 158 | return buf; 159 | } 160 | 161 | static void 162 | skip_ws(char **s) 163 | { 164 | while (isspace(**s)) 165 | (*s)++; 166 | } 167 | 168 | static void 169 | decode_array(lua_State *L, char **s, int null) 170 | { 171 | int i = 1; 172 | 173 | luaL_checkstack(L, 2, "Out of stack space"); 174 | (*s)++; 175 | lua_newtable(L); 176 | for (i = 1; 1; i++) { 177 | skip_ws(s); 178 | lua_pushinteger(L, i); 179 | decode_value(L, s, null); 180 | lua_settable(L, -3); 181 | skip_ws(s); 182 | if (**s == ',') { 183 | (*s)++; 184 | skip_ws(s); 185 | } else 186 | break; 187 | } 188 | skip_ws(s); 189 | if (**s == ']') 190 | (*s)++; 191 | else 192 | json_error(L, "array does not end with ']'"); 193 | } 194 | 195 | static void 196 | decode_object(lua_State *L, char **s, int null) 197 | { 198 | luaL_checkstack(L, 1, "Out of stack space"); 199 | 200 | (*s)++; 201 | lua_newtable(L); 202 | skip_ws(s); 203 | 204 | if (**s != '}') { 205 | while (1) { 206 | skip_ws(s); 207 | decode_string(L, s); 208 | skip_ws(s); 209 | if (**s != ':') 210 | json_error(L, "object lacks separator ':'"); 211 | (*s)++; 212 | skip_ws(s); 213 | decode_value(L, s, null); 214 | lua_settable(L, -3); 215 | skip_ws(s); 216 | if (**s == ',') { 217 | (*s)++; 218 | skip_ws(s); 219 | } else 220 | break; 221 | } 222 | skip_ws(s); 223 | } 224 | if (**s == '}') 225 | (*s)++; 226 | else 227 | json_error(L, "objects does not end with '}'"); 228 | } 229 | 230 | static void 231 | decode_string(lua_State *L, char **s) 232 | { 233 | size_t len; 234 | char *newstr = NULL, *newc, *beginning, *end, *nextEscape = NULL; 235 | char utfbuf[4] = ""; 236 | 237 | luaL_checkstack(L, 1, "Out of stack space"); 238 | (*s)++; 239 | beginning = *s; 240 | for (end = NULL; **s != '\0' && end == NULL; (*s)++) { 241 | if (**s == '"' && (*((*s) - 1) != '\\')) 242 | end = *s; 243 | } 244 | if (end == NULL) 245 | return; 246 | *s = beginning; 247 | len = strlen(*s); 248 | if ((newstr = malloc(len + 1)) == NULL) 249 | json_error(L, "memory error"); 250 | memset(newstr, 0, len + 1); 251 | newc = newstr; 252 | while (*s != end) { 253 | nextEscape = strchr(*s, '\\'); 254 | if (nextEscape > end) 255 | nextEscape = NULL; 256 | if (nextEscape == *s) { 257 | switch (*((*s) + 1)) { 258 | case '"': 259 | *newc = '"'; 260 | newc++; 261 | (*s) += 2; 262 | break; 263 | case '\\': 264 | *newc = '\\'; 265 | newc++; 266 | (*s) += 2; 267 | break; 268 | case '/': 269 | *newc = '/'; 270 | newc++; 271 | (*s) += 2; 272 | break; 273 | case 'b': 274 | *newc = '\b'; 275 | newc++; 276 | (*s) += 2; 277 | break; 278 | case 'f': 279 | *newc = '\f'; 280 | newc++; 281 | (*s) += 2; 282 | break; 283 | case 'n': 284 | *newc = '\n'; 285 | newc++; 286 | (*s) += 2; 287 | break; 288 | case 'r': 289 | *newc = '\r'; 290 | newc++; 291 | (*s) += 2; 292 | break; 293 | case 't': 294 | *newc = '\t'; 295 | newc++; 296 | (*s) += 2; 297 | break; 298 | case 'u': 299 | code2utf8(L, (unsigned char *)(*s) + 2, utfbuf); 300 | len = strlen(utfbuf); 301 | strcpy(newc, utfbuf); 302 | newc += len; 303 | (*s) += 6; 304 | break; 305 | default: 306 | json_error(L, "invalid escape character"); 307 | break; 308 | } 309 | } else if (nextEscape != NULL) { 310 | len = nextEscape - *s; 311 | strncpy(newc, *s, len); 312 | newc += len; 313 | (*s) += len; 314 | } else { 315 | len = end - *s; 316 | strncpy(newc, *s, len); 317 | newc += len; 318 | (*s) += len; 319 | } 320 | } 321 | *newc = 0; 322 | lua_pushstring(L, newstr); 323 | (*s)++; 324 | free(newstr); 325 | } 326 | 327 | static void 328 | decode_value(lua_State *L, char **s, int null) 329 | { 330 | skip_ws(s); 331 | 332 | luaL_checkstack(L, 1, "Out of stack space"); 333 | if (!strncmp(*s, "false", 5)) { 334 | lua_pushboolean(L, 0); 335 | *s += 5; 336 | } else if (!strncmp(*s, "true", 4)) { 337 | lua_pushboolean(L, 1); 338 | *s += 4; 339 | } else if (!strncmp(*s, "null", 4)) { 340 | switch (null) { 341 | case 0: 342 | lua_pushstring(L, ""); 343 | break; 344 | case 1: 345 | lua_newtable(L); 346 | luaL_setmetatable(L, JSON_NULL_METATABLE); 347 | break; 348 | case 2: 349 | lua_pushnil(L); 350 | break; 351 | } 352 | *s += 4; 353 | } else if (isdigit(**s) || **s == '+' || **s == '-') { 354 | char *p = *s; 355 | int isfloat = 0; 356 | 357 | /* advance pointer past the number */ 358 | while (isdigit(**s) || **s == '+' || **s == '-' 359 | || **s == 'e' || **s == 'E' || **s == '.') { 360 | if (**s == 'e' || **s == 'E' || **s == '.') 361 | isfloat = 1; 362 | (*s)++; 363 | } 364 | if (isfloat) 365 | lua_pushnumber(L, atof(p)); 366 | else 367 | lua_pushinteger(L, atol(p)); 368 | } else { 369 | switch (**s) { 370 | case '[': 371 | decode_array(L, s, null); 372 | break; 373 | case '{': 374 | decode_object(L, s, null); 375 | break; 376 | case '"': 377 | decode_string(L, s); 378 | break; 379 | case ']': /* ignore end of empty array */ 380 | lua_pushnil(L); 381 | break; 382 | default: 383 | json_error(L, "syntax error"); 384 | break; 385 | } 386 | } 387 | } 388 | 389 | static int 390 | json_decode(lua_State *L) 391 | { 392 | char *s; 393 | int null; 394 | const char *const options[] = { 395 | "empty-string", 396 | "json-null", 397 | "nil", 398 | NULL 399 | }; 400 | 401 | s = (char *)luaL_checkstring(L, 1); 402 | 403 | null = luaL_checkoption(L, 2, "json-null", options); 404 | 405 | if (!setjmp(env)) { 406 | decode_value(L, &s, null); 407 | return 1; 408 | } else 409 | return 2; 410 | } 411 | 412 | /* encode JSON */ 413 | 414 | /* encode_string assumes an UTF-8 string */ 415 | static void 416 | encode_string(lua_State *L, struct buffer *b, unsigned char *s) 417 | { 418 | char hexbuf[6]; 419 | 420 | buf_addchar(b, '"'); 421 | for (; *s; s++) { 422 | switch (*s) { 423 | case '\\': 424 | buf_addstring(b, "\\\\"); 425 | break; 426 | case '"': 427 | buf_addstring(b, "\\\""); 428 | break; 429 | case '\b': 430 | buf_addstring(b, "\\b"); 431 | break; 432 | case '\f': 433 | buf_addstring(b, "\\f"); 434 | break; 435 | case '\n': 436 | buf_addstring(b, "\\n"); 437 | break; 438 | case '\r': 439 | buf_addstring(b, "\\r"); 440 | break; 441 | case '\t': 442 | buf_addstring(b, "\\t"); 443 | break; 444 | default: 445 | /* Convert UTF-8 to unicode 446 | * 00000000 - 0000007F: 0xxxxxxx 447 | * 00000080 - 000007FF: 110xxxxx 10xxxxxx 448 | * 00000800 - 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 449 | * 00010000 - 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 450 | */ 451 | if ((*s & 0x80) == 0) 452 | buf_addchar(b, *s); 453 | else if (((*s >> 5) & 0x07) == 0x06) { 454 | buf_addstring(b, "\\u"); 455 | snprintf(hexbuf, sizeof hexbuf, "%04x", 456 | ((*s & 0x1f) << 6) | (*(s + 1) & 0x3f)); 457 | buf_addstring(b, hexbuf); 458 | s++; 459 | } else if (((*s >> 4) & 0x0f) == 0x0e) { 460 | buf_addstring(b, "\\u"); 461 | snprintf(hexbuf, sizeof hexbuf, "%04x", 462 | ((*s & 0x0f) << 12) | 463 | ((*(s + 1) & 0x3f) << 6) | 464 | (*(s + 2) & 0x3f)); 465 | buf_addstring(b, hexbuf); 466 | s += 2; 467 | } else if (((*s >> 3) & 0x1f) == 0x1e) { 468 | buf_addstring(b, "\\u"); 469 | snprintf(hexbuf, sizeof hexbuf, "%04x", 470 | ((*s & 0x07) << 18) | 471 | ((*(s + 1) & 0x3f) << 12) | 472 | ((*(s + 2) & 0x3f) << 6) | 473 | (*(s + 3) & 0x3f)); 474 | buf_addstring(b, hexbuf); 475 | s += 3; 476 | } 477 | break; 478 | } 479 | } 480 | buf_addchar(b, '"'); 481 | } 482 | 483 | static void 484 | encode(lua_State *L, struct buffer *b) 485 | { 486 | int e, t, n, m; 487 | 488 | switch (lua_type(L, -1)) { 489 | case LUA_TBOOLEAN: 490 | buf_addstring(b, lua_toboolean(L, -1) ? "true" : "false"); 491 | lua_pop(L, 1); 492 | break; 493 | case LUA_TNUMBER: 494 | buf_addstring(b, lua_tostring(L, -1)); 495 | lua_pop(L, 1); 496 | break; 497 | case LUA_TSTRING: 498 | encode_string(L, b, (unsigned char *)lua_tostring(L, -1)); 499 | lua_pop(L, 1); 500 | break; 501 | case LUA_TTABLE: 502 | /* check if this is the null value */ 503 | luaL_checkstack(L, 2, "out of stack space"); 504 | if (lua_getmetatable(L, -1)) { 505 | luaL_getmetatable(L, JSON_NULL_METATABLE); 506 | if (lua_compare(L, -2, -1, LUA_OPEQ)) { 507 | lua_pop(L, 2); 508 | buf_addstring(b, "null"); 509 | lua_pop(L, 1); 510 | break; 511 | } 512 | lua_pop(L, 2); 513 | } 514 | /* if there are t[1] .. t[n], output them as array */ 515 | n = 0; 516 | e = 1; 517 | t = lua_gettop(L); 518 | for (m = 1; ; m++) { 519 | lua_geti(L, t, m); 520 | if (lua_isnil(L, -1)) { 521 | lua_pop(L, 1); 522 | break; 523 | } 524 | buf_addchar(b, n ? ',' : '['); 525 | encode(L, b); 526 | n++; 527 | } 528 | if (n) { 529 | buf_addchar(b, ']'); 530 | lua_pop(L, 1); 531 | e = 0; 532 | break; 533 | } 534 | 535 | /* output non-numerical indices as object */ 536 | t = lua_gettop(L); 537 | lua_pushnil(L); 538 | n = 0; 539 | while (lua_next(L, t) != 0) { 540 | int key /*, value */; 541 | 542 | key = lua_absindex(L, -2); 543 | /* value = lua_absindex(L, -1); */ 544 | 545 | if (lua_type(L, -2) == LUA_TNUMBER) { 546 | lua_pop(L, 1); 547 | continue; 548 | } 549 | buf_addstring(b, n ? ",\"" : "{\""); 550 | buf_addstring(b, lua_tostring(L, -2)); 551 | buf_addstring(b, "\":"); 552 | encode(L, b); 553 | lua_pushvalue(L, key); 554 | /* lua_remove(L, value); */ 555 | /* lua_remove(L, key); */ 556 | n++; 557 | } 558 | if (n) { 559 | buf_addchar(b, '}'); 560 | e = 0; 561 | } 562 | 563 | if (e) 564 | buf_addstring(b, "[]"); 565 | lua_pop(L, 1); 566 | break; 567 | case LUA_TNIL: 568 | buf_addstring(b, "null"); 569 | lua_pop(L, 1); 570 | break; 571 | default: 572 | json_error(L, "Lua type %s is incompatible with JSON", 573 | luaL_typename(L, -1)); 574 | lua_pop(L, 1); 575 | } 576 | } 577 | 578 | static int 579 | json_encode(lua_State *L) 580 | { 581 | struct buffer b; 582 | 583 | buf_init(&b); 584 | encode(L, &b); 585 | buf_push(&b, L); 586 | buf_free(&b); 587 | return 1; 588 | } 589 | 590 | static int 591 | json_isnull(lua_State *L) 592 | { 593 | if (lua_getmetatable(L, -1)) { 594 | luaL_getmetatable(L, JSON_NULL_METATABLE); 595 | if (lua_compare(L, -2, -1, LUA_OPEQ)) { 596 | lua_pop(L, 2); 597 | lua_pushboolean(L, 1); 598 | goto done; 599 | } 600 | lua_pop(L, 2); 601 | } 602 | lua_pushboolean(L, 0); 603 | done: 604 | return 1; 605 | } 606 | 607 | static int 608 | json_null(lua_State *L) 609 | { 610 | lua_pushstring(L, "null"); 611 | return 1; 612 | } 613 | 614 | int 615 | luaopen_json(lua_State* L) 616 | { 617 | static const struct luaL_Reg methods[] = { 618 | { "decode", json_decode }, 619 | { "encode", json_encode }, 620 | { "isnull", json_isnull }, 621 | { NULL, NULL } 622 | }; 623 | static const struct luaL_Reg null_methods[] = { 624 | { "__tostring", json_null }, 625 | { "__call", json_null }, 626 | { NULL, NULL } 627 | }; 628 | luaL_newlib(L, methods); 629 | lua_pushliteral(L, "_COPYRIGHT"); 630 | lua_pushliteral(L, "Copyright (C) 2011 - 2022 " 631 | "micro systems marc balmer"); 632 | lua_settable(L, -3); 633 | lua_pushliteral(L, "_DESCRIPTION"); 634 | lua_pushliteral(L, "JSON encoder/decoder for Lua"); 635 | lua_settable(L, -3); 636 | lua_pushliteral(L, "_VERSION"); 637 | lua_pushliteral(L, "json 1.3.0"); 638 | lua_settable(L, -3); 639 | 640 | lua_newtable(L); 641 | 642 | /* The null metatable */ 643 | if (luaL_newmetatable(L, JSON_NULL_METATABLE)) { 644 | luaL_setfuncs(L, null_methods, 0); 645 | lua_pushliteral(L, "__metatable"); 646 | lua_pushliteral(L, "must not access this metatable"); 647 | lua_settable(L, -3); 648 | 649 | } 650 | lua_setmetatable(L, -2); 651 | 652 | if (luaL_newmetatable(L, JSON_GCMEM_METATABLE)) { 653 | lua_pushliteral(L, "__gc"); 654 | lua_pushcfunction(L, gcmem_clear); 655 | lua_settable(L, -3); 656 | } 657 | lua_pop(L, 1); 658 | 659 | lua_setfield(L, -2, "null"); 660 | return 1; 661 | } 662 | -------------------------------------------------------------------------------- /null.lua: -------------------------------------------------------------------------------- 1 | local json = require 'json' 2 | 3 | local d = { 4 | a = 42, 5 | b = json.null 6 | } 7 | 8 | print(json.encode(d)) 9 | 10 | -------------------------------------------------------------------------------- /shlib_version: -------------------------------------------------------------------------------- 1 | major=1 2 | minor=0 3 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | -- import the json module 2 | 3 | local json = require('json') 4 | 5 | local foo = json.decode([[ 6 | {"name" : "lol", "age" : -1.5e+06, "foo" : ["bar", true, null]} 7 | ]]) 8 | foo.x = 'x' 9 | -- foo[1] = 'hossa' 10 | -- foo[2] = 'rossa' 11 | 12 | print(foo.age) -- -1500000 13 | print(foo.name) -- lol 14 | print(foo.foo[1]) -- bar 15 | print(foo.foo[2]) -- true 16 | print(foo.foo[3]) -- null 17 | print(json.isnull(foo.foo[3])) -- true 18 | foo.foox = "omg :D" 19 | foo.theNull = json.null 20 | foo.itIs = true 21 | foo.itIsNot = false 22 | foo.isNil = nil 23 | foo.a = 'a' 24 | 25 | foo.subtable = { 26 | a = 'one', 27 | b = 'two' 28 | } 29 | 30 | local a = { 31 | test = 'hello', 32 | test2 = 'world' 33 | } 34 | 35 | foo.nested = { 36 | deeper = { 37 | name = 'Miller', 38 | location = 'Brooklyn' 39 | }, 40 | } 41 | 42 | -- foo.nested.anotherfoo = foo 43 | a.myself = a 44 | 45 | local str = json.encode(foo) 46 | print(str) 47 | 48 | local foo2 = json.decode(str) 49 | 50 | print(json.encode(foo2)) -- {"name":"lol",age:-1500000,"foo":"omg :D"} 51 | print(json.encode(nil)) 52 | print(json.encode(function () print('foo') end)) 53 | 54 | print(json.encode {{a=1},{b=2}}) 55 | --------------------------------------------------------------------------------