| rev | 
   line source | 
| 
jbe@121
 | 
     1 #include <lua.h>
 | 
| 
jbe@121
 | 
     2 #include <lauxlib.h>
 | 
| 
jbe@122
 | 
     3 #include <stdlib.h>
 | 
| 
jbe@121
 | 
     4 #include <string.h>
 | 
| 
jbe@154
 | 
     5 #include <math.h>
 | 
| 
jbe@432
 | 
     6 #include <stdint.h>
 | 
| 
jbe@432
 | 
     7 /* TODO: stdint.h only needed for Lua 5.2 compatibility */
 | 
| 
jbe@121
 | 
     8 
 | 
| 
jbe@144
 | 
     9 // maximum number of nested JSON values (objects and arrays):
 | 
| 
jbe@182
 | 
    10 // NOTE: json_import can store 2^32 / 3 levels on stack swap (using
 | 
| 
jbe@183
 | 
    11 //       also negative indicies after integer wraparound), and
 | 
| 
jbe@183
 | 
    12 //       json_export can store even more levels, so 1024^3 =
 | 
| 
jbe@183
 | 
    13 //       1073741824 is a safe value and allows practically unlimited
 | 
| 
jbe@183
 | 
    14 //       levels for JSON documents <= 2 GiB.
 | 
| 
jbe@182
 | 
    15 #define JSON_MAXDEPTH (1024*1024*1024)
 | 
| 
jbe@142
 | 
    16 
 | 
| 
jbe@193
 | 
    17 // define type JSON_LIGHTUSERDATA and
 | 
| 
jbe@193
 | 
    18 // generate dummy memory addresses for lightuserdata values:
 | 
| 
jbe@193
 | 
    19 #define JSON_LIGHTUSERDATA char
 | 
| 
jbe@193
 | 
    20 static struct {
 | 
| 
jbe@193
 | 
    21   JSON_LIGHTUSERDATA nullmark;   // lightuserdata value represents a NULL value
 | 
| 
jbe@193
 | 
    22   JSON_LIGHTUSERDATA shadowtbl;  // lightuserdata key for shadow table
 | 
| 
jbe@193
 | 
    23 } json_lightuserdata;
 | 
| 
jbe@193
 | 
    24 
 | 
| 
jbe@193
 | 
    25 // macros for special nullmark value:
 | 
| 
jbe@193
 | 
    26 #define json_isnullmark(L, i) (lua_touserdata((L), (i)) == &json_lightuserdata.nullmark)
 | 
| 
jbe@193
 | 
    27 #define json_pushnullmark(L) lua_pushlightuserdata((L), &json_lightuserdata.nullmark)
 | 
| 
jbe@193
 | 
    28 
 | 
| 
jbe@193
 | 
    29 // macros for getting and setting shadow tables
 | 
| 
jbe@193
 | 
    30 #define json_setshadow(L, i) lua_rawsetp((L), (i), &json_lightuserdata.shadowtbl)
 | 
| 
jbe@193
 | 
    31 #define json_getshadow(L, i) lua_rawgetp((L), (i), &json_lightuserdata.shadowtbl)
 | 
| 
jbe@193
 | 
    32 #define json_createproxy(L) lua_createtable((L), 0, 1)
 | 
| 
jbe@193
 | 
    33 
 | 
| 
jbe@193
 | 
    34 // generate additional dummy memory addresses that represent Lua objects
 | 
| 
jbe@193
 | 
    35 // via lightuserdata keys and LUA_REGISTRYINDEX:
 | 
| 
jbe@193
 | 
    36 static struct {
 | 
| 
jbe@193
 | 
    37   JSON_LIGHTUSERDATA objectmt;  // metatable for JSON objects
 | 
| 
jbe@193
 | 
    38   JSON_LIGHTUSERDATA arraymt;   // metatable for JSON arrays
 | 
| 
jbe@193
 | 
    39 } json_registry;
 | 
| 
jbe@155
 | 
    40 
 | 
| 
jbe@144
 | 
    41 // macros for usage of Lua registry:
 | 
| 
jbe@145
 | 
    42 #define json_regpointer(x) (&json_registry.x)
 | 
| 
jbe@151
 | 
    43 #define json_regfetchpointer(L, x) lua_rawgetp((L), LUA_REGISTRYINDEX, (x))
 | 
| 
jbe@151
 | 
    44 #define json_regfetch(L, x) json_regfetchpointer(L, json_regpointer(x))
 | 
| 
jbe@151
 | 
    45 #define json_regstore(L, x) lua_rawsetp(L, LUA_REGISTRYINDEX, json_regpointer(x))
 | 
| 
jbe@145
 | 
    46 
 | 
| 
jbe@157
 | 
    47 // returns the string "<JSON null marker>":
 | 
| 
jbe@157
 | 
    48 static int json_nullmark_tostring(lua_State *L) {
 | 
| 
jbe@157
 | 
    49   lua_pushliteral(L, "<JSON null marker>");
 | 
| 
jbe@157
 | 
    50   return 1;
 | 
| 
jbe@157
 | 
    51 }
 | 
| 
jbe@157
 | 
    52 
 | 
| 
jbe@202
 | 
    53 #define json_object_source_idx 1
 | 
| 
jbe@202
 | 
    54 #define json_object_iterator_idx 2
 | 
| 
jbe@202
 | 
    55 #define json_object_output_idx 3
 | 
| 
jbe@202
 | 
    56 #define json_object_shadow_idx 4
 | 
| 
jbe@202
 | 
    57 #define json_object_iterfun_idx 5
 | 
| 
jbe@202
 | 
    58 #define json_object_itertbl_idx 6
 | 
| 
jbe@169
 | 
    59 
 | 
| 
jbe@202
 | 
    60 // converts a Lua table (or any other iterable value) to a JSON object:
 | 
| 
jbe@169
 | 
    61 // (does never modify the argument, returns an empty object or array if argument is nil)
 | 
| 
jbe@202
 | 
    62 static int json_object(lua_State *L) {
 | 
| 
jbe@171
 | 
    63   // determine is argument is given:
 | 
| 
jbe@202
 | 
    64   if (lua_isnoneornil(L, json_object_source_idx)) {
 | 
| 
jbe@171
 | 
    65     // if no argument is given (or if argument is nil),
 | 
| 
jbe@193
 | 
    66     // create proxy table with shadow table, and leave proxy table on top of stack:
 | 
| 
jbe@193
 | 
    67     json_createproxy(L);
 | 
| 
jbe@169
 | 
    68     lua_newtable(L);
 | 
| 
jbe@193
 | 
    69     json_setshadow(L, -2);
 | 
| 
jbe@169
 | 
    70   } else {
 | 
| 
jbe@171
 | 
    71     // if an argument was given,
 | 
| 
jbe@193
 | 
    72     // stack shall contain only one function argument:
 | 
| 
jbe@171
 | 
    73     lua_settop(L, 1);
 | 
| 
jbe@193
 | 
    74     // check if there is an iterator function in its metatable:
 | 
| 
jbe@202
 | 
    75     if (luaL_getmetafield(L, json_object_source_idx, "__pairs")) {
 | 
| 
jbe@193
 | 
    76       // if there is an iterator function,
 | 
| 
jbe@193
 | 
    77       // leave it on stack position 2 and verify its type:
 | 
| 
jbe@202
 | 
    78       if (lua_type(L, json_object_iterator_idx) != LUA_TFUNCTION)
 | 
| 
jbe@202
 | 
    79         return luaL_error(L, "__pairs metamethod is not a function");
 | 
| 
jbe@169
 | 
    80     } else {
 | 
| 
jbe@193
 | 
    81       // if there is no iterator function,
 | 
| 
jbe@193
 | 
    82       // verify the type of the argument itself:
 | 
| 
jbe@202
 | 
    83       luaL_checktype(L, json_object_source_idx, LUA_TTABLE);
 | 
| 
jbe@193
 | 
    84       // push nil onto stack position 2:
 | 
| 
jbe@169
 | 
    85       lua_pushnil(L);
 | 
| 
jbe@143
 | 
    86     }
 | 
| 
jbe@171
 | 
    87     // create result table on stack position 3:
 | 
| 
jbe@193
 | 
    88     json_createproxy(L);
 | 
| 
jbe@169
 | 
    89     // create shadow table on stack position 4:
 | 
| 
jbe@169
 | 
    90     lua_newtable(L);
 | 
| 
jbe@193
 | 
    91     lua_pushvalue(L, -1);
 | 
| 
jbe@193
 | 
    92     json_setshadow(L, -3);
 | 
| 
jbe@171
 | 
    93     // check if iterator function exists:
 | 
| 
jbe@202
 | 
    94     if (lua_isnil(L, json_object_iterator_idx)) {
 | 
| 
jbe@171
 | 
    95       // if there is no iterator function,
 | 
| 
jbe@202
 | 
    96       // copy all string key value pairs to shadow table:
 | 
| 
jbe@202
 | 
    97       for (lua_pushnil(L); lua_next(L, json_object_source_idx); lua_pop(L, 1)) {
 | 
| 
jbe@202
 | 
    98         if (lua_type(L, -2) == LUA_TSTRING) {
 | 
| 
jbe@202
 | 
    99           lua_pushvalue(L, -2);
 | 
| 
jbe@202
 | 
   100           lua_pushvalue(L, -2);
 | 
| 
jbe@202
 | 
   101           lua_rawset(L, json_object_shadow_idx);
 | 
| 
jbe@171
 | 
   102         }
 | 
| 
jbe@169
 | 
   103       }
 | 
| 
jbe@169
 | 
   104     } else {
 | 
| 
jbe@172
 | 
   105       // if there is an iterator function,
 | 
| 
jbe@172
 | 
   106       // call iterator function with source value (first argument)
 | 
| 
jbe@172
 | 
   107       // and store 3 result values on stack positions 5 through 7:
 | 
| 
jbe@202
 | 
   108       lua_pushvalue(L, json_object_iterator_idx);
 | 
| 
jbe@172
 | 
   109       lua_pushvalue(L, 1);
 | 
| 
jbe@172
 | 
   110       lua_call(L, 1, 3);
 | 
| 
jbe@175
 | 
   111       // iterate through key value pairs and store some of them in shadow table
 | 
| 
jbe@174
 | 
   112       // while replacing nil values with null-marker:
 | 
| 
jbe@172
 | 
   113       while (1) {
 | 
| 
jbe@175
 | 
   114         // call iterfun function:
 | 
| 
jbe@202
 | 
   115         lua_pushvalue(L, json_object_iterfun_idx);
 | 
| 
jbe@202
 | 
   116         lua_pushvalue(L, json_object_itertbl_idx);
 | 
| 
jbe@172
 | 
   117         lua_pushvalue(L, -3);
 | 
| 
jbe@172
 | 
   118         lua_remove(L, -4);
 | 
| 
jbe@172
 | 
   119         lua_call(L, 2, 2);
 | 
| 
jbe@175
 | 
   120         // break iteration loop if key is nil:
 | 
| 
jbe@172
 | 
   121         if (lua_isnil(L, -2)) break;
 | 
| 
jbe@175
 | 
   122         // store key value pair only if key type is correct:
 | 
| 
jbe@202
 | 
   123         if (lua_type(L, -2) == LUA_TSTRING) {
 | 
| 
jbe@175
 | 
   124           // if key type is correct,
 | 
| 
jbe@175
 | 
   125           // push key onto stack:
 | 
| 
jbe@172
 | 
   126           lua_pushvalue(L, -2);
 | 
| 
jbe@175
 | 
   127           // if value is nil, push null-marker onto stack (as value):
 | 
| 
jbe@174
 | 
   128           if (lua_isnil(L, -2)) json_pushnullmark(L);
 | 
| 
jbe@175
 | 
   129           // else push value onto stack:
 | 
| 
jbe@174
 | 
   130           else lua_pushvalue(L, -2);
 | 
| 
jbe@175
 | 
   131           // set key value pair in shadow table:
 | 
| 
jbe@202
 | 
   132           lua_rawset(L, json_object_shadow_idx);
 | 
| 
jbe@172
 | 
   133         }
 | 
| 
jbe@175
 | 
   134         // pop value from stack, but leave key on stack:
 | 
| 
jbe@172
 | 
   135         lua_pop(L, 1);
 | 
| 
jbe@172
 | 
   136       }
 | 
| 
jbe@143
 | 
   137     }
 | 
| 
jbe@171
 | 
   138     // let result table be on top of stack:
 | 
| 
jbe@202
 | 
   139     lua_settop(L, json_object_output_idx);
 | 
| 
jbe@136
 | 
   140   }
 | 
| 
jbe@171
 | 
   141   // set metatable (for result table on top of stack):
 | 
| 
jbe@202
 | 
   142   json_regfetch(L, objectmt);
 | 
| 
jbe@169
 | 
   143   lua_setmetatable(L, -2);
 | 
| 
jbe@171
 | 
   144   // return table on top of stack:
 | 
| 
jbe@136
 | 
   145   return 1;
 | 
| 
jbe@136
 | 
   146 }
 | 
| 
jbe@136
 | 
   147 
 | 
| 
jbe@202
 | 
   148 #define json_array_source_idx 1
 | 
| 
jbe@202
 | 
   149 #define json_array_output_idx 2
 | 
| 
jbe@202
 | 
   150 #define json_array_shadow_idx 3
 | 
| 
jbe@136
 | 
   151 
 | 
| 
jbe@175
 | 
   152 // converts a Lua table (or any other iterable value) to a JSON array:
 | 
| 
jbe@175
 | 
   153 // (does never modify the argument, returns an empty object or array if argument is nil)
 | 
| 
jbe@136
 | 
   154 static int json_array(lua_State *L) {
 | 
| 
jbe@202
 | 
   155   // determine is argument is given:
 | 
| 
jbe@202
 | 
   156   if (lua_isnoneornil(L, json_array_source_idx)) {
 | 
| 
jbe@202
 | 
   157     // if no argument is given (or if argument is nil),
 | 
| 
jbe@202
 | 
   158     // create proxy table with shadow table, and leave proxy table on top of stack:
 | 
| 
jbe@202
 | 
   159     json_createproxy(L);
 | 
| 
jbe@202
 | 
   160     lua_newtable(L);
 | 
| 
jbe@202
 | 
   161     json_setshadow(L, -2);
 | 
| 
jbe@202
 | 
   162   } else {
 | 
| 
jbe@202
 | 
   163     lua_Integer arrayidx, arraylen;
 | 
| 
jbe@202
 | 
   164     // if an argument was given,
 | 
| 
jbe@202
 | 
   165     // stack shall contain only one function argument:
 | 
| 
jbe@202
 | 
   166     lua_settop(L, 1);
 | 
| 
jbe@202
 | 
   167     // create result table on stack position 2:
 | 
| 
jbe@202
 | 
   168     json_createproxy(L);
 | 
| 
jbe@202
 | 
   169     // create shadow table on stack position 3:
 | 
| 
jbe@202
 | 
   170     lua_newtable(L);
 | 
| 
jbe@202
 | 
   171     lua_pushvalue(L, -1);
 | 
| 
jbe@202
 | 
   172     json_setshadow(L, -3);
 | 
| 
jbe@202
 | 
   173     // determine length of array:
 | 
| 
jbe@202
 | 
   174     arraylen = luaL_len(L, json_array_source_idx);
 | 
| 
jbe@202
 | 
   175     // for an array, copy consecutive integer value pairs to shadow table:
 | 
| 
jbe@202
 | 
   176     for (arrayidx=0; arrayidx<arraylen; ) {
 | 
| 
jbe@202
 | 
   177       // increment arrayidx at head of loop:
 | 
| 
jbe@202
 | 
   178       arrayidx++;
 | 
| 
jbe@202
 | 
   179       // get next array entry:
 | 
| 
jbe@202
 | 
   180       lua_pushinteger(L, arrayidx);
 | 
| 
jbe@202
 | 
   181       lua_gettable(L, json_array_source_idx);
 | 
| 
jbe@202
 | 
   182       // check if value is nil:
 | 
| 
jbe@202
 | 
   183       if (lua_isnil(L, -1)) {
 | 
| 
jbe@202
 | 
   184         // if yes, replace it with null-marker:
 | 
| 
jbe@202
 | 
   185         lua_pop(L, 1);
 | 
| 
jbe@202
 | 
   186         json_pushnullmark(L);
 | 
| 
jbe@202
 | 
   187       }
 | 
| 
jbe@202
 | 
   188       // store value in shadow table:
 | 
| 
jbe@202
 | 
   189       lua_rawseti(L, json_array_shadow_idx, arrayidx);
 | 
| 
jbe@202
 | 
   190     }
 | 
| 
jbe@202
 | 
   191     // let result table be on top of stack:
 | 
| 
jbe@202
 | 
   192     lua_settop(L, json_array_output_idx);
 | 
| 
jbe@202
 | 
   193   }
 | 
| 
jbe@202
 | 
   194   // set metatable (for result table on top of stack):
 | 
| 
jbe@202
 | 
   195   json_regfetch(L, arraymt);
 | 
| 
jbe@202
 | 
   196   lua_setmetatable(L, -2);
 | 
| 
jbe@202
 | 
   197   // return table on top of stack:
 | 
| 
jbe@202
 | 
   198   return 1;
 | 
| 
jbe@136
 | 
   199 }
 | 
| 
jbe@136
 | 
   200 
 | 
| 
jbe@145
 | 
   201 // internal states of JSON parser:
 | 
| 
jbe@124
 | 
   202 #define JSON_STATE_VALUE 0
 | 
| 
jbe@124
 | 
   203 #define JSON_STATE_OBJECT_KEY 1
 | 
| 
jbe@124
 | 
   204 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2
 | 
| 
jbe@124
 | 
   205 #define JSON_STATE_OBJECT_VALUE 3
 | 
| 
jbe@124
 | 
   206 #define JSON_STATE_OBJECT_SEPARATOR 4
 | 
| 
jbe@124
 | 
   207 #define JSON_STATE_ARRAY_VALUE 5
 | 
| 
jbe@124
 | 
   208 #define JSON_STATE_ARRAY_SEPARATOR 6
 | 
| 
jbe@124
 | 
   209 #define JSON_STATE_END 7
 | 
| 
jbe@121
 | 
   210 
 | 
| 
jbe@145
 | 
   211 // special Lua stack indicies for json_import function:
 | 
| 
jbe@138
 | 
   212 #define json_import_objectmt_idx 2
 | 
| 
jbe@138
 | 
   213 #define json_import_arraymt_idx 3
 | 
| 
jbe@193
 | 
   214 #define json_import_stackswap_idx 4
 | 
| 
jbe@138
 | 
   215 
 | 
| 
jbe@168
 | 
   216 // macros for hex decoding:
 | 
| 
jbe@168
 | 
   217 #define json_utf16_surrogate(x) ((x) >= 0xD800 && (x) <= 0xDFFF)
 | 
| 
jbe@168
 | 
   218 #define json_utf16_lead(x) ((x) >= 0xD800 && (x) <= 0xDBFF)
 | 
| 
jbe@168
 | 
   219 #define json_utf16_tail(x) ((x) >= 0xDC00 && (x) <= 0xDFFF)
 | 
| 
jbe@167
 | 
   220 #define json_import_readhex(x) \
 | 
| 
jbe@167
 | 
   221   do { \
 | 
| 
jbe@167
 | 
   222     x = 0; \
 | 
| 
jbe@167
 | 
   223     for (i=0; i<4; i++) { \
 | 
| 
jbe@167
 | 
   224       x <<= 4; \
 | 
| 
jbe@167
 | 
   225       c = str[pos++]; \
 | 
| 
jbe@167
 | 
   226       if (c >= '0' && c <= '9') x += c - '0'; \
 | 
| 
jbe@167
 | 
   227       else if (c >= 'A' && c <= 'F') x += c - 'A' + 10; \
 | 
| 
jbe@167
 | 
   228       else if (c >= 'a' && c <= 'f') x += c - 'a' + 10; \
 | 
| 
jbe@167
 | 
   229       else if (c == 0) goto json_import_unexpected_eof; \
 | 
| 
jbe@167
 | 
   230       else goto json_import_unexpected_escape; \
 | 
| 
jbe@167
 | 
   231     } \
 | 
| 
jbe@167
 | 
   232   } while (0)
 | 
| 
jbe@167
 | 
   233 
 | 
| 
jbe@136
 | 
   234 // decodes a JSON document:
 | 
| 
jbe@121
 | 
   235 static int json_import(lua_State *L) {
 | 
| 
jbe@181
 | 
   236   int stackswapidx = 0;  // elements in stack swap table
 | 
| 
jbe@181
 | 
   237   int i;                 // loop variable
 | 
| 
jbe@181
 | 
   238   const char *str;       // string to parse
 | 
| 
jbe@181
 | 
   239   size_t total;          // total length of string to parse
 | 
| 
jbe@181
 | 
   240   size_t pos = 0;        // current position in string to parse
 | 
| 
jbe@181
 | 
   241   size_t level = 0;      // nested levels of objects/arrays currently being processed
 | 
| 
jbe@145
 | 
   242   int mode = JSON_STATE_VALUE;  // state of parser (i.e. "what's expected next?")
 | 
| 
jbe@181
 | 
   243   unsigned char c;       // variable to store a single character to be processed (unsigned!)
 | 
| 
jbe@181
 | 
   244   luaL_Buffer luabuf;    // Lua buffer to decode JSON string values
 | 
| 
jbe@181
 | 
   245   char *cbuf;            // C buffer to decode JSON string values
 | 
| 
jbe@181
 | 
   246   size_t outlen;         // maximum length or write position of C buffer
 | 
| 
jbe@181
 | 
   247   long codepoint;        // decoded UTF-16 character or higher codepoint
 | 
| 
jbe@181
 | 
   248   long utf16tail;        // second decoded UTF-16 character (surrogate tail)
 | 
| 
jbe@181
 | 
   249   size_t arraylen;       // variable to temporarily store the array length
 | 
| 
jbe@166
 | 
   250   // require string as argument and convert to C string with length information:
 | 
| 
jbe@166
 | 
   251   str = luaL_checklstring(L, 1, &total);
 | 
| 
jbe@166
 | 
   252   // if string contains a NULL byte, this is a syntax error
 | 
| 
jbe@166
 | 
   253   if (strlen(str) != total) goto json_import_syntax_error;
 | 
| 
jbe@147
 | 
   254   // stack shall contain one function argument:
 | 
| 
jbe@138
 | 
   255   lua_settop(L, 1);
 | 
| 
jbe@147
 | 
   256   // push objectmt onto stack position 2:
 | 
| 
jbe@144
 | 
   257   json_regfetch(L, objectmt);
 | 
| 
jbe@147
 | 
   258   // push arraymt onto stack position 3:
 | 
| 
jbe@144
 | 
   259   json_regfetch(L, arraymt);
 | 
| 
jbe@181
 | 
   260   // push table for stack swapping onto stack position 5:
 | 
| 
jbe@181
 | 
   261   // (needed to avoid Lua stack overflows)
 | 
| 
jbe@181
 | 
   262   lua_newtable(L);
 | 
| 
jbe@136
 | 
   263   // main loop of parser:
 | 
| 
jbe@136
 | 
   264   json_import_loop:
 | 
| 
jbe@136
 | 
   265   // skip whitespace and store next character in variable 'c':
 | 
| 
jbe@146
 | 
   266   while (c = str[pos],
 | 
| 
jbe@146
 | 
   267     c == ' ' ||
 | 
| 
jbe@146
 | 
   268     c == '\f' ||
 | 
| 
jbe@146
 | 
   269     c == '\n' ||
 | 
| 
jbe@146
 | 
   270     c == '\r' ||
 | 
| 
jbe@146
 | 
   271     c == '\t' ||
 | 
| 
jbe@146
 | 
   272     c == '\v'
 | 
| 
jbe@146
 | 
   273   ) pos++;
 | 
| 
jbe@170
 | 
   274   // NOTE: variable c needs to be unsigned in the following code
 | 
| 
jbe@136
 | 
   275   // switch statement to handle certain (single) characters:
 | 
| 
jbe@121
 | 
   276   switch (c) {
 | 
| 
jbe@136
 | 
   277   // handle end of JSON document:
 | 
| 
jbe@121
 | 
   278   case 0:
 | 
| 
jbe@136
 | 
   279     // if end of JSON document was expected, then return top element of stack as result:
 | 
| 
jbe@124
 | 
   280     if (mode == JSON_STATE_END) return 1;
 | 
| 
jbe@136
 | 
   281     // otherwise, the JSON document was malformed:
 | 
| 
jbe@167
 | 
   282     if (level == 0) {
 | 
| 
jbe@167
 | 
   283       lua_pushnil(L);
 | 
| 
jbe@167
 | 
   284       lua_pushliteral(L, "Empty string");
 | 
| 
jbe@167
 | 
   285     } else {
 | 
| 
jbe@167
 | 
   286       json_import_unexpected_eof:
 | 
| 
jbe@167
 | 
   287       lua_pushnil(L);
 | 
| 
jbe@167
 | 
   288       lua_pushliteral(L, "Unexpected end of JSON document");
 | 
| 
jbe@167
 | 
   289     }
 | 
| 
jbe@121
 | 
   290     return 2;
 | 
| 
jbe@181
 | 
   291   // new JSON object or JSON array:
 | 
| 
jbe@121
 | 
   292   case '{':
 | 
| 
jbe@181
 | 
   293   case '[':
 | 
| 
jbe@181
 | 
   294     // if an encountered JSON object is not expected here, then return an error:
 | 
| 
jbe@146
 | 
   295     if (
 | 
| 
jbe@181
 | 
   296       c == '{' &&
 | 
| 
jbe@181
 | 
   297       mode != JSON_STATE_VALUE &&
 | 
| 
jbe@181
 | 
   298       mode != JSON_STATE_OBJECT_VALUE &&
 | 
| 
jbe@181
 | 
   299       mode != JSON_STATE_ARRAY_VALUE
 | 
| 
jbe@181
 | 
   300     ) goto json_import_syntax_error;
 | 
| 
jbe@181
 | 
   301     // if an encountered JSON array is not expected here, then return an error:
 | 
| 
jbe@181
 | 
   302     if (
 | 
| 
jbe@181
 | 
   303       c == '[' &&
 | 
| 
jbe@146
 | 
   304       mode != JSON_STATE_VALUE &&
 | 
| 
jbe@146
 | 
   305       mode != JSON_STATE_OBJECT_VALUE &&
 | 
| 
jbe@146
 | 
   306       mode != JSON_STATE_ARRAY_VALUE
 | 
| 
jbe@146
 | 
   307     ) goto json_import_syntax_error;
 | 
| 
jbe@181
 | 
   308     // consume input character:
 | 
| 
jbe@181
 | 
   309     pos++;
 | 
| 
jbe@181
 | 
   310     // limit nested levels:
 | 
| 
jbe@181
 | 
   311     if (level >= JSON_MAXDEPTH) {
 | 
| 
jbe@181
 | 
   312       lua_pushnil(L);
 | 
| 
jbe@181
 | 
   313       lua_pushfstring(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
 | 
| 
jbe@181
 | 
   314       return 2;
 | 
| 
jbe@181
 | 
   315     }
 | 
| 
jbe@181
 | 
   316     // swap Lua stack entries for previous level to swap table:
 | 
| 
jbe@181
 | 
   317     // (avoids depth limitations due to Lua stack size)
 | 
| 
jbe@181
 | 
   318     if (level) {
 | 
| 
jbe@181
 | 
   319       lua_rawseti(L, json_import_stackswap_idx, ++stackswapidx);
 | 
| 
jbe@181
 | 
   320       lua_rawseti(L, json_import_stackswap_idx, ++stackswapidx);
 | 
| 
jbe@181
 | 
   321       lua_rawseti(L, json_import_stackswap_idx, ++stackswapidx);
 | 
| 
jbe@181
 | 
   322     }
 | 
| 
jbe@181
 | 
   323     // increment level:
 | 
| 
jbe@181
 | 
   324     level++;
 | 
| 
jbe@181
 | 
   325     // create JSON object or JSON array on stack:
 | 
| 
jbe@136
 | 
   326     lua_newtable(L);
 | 
| 
jbe@181
 | 
   327     // set metatable of JSON object or JSON array:
 | 
| 
jbe@181
 | 
   328     lua_pushvalue(L, c == '{' ? json_import_objectmt_idx : json_import_arraymt_idx);
 | 
| 
jbe@125
 | 
   329     lua_setmetatable(L, -2);
 | 
| 
jbe@136
 | 
   330     // create internal shadow table on stack:
 | 
| 
jbe@136
 | 
   331     lua_newtable(L);
 | 
| 
jbe@146
 | 
   332     // register internal shadow table:
 | 
| 
jbe@193
 | 
   333     lua_pushvalue(L, -1);
 | 
| 
jbe@193
 | 
   334     json_setshadow(L, -3);
 | 
| 
jbe@181
 | 
   335     // distinguish between JSON objects and JSON arrays:
 | 
| 
jbe@181
 | 
   336     if (c == '{') {
 | 
| 
jbe@181
 | 
   337       // if JSON object,
 | 
| 
jbe@181
 | 
   338       // expect object key (or end of object) to follow:
 | 
| 
jbe@181
 | 
   339       mode = JSON_STATE_OBJECT_KEY;
 | 
| 
jbe@181
 | 
   340     } else {
 | 
| 
jbe@181
 | 
   341       // if JSON array,
 | 
| 
jbe@181
 | 
   342       // expect array value (or end of array) to follow:
 | 
| 
jbe@181
 | 
   343       mode = JSON_STATE_ARRAY_VALUE;
 | 
| 
jbe@181
 | 
   344       // add nil as key (needed to keep stack balance) and as magic to detect arrays:
 | 
| 
jbe@181
 | 
   345       if (c == '[') lua_pushnil(L);
 | 
| 
jbe@142
 | 
   346     }
 | 
| 
jbe@121
 | 
   347     goto json_import_loop;
 | 
| 
jbe@136
 | 
   348   // end of JSON object:
 | 
| 
jbe@121
 | 
   349   case '}':
 | 
| 
jbe@136
 | 
   350     // if end of JSON object is not expected here, then return an error:
 | 
| 
jbe@146
 | 
   351     if (
 | 
| 
jbe@146
 | 
   352       mode != JSON_STATE_OBJECT_KEY &&
 | 
| 
jbe@146
 | 
   353       mode != JSON_STATE_OBJECT_SEPARATOR
 | 
| 
jbe@146
 | 
   354     ) goto json_import_syntax_error;
 | 
| 
jbe@136
 | 
   355     // jump to common code for end of JSON object and JSON array:
 | 
| 
jbe@121
 | 
   356     goto json_import_close;
 | 
| 
jbe@136
 | 
   357   // end of JSON array:
 | 
| 
jbe@121
 | 
   358   case ']':
 | 
| 
jbe@136
 | 
   359     // if end of JSON array is not expected here, then return an error:
 | 
| 
jbe@146
 | 
   360     if (
 | 
| 
jbe@146
 | 
   361       mode != JSON_STATE_ARRAY_VALUE &&
 | 
| 
jbe@146
 | 
   362       mode != JSON_STATE_ARRAY_SEPARATOR
 | 
| 
jbe@146
 | 
   363     ) goto json_import_syntax_error;
 | 
| 
jbe@146
 | 
   364     // pop nil key/magic (that was needed to keep stack balance):
 | 
| 
jbe@140
 | 
   365     lua_pop(L, 1);
 | 
| 
jbe@136
 | 
   366     // continue with common code for end of JSON object and JSON array:
 | 
| 
jbe@136
 | 
   367   // common code for end of JSON object or JSON array:
 | 
| 
jbe@121
 | 
   368   json_import_close:
 | 
| 
jbe@136
 | 
   369     // consume input character:
 | 
| 
jbe@121
 | 
   370     pos++;
 | 
| 
jbe@136
 | 
   371     // pop shadow table:
 | 
| 
jbe@136
 | 
   372     lua_pop(L, 1);
 | 
| 
jbe@136
 | 
   373     // check if nested:
 | 
| 
jbe@121
 | 
   374     if (--level) {
 | 
| 
jbe@146
 | 
   375       // if nested,
 | 
| 
jbe@181
 | 
   376       // restore previous stack elements from stack swap:
 | 
| 
jbe@181
 | 
   377       lua_rawgeti(L, json_import_stackswap_idx, stackswapidx--);
 | 
| 
jbe@181
 | 
   378       lua_insert(L, -2);
 | 
| 
jbe@181
 | 
   379       lua_rawgeti(L, json_import_stackswap_idx, stackswapidx--);
 | 
| 
jbe@181
 | 
   380       lua_insert(L, -2);
 | 
| 
jbe@181
 | 
   381       lua_rawgeti(L, json_import_stackswap_idx, stackswapidx--);
 | 
| 
jbe@181
 | 
   382       lua_insert(L, -2);
 | 
| 
jbe@146
 | 
   383       // check if outer(!) structure is an array or object:
 | 
| 
jbe@140
 | 
   384       if (lua_isnil(L, -2)) {
 | 
| 
jbe@136
 | 
   385         // select array value processing:
 | 
| 
jbe@124
 | 
   386         mode = JSON_STATE_ARRAY_VALUE;
 | 
| 
jbe@121
 | 
   387       } else {
 | 
| 
jbe@136
 | 
   388         // select object value processing:
 | 
| 
jbe@124
 | 
   389         mode = JSON_STATE_OBJECT_VALUE;
 | 
| 
jbe@121
 | 
   390       }
 | 
| 
jbe@136
 | 
   391       // store value in outer structure:
 | 
| 
jbe@121
 | 
   392       goto json_import_process_value;
 | 
| 
jbe@121
 | 
   393     }
 | 
| 
jbe@136
 | 
   394     // if not nested, then expect end of JSON document and continue with loop:
 | 
| 
jbe@136
 | 
   395     mode = JSON_STATE_END;
 | 
| 
jbe@121
 | 
   396     goto json_import_loop;
 | 
| 
jbe@136
 | 
   397   // key terminator:
 | 
| 
jbe@121
 | 
   398   case ':':
 | 
| 
jbe@136
 | 
   399     // if key terminator is not expected here, then return an error:
 | 
| 
jbe@124
 | 
   400     if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR)
 | 
| 
jbe@121
 | 
   401       goto json_import_syntax_error;
 | 
| 
jbe@136
 | 
   402     // consume input character:
 | 
| 
jbe@121
 | 
   403     pos++;
 | 
| 
jbe@146
 | 
   404     // expect object value to follow:
 | 
| 
jbe@124
 | 
   405     mode = JSON_STATE_OBJECT_VALUE;
 | 
| 
jbe@146
 | 
   406     // continue with loop:
 | 
| 
jbe@121
 | 
   407     goto json_import_loop;
 | 
| 
jbe@136
 | 
   408   // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
 | 
| 
jbe@121
 | 
   409   case ',':
 | 
| 
jbe@146
 | 
   410     // branch according to parser state:
 | 
| 
jbe@124
 | 
   411     if (mode == JSON_STATE_OBJECT_SEPARATOR) {
 | 
| 
jbe@146
 | 
   412       // expect an object key to follow:
 | 
| 
jbe@124
 | 
   413       mode = JSON_STATE_OBJECT_KEY;
 | 
| 
jbe@124
 | 
   414     } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
 | 
| 
jbe@146
 | 
   415       // expect an array value to follow:
 | 
| 
jbe@124
 | 
   416       mode = JSON_STATE_ARRAY_VALUE;
 | 
| 
jbe@121
 | 
   417     } else {
 | 
| 
jbe@136
 | 
   418        // if value terminator is not expected here, then return an error:
 | 
| 
jbe@136
 | 
   419        goto json_import_syntax_error;
 | 
| 
jbe@121
 | 
   420     }
 | 
| 
jbe@136
 | 
   421     // consume input character:
 | 
| 
jbe@121
 | 
   422     pos++;
 | 
| 
jbe@136
 | 
   423     // continue with loop:
 | 
| 
jbe@121
 | 
   424     goto json_import_loop;
 | 
| 
jbe@136
 | 
   425   // string literal:
 | 
| 
jbe@121
 | 
   426   case '"':
 | 
| 
jbe@146
 | 
   427     // consume quote character:
 | 
| 
jbe@146
 | 
   428     pos++;
 | 
| 
jbe@162
 | 
   429     // find last character in input string:
 | 
| 
jbe@162
 | 
   430     outlen = pos;
 | 
| 
jbe@162
 | 
   431     while ((c = str[outlen]) != '"') {
 | 
| 
jbe@161
 | 
   432       // consume one character:
 | 
| 
jbe@162
 | 
   433       outlen++;
 | 
| 
jbe@161
 | 
   434       // handle unexpected end of JSON document:
 | 
| 
jbe@161
 | 
   435       if (c == 0) goto json_import_unexpected_eof;
 | 
| 
jbe@161
 | 
   436       // consume one extra character when encountering an escaped quote:
 | 
| 
jbe@162
 | 
   437       else if (c == '\\' && str[outlen] == '"') outlen++;
 | 
| 
jbe@161
 | 
   438     }
 | 
| 
jbe@162
 | 
   439     // determine buffer length:
 | 
| 
jbe@162
 | 
   440     outlen -= pos;
 | 
| 
jbe@161
 | 
   441     // check if string is non empty:
 | 
| 
jbe@162
 | 
   442     if (outlen) {
 | 
| 
jbe@161
 | 
   443       // prepare buffer to decode string (with maximum possible length) and set write position to zero:
 | 
| 
jbe@162
 | 
   444       cbuf = luaL_buffinitsize(L, &luabuf, outlen);
 | 
| 
jbe@162
 | 
   445       outlen = 0;
 | 
| 
jbe@161
 | 
   446       // loop through the characters until encountering end quote:
 | 
| 
jbe@161
 | 
   447       while ((c = str[pos++]) != '"') {
 | 
| 
jbe@162
 | 
   448         // NOTE: unexpected end cannot happen anymore
 | 
| 
jbe@162
 | 
   449         if (c < 32 || c == 127) {
 | 
| 
jbe@161
 | 
   450           // do not allow ASCII control characters:
 | 
| 
jbe@161
 | 
   451           // NOTE: illegal UTF-8 sequences and extended control characters are not sanitized
 | 
| 
jbe@161
 | 
   452           //       by this parser to allow different encodings than Unicode
 | 
| 
jbe@161
 | 
   453           lua_pushnil(L);
 | 
| 
jbe@161
 | 
   454           lua_pushliteral(L, "Unexpected control character in JSON string");
 | 
| 
jbe@161
 | 
   455           return 2;
 | 
| 
jbe@161
 | 
   456         } else if (c == '\\') {
 | 
| 
jbe@161
 | 
   457           // read next char after backslash escape:
 | 
| 
jbe@161
 | 
   458           c = str[pos++];
 | 
| 
jbe@161
 | 
   459           switch (c) {
 | 
| 
jbe@161
 | 
   460           // unexpected end-of-string:
 | 
| 
jbe@161
 | 
   461           case 0:
 | 
| 
jbe@161
 | 
   462             goto json_import_unexpected_eof;
 | 
| 
jbe@161
 | 
   463           // unescaping of quotation mark, slash, and backslash:
 | 
| 
jbe@161
 | 
   464           case '"':
 | 
| 
jbe@161
 | 
   465           case '/':
 | 
| 
jbe@161
 | 
   466           case '\\':
 | 
| 
jbe@162
 | 
   467             cbuf[outlen++] = c;
 | 
| 
jbe@161
 | 
   468             break;
 | 
| 
jbe@161
 | 
   469           // unescaping of backspace:
 | 
| 
jbe@162
 | 
   470           case 'b': cbuf[outlen++] = '\b'; break;
 | 
| 
jbe@161
 | 
   471           // unescaping of form-feed:
 | 
| 
jbe@162
 | 
   472           case 'f': cbuf[outlen++] = '\f'; break;
 | 
| 
jbe@161
 | 
   473           // unescaping of new-line:
 | 
| 
jbe@162
 | 
   474           case 'n': cbuf[outlen++] = '\n'; break;
 | 
| 
jbe@161
 | 
   475           // unescaping of carriage-return:
 | 
| 
jbe@162
 | 
   476           case 'r': cbuf[outlen++] = '\r'; break;
 | 
| 
jbe@161
 | 
   477           // unescaping of tabulator:
 | 
| 
jbe@162
 | 
   478           case 't': cbuf[outlen++] = '\t'; break;
 | 
| 
jbe@161
 | 
   479           // unescaping of UTF-16 characters
 | 
| 
jbe@161
 | 
   480           case 'u':
 | 
| 
jbe@167
 | 
   481             // decode 4 hex nibbles:
 | 
| 
jbe@167
 | 
   482             json_import_readhex(codepoint);
 | 
| 
jbe@167
 | 
   483             // handle surrogate character:
 | 
| 
jbe@167
 | 
   484             if (json_utf16_surrogate(codepoint)) {
 | 
| 
jbe@167
 | 
   485               // check if first surrogate is in valid range:
 | 
| 
jbe@167
 | 
   486               if (json_utf16_lead(codepoint)) {
 | 
| 
jbe@167
 | 
   487                 // require second surrogate:
 | 
| 
jbe@167
 | 
   488                 if ((c = str[pos++]) != '\\' || (c = str[pos++]) != 'u') {
 | 
| 
jbe@167
 | 
   489                   if (c == 0) goto json_import_unexpected_eof;
 | 
| 
jbe@167
 | 
   490                   else goto json_import_wrong_surrogate;
 | 
| 
jbe@167
 | 
   491                 }
 | 
| 
jbe@167
 | 
   492                 // read 4 hex nibbles of second surrogate character:
 | 
| 
jbe@167
 | 
   493                 json_import_readhex(utf16tail);
 | 
| 
jbe@167
 | 
   494                 // check if second surrogate is in valid range:
 | 
| 
jbe@167
 | 
   495                 if (!json_utf16_tail(utf16tail)) goto json_import_wrong_surrogate;
 | 
| 
jbe@167
 | 
   496                 // calculate codepoint:
 | 
| 
jbe@167
 | 
   497                 codepoint = 0x10000 + (utf16tail - 0xDC00) + (codepoint - 0xD800) * 0x400;
 | 
| 
jbe@167
 | 
   498               } else {
 | 
| 
jbe@167
 | 
   499                 // throw error for wrong surrogates:
 | 
| 
jbe@167
 | 
   500                 json_import_wrong_surrogate:
 | 
| 
jbe@167
 | 
   501                 lua_pushnil(L);
 | 
| 
jbe@167
 | 
   502                 lua_pushliteral(L, "Illegal UTF-16 surrogate in JSON string escape sequence");
 | 
| 
jbe@167
 | 
   503                 return 2;
 | 
| 
jbe@167
 | 
   504               }
 | 
| 
jbe@167
 | 
   505             }
 | 
| 
jbe@167
 | 
   506             // encode as UTF-8:
 | 
| 
jbe@167
 | 
   507             if (codepoint < 0x80) {
 | 
| 
jbe@167
 | 
   508               cbuf[outlen++] = (char)codepoint;
 | 
| 
jbe@167
 | 
   509             } else if (codepoint < 0x800) {
 | 
| 
jbe@167
 | 
   510               cbuf[outlen++] = (char)(0xc0 | (codepoint >> 6));
 | 
| 
jbe@167
 | 
   511               cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
 | 
| 
jbe@167
 | 
   512             } else if (codepoint < 0x10000) {
 | 
| 
jbe@167
 | 
   513               cbuf[outlen++] = (char)(0xe0 | (codepoint >> 12));
 | 
| 
jbe@167
 | 
   514               cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
 | 
| 
jbe@167
 | 
   515               cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
 | 
| 
jbe@167
 | 
   516             } else {
 | 
| 
jbe@167
 | 
   517               cbuf[outlen++] = (char)(0xf0 | (codepoint >> 18));
 | 
| 
jbe@167
 | 
   518               cbuf[outlen++] = (char)(0x80 | ((codepoint >> 12) & 0x3f));
 | 
| 
jbe@167
 | 
   519               cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
 | 
| 
jbe@167
 | 
   520               cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
 | 
| 
jbe@167
 | 
   521             }
 | 
| 
jbe@167
 | 
   522             break;
 | 
| 
jbe@161
 | 
   523           // unexpected escape sequence:
 | 
| 
jbe@161
 | 
   524           default:
 | 
| 
jbe@167
 | 
   525             json_import_unexpected_escape:
 | 
| 
jbe@161
 | 
   526             lua_pushnil(L);
 | 
| 
jbe@161
 | 
   527             lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
 | 
| 
jbe@161
 | 
   528             return 2;
 | 
| 
jbe@161
 | 
   529           }
 | 
| 
jbe@161
 | 
   530         } else {
 | 
| 
jbe@161
 | 
   531           // normal character:
 | 
| 
jbe@162
 | 
   532           cbuf[outlen++] = c;
 | 
| 
jbe@121
 | 
   533         }
 | 
| 
jbe@121
 | 
   534       }
 | 
| 
jbe@161
 | 
   535       // process buffer to Lua string:
 | 
| 
jbe@162
 | 
   536       luaL_pushresultsize(&luabuf, outlen);
 | 
| 
jbe@161
 | 
   537     } else {
 | 
| 
jbe@161
 | 
   538       // if JSON string is empty,
 | 
| 
jbe@161
 | 
   539       // push empty Lua string:
 | 
| 
jbe@161
 | 
   540       lua_pushliteral(L, "");
 | 
| 
jbe@167
 | 
   541       // consume closing quote:
 | 
| 
jbe@167
 | 
   542       pos++;
 | 
| 
jbe@121
 | 
   543     }
 | 
| 
jbe@136
 | 
   544     // continue with processing of decoded string:
 | 
| 
jbe@121
 | 
   545     goto json_import_process_value;
 | 
| 
jbe@121
 | 
   546   }
 | 
| 
jbe@136
 | 
   547   // process values whose type is is not deducible from a single character:
 | 
| 
jbe@136
 | 
   548   if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
 | 
| 
jbe@427
 | 
   549     // try to parse number:
 | 
| 
jbe@167
 | 
   550     double numval;
 | 
| 
jbe@122
 | 
   551     char *endptr;
 | 
| 
jbe@427
 | 
   552     size_t endpos;
 | 
| 
jbe@427
 | 
   553     // use strtod() call to parse a (double precision) floating point number
 | 
| 
jbe@427
 | 
   554     // and to determine length of number:
 | 
| 
jbe@122
 | 
   555     numval = strtod(str+pos, &endptr);
 | 
| 
jbe@146
 | 
   556     // catch parsing errors:
 | 
| 
jbe@122
 | 
   557     if (endptr == str+pos) goto json_import_syntax_error;
 | 
| 
jbe@427
 | 
   558     // calculate end position of number:
 | 
| 
jbe@427
 | 
   559     endpos = endptr - str;
 | 
| 
jbe@427
 | 
   560 #if LUA_VERSION_NUM >= 503
 | 
| 
jbe@427
 | 
   561     // try alternative integer interpretation:
 | 
| 
jbe@427
 | 
   562     {
 | 
| 
jbe@427
 | 
   563       lua_Integer intval = 0;
 | 
| 
jbe@427
 | 
   564       size_t curpos;
 | 
| 
jbe@427
 | 
   565       if (c >= '0' && c <= '9') intval = c - '0';
 | 
| 
jbe@427
 | 
   566       for (curpos=pos+1; curpos<endpos; curpos++) {
 | 
| 
jbe@427
 | 
   567         lua_Integer d = str[curpos] - '0';
 | 
| 
jbe@427
 | 
   568         if (d < 0 || d > 9) break;
 | 
| 
jbe@427
 | 
   569         if (c == '-') {
 | 
| 
jbe@427
 | 
   570           // NOTE: rounding of negative integer division may be undefined
 | 
| 
jbe@427
 | 
   571           if (
 | 
| 
jbe@427
 | 
   572             intval == LUA_MININTEGER ||
 | 
| 
jbe@427
 | 
   573             -intval > (-(LUA_MININTEGER+10) - d) / 10 + 1
 | 
| 
jbe@427
 | 
   574           ) break;
 | 
| 
jbe@427
 | 
   575           intval = 10 * intval - d;
 | 
| 
jbe@427
 | 
   576         } else {
 | 
| 
jbe@427
 | 
   577           if (intval > (LUA_MAXINTEGER - d) / 10) break;
 | 
| 
jbe@427
 | 
   578           intval = 10 * intval + d;
 | 
| 
jbe@427
 | 
   579         }
 | 
| 
jbe@427
 | 
   580       }
 | 
| 
jbe@441
 | 
   581       // push result onto Lua stack:
 | 
| 
jbe@427
 | 
   582       if (curpos == endpos) lua_pushinteger(L, intval);
 | 
| 
jbe@427
 | 
   583       else lua_pushnumber(L, numval);
 | 
| 
jbe@427
 | 
   584     }
 | 
| 
jbe@441
 | 
   585 #else
 | 
| 
jbe@441
 | 
   586     // push result onto Lua stack:
 | 
| 
jbe@441
 | 
   587     lua_pushnumber(L, numval);
 | 
| 
jbe@427
 | 
   588 #endif
 | 
| 
jbe@146
 | 
   589     // consume characters that were parsed:
 | 
| 
jbe@427
 | 
   590     pos = endpos;
 | 
| 
jbe@122
 | 
   591   } else if (!strncmp(str+pos, "true", 4)) {
 | 
| 
jbe@136
 | 
   592     // consume 4 input characters for "true":
 | 
| 
jbe@121
 | 
   593     pos += 4;
 | 
| 
jbe@147
 | 
   594     // put Lua true value onto stack:
 | 
| 
jbe@136
 | 
   595     lua_pushboolean(L, 1);
 | 
| 
jbe@121
 | 
   596   } else if (!strncmp(str+pos, "false", 5)) {
 | 
| 
jbe@136
 | 
   597     // consume 5 input characters for "false":
 | 
| 
jbe@121
 | 
   598     pos += 5;
 | 
| 
jbe@147
 | 
   599     // put Lua false value onto stack:
 | 
| 
jbe@136
 | 
   600     lua_pushboolean(L, 0);
 | 
| 
jbe@121
 | 
   601   } else if (!strncmp(str+pos, "null", 4)) {
 | 
| 
jbe@136
 | 
   602     // consume 4 input characters for "null":
 | 
| 
jbe@136
 | 
   603     pos += 4;
 | 
| 
jbe@194
 | 
   604     // push special null-marker onto stack:
 | 
| 
jbe@194
 | 
   605     json_pushnullmark(L);
 | 
| 
jbe@121
 | 
   606   } else {
 | 
| 
jbe@136
 | 
   607     // all other cases are a syntax error:
 | 
| 
jbe@121
 | 
   608     goto json_import_syntax_error;
 | 
| 
jbe@121
 | 
   609   }
 | 
| 
jbe@136
 | 
   610   // process a decoded value or key value pair (expected on top of Lua stack):
 | 
| 
jbe@136
 | 
   611   json_import_process_value:
 | 
| 
jbe@121
 | 
   612   switch (mode) {
 | 
| 
jbe@136
 | 
   613   // an object key has been read:
 | 
| 
jbe@124
 | 
   614   case JSON_STATE_OBJECT_KEY:
 | 
| 
jbe@136
 | 
   615     // if an object key is not a string, then this is a syntax error:
 | 
| 
jbe@121
 | 
   616     if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
 | 
| 
jbe@146
 | 
   617     // expect key terminator to follow:
 | 
| 
jbe@124
 | 
   618     mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
 | 
| 
jbe@146
 | 
   619     // continue with loop:
 | 
| 
jbe@121
 | 
   620     goto json_import_loop;
 | 
| 
jbe@136
 | 
   621   // a key value pair has been read:
 | 
| 
jbe@124
 | 
   622   case JSON_STATE_OBJECT_VALUE:
 | 
| 
jbe@136
 | 
   623     // store key value pair in outer shadow table:
 | 
| 
jbe@130
 | 
   624     lua_rawset(L, -3);
 | 
| 
jbe@146
 | 
   625     // expect value terminator (or end of object) to follow:
 | 
| 
jbe@124
 | 
   626     mode = JSON_STATE_OBJECT_SEPARATOR;
 | 
| 
jbe@146
 | 
   627     // continue with loop:
 | 
| 
jbe@121
 | 
   628     goto json_import_loop;
 | 
| 
jbe@136
 | 
   629   // an array value has been read:
 | 
| 
jbe@124
 | 
   630   case JSON_STATE_ARRAY_VALUE:
 | 
| 
jbe@152
 | 
   631     // get current array length:
 | 
| 
jbe@152
 | 
   632     arraylen = lua_rawlen(L, -3);
 | 
| 
jbe@427
 | 
   633     // throw error if array would exceed INT_MAX-1 elements:
 | 
| 
jbe@427
 | 
   634     // NOTE: Lua 5.3 may support more elements, but C libraries may not
 | 
| 
jbe@427
 | 
   635     if (arraylen > INT_MAX-1) {
 | 
| 
jbe@152
 | 
   636       lua_pushnil(L);
 | 
| 
jbe@427
 | 
   637       lua_pushfstring(L, "Array exceeded length of %d elements", INT_MAX-1);
 | 
| 
jbe@152
 | 
   638     }
 | 
| 
jbe@136
 | 
   639     // store value in outer shadow table:
 | 
| 
jbe@152
 | 
   640     lua_rawseti(L, -3, arraylen + 1);
 | 
| 
jbe@146
 | 
   641     // expect value terminator (or end of object) to follow:
 | 
| 
jbe@124
 | 
   642     mode = JSON_STATE_ARRAY_SEPARATOR;
 | 
| 
jbe@146
 | 
   643     // continue with loop
 | 
| 
jbe@121
 | 
   644     goto json_import_loop;
 | 
| 
jbe@136
 | 
   645   // a single value has been read:
 | 
| 
jbe@124
 | 
   646   case JSON_STATE_VALUE:
 | 
| 
jbe@136
 | 
   647     // leave value on top of stack, expect end of JSON document, and continue with loop:
 | 
| 
jbe@124
 | 
   648     mode = JSON_STATE_END;
 | 
| 
jbe@121
 | 
   649     goto json_import_loop;
 | 
| 
jbe@121
 | 
   650   }
 | 
| 
jbe@146
 | 
   651   // syntax error handling (reachable by goto statement):
 | 
| 
jbe@136
 | 
   652   json_import_syntax_error:
 | 
| 
jbe@121
 | 
   653   lua_pushnil(L);
 | 
| 
jbe@121
 | 
   654   lua_pushliteral(L, "Syntax error in JSON document");
 | 
| 
jbe@121
 | 
   655   return 2;
 | 
| 
jbe@121
 | 
   656 }
 | 
| 
jbe@121
 | 
   657 
 | 
| 
jbe@146
 | 
   658 // gets a value or its type from a JSON document (passed as first argument)
 | 
| 
jbe@175
 | 
   659 // using a path (passed as variable number of keys after the first argument):
 | 
| 
jbe@137
 | 
   660 static int json_path(lua_State *L, int type_mode) {
 | 
| 
jbe@193
 | 
   661   int stacktop;  // number of arguments
 | 
| 
jbe@193
 | 
   662   int idx = 2;   // stack index of current argument to process
 | 
| 
jbe@173
 | 
   663   // require at least one argument:
 | 
| 
jbe@173
 | 
   664   luaL_checkany(L, 1);
 | 
| 
jbe@193
 | 
   665   // store stack index of top of stack (number of arguments):
 | 
| 
jbe@138
 | 
   666   stacktop = lua_gettop(L);
 | 
| 
jbe@146
 | 
   667   // use first argument as "current value" (stored on top of stack):
 | 
| 
jbe@193
 | 
   668   lua_pushvalue(L, 1);
 | 
| 
jbe@146
 | 
   669   // process each "path key" (2nd argument and following arguments):
 | 
| 
jbe@138
 | 
   670   while (idx <= stacktop) {
 | 
| 
jbe@146
 | 
   671     // if "current value" (on top of stack) is nil, then the path cannot be walked and nil is returned:
 | 
| 
jbe@137
 | 
   672     if (lua_isnil(L, -1)) return 1;
 | 
| 
jbe@137
 | 
   673     // try to get shadow table of "current value":
 | 
| 
jbe@193
 | 
   674     json_getshadow(L, -1);
 | 
| 
jbe@126
 | 
   675     if (lua_isnil(L, -1)) {
 | 
| 
jbe@137
 | 
   676       // if no shadow table is found,
 | 
| 
jbe@193
 | 
   677       if (lua_type(L, -2) == LUA_TTABLE) {
 | 
| 
jbe@146
 | 
   678         // and if "current value" is a table,
 | 
| 
jbe@193
 | 
   679         // pop nil from stack:
 | 
| 
jbe@146
 | 
   680         lua_pop(L, 1);
 | 
| 
jbe@137
 | 
   681         // get "next value" using the "path key":
 | 
| 
jbe@130
 | 
   682         lua_pushvalue(L, idx++);
 | 
| 
jbe@130
 | 
   683         lua_gettable(L, -2);
 | 
| 
jbe@130
 | 
   684       } else {
 | 
| 
jbe@137
 | 
   685         // if "current value" is not a table,
 | 
| 
jbe@146
 | 
   686         // then the path cannot be walked and nil (already on top of stack) is returned:
 | 
| 
jbe@137
 | 
   687         return 1;
 | 
| 
jbe@130
 | 
   688       }
 | 
| 
jbe@130
 | 
   689     } else {
 | 
| 
jbe@137
 | 
   690       // if a shadow table is found,
 | 
| 
jbe@137
 | 
   691       // set "current value" to its shadow table:
 | 
| 
jbe@130
 | 
   692       lua_replace(L, -2);
 | 
| 
jbe@137
 | 
   693       // get "next value" using the "path key":
 | 
| 
jbe@130
 | 
   694       lua_pushvalue(L, idx++);
 | 
| 
jbe@130
 | 
   695       lua_rawget(L, -2);
 | 
| 
jbe@126
 | 
   696     }
 | 
| 
jbe@137
 | 
   697     // the "next value" replaces the "current value":
 | 
| 
jbe@130
 | 
   698     lua_replace(L, -2);
 | 
| 
jbe@126
 | 
   699   }
 | 
| 
jbe@137
 | 
   700   if (!type_mode) {
 | 
| 
jbe@137
 | 
   701     // if a value (and not its type) was requested,
 | 
| 
jbe@137
 | 
   702     // check if value is the null-marker, and store nil on top of Lua stack in that case:
 | 
| 
jbe@155
 | 
   703     if (json_isnullmark(L, -1)) lua_pushnil(L);
 | 
| 
jbe@137
 | 
   704   } else {
 | 
| 
jbe@137
 | 
   705     // if the type was requested,
 | 
| 
jbe@137
 | 
   706     // check if value is the null-marker:
 | 
| 
jbe@155
 | 
   707     if (json_isnullmark(L, -1)) {
 | 
| 
jbe@137
 | 
   708       // if yes, store string "null" on top of Lua stack:
 | 
| 
jbe@130
 | 
   709       lua_pushliteral(L, "null");
 | 
| 
jbe@137
 | 
   710     } else {
 | 
| 
jbe@137
 | 
   711       // otherwise,
 | 
| 
jbe@138
 | 
   712       // check if metatable indicates "object" or "array":
 | 
| 
jbe@138
 | 
   713       if (lua_getmetatable(L, -1)) {
 | 
| 
jbe@144
 | 
   714         json_regfetch(L, objectmt);
 | 
| 
jbe@138
 | 
   715         if (lua_rawequal(L, -2, -1)) {
 | 
| 
jbe@146
 | 
   716           // if value has metatable for JSON objects,
 | 
| 
jbe@138
 | 
   717           // return string "object":
 | 
| 
jbe@138
 | 
   718           lua_pushliteral(L, "object");
 | 
| 
jbe@138
 | 
   719           return 1;
 | 
| 
jbe@138
 | 
   720         }
 | 
| 
jbe@144
 | 
   721         json_regfetch(L, arraymt);
 | 
| 
jbe@138
 | 
   722         if (lua_rawequal(L, -3, -1)) {
 | 
| 
jbe@146
 | 
   723           // if value has metatable for JSON arrays,
 | 
| 
jbe@146
 | 
   724           // return string "object":
 | 
| 
jbe@138
 | 
   725           lua_pushliteral(L, "array");
 | 
| 
jbe@138
 | 
   726           return 1;
 | 
| 
jbe@138
 | 
   727         }
 | 
| 
jbe@146
 | 
   728         // remove 3 metatables (one of the value, two for comparison) from stack:
 | 
| 
jbe@138
 | 
   729         lua_pop(L, 3);
 | 
| 
jbe@138
 | 
   730       }
 | 
| 
jbe@138
 | 
   731       // otherwise, get the Lua type:
 | 
| 
jbe@138
 | 
   732       lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
 | 
| 
jbe@126
 | 
   733     }
 | 
| 
jbe@126
 | 
   734   }
 | 
| 
jbe@137
 | 
   735   // return the top most value on the Lua stack:
 | 
| 
jbe@137
 | 
   736   return 1;
 | 
| 
jbe@130
 | 
   737 }
 | 
| 
jbe@130
 | 
   738 
 | 
| 
jbe@147
 | 
   739 // gets a value from a JSON document (passed as first argument)
 | 
| 
jbe@175
 | 
   740 // using a path (passed as variable number of keys after the first argument):
 | 
| 
jbe@130
 | 
   741 static int json_get(lua_State *L) {
 | 
| 
jbe@137
 | 
   742   return json_path(L, 0);
 | 
| 
jbe@130
 | 
   743 }
 | 
| 
jbe@130
 | 
   744 
 | 
| 
jbe@147
 | 
   745 // gets a value's type from a JSON document (passed as first argument)
 | 
| 
jbe@175
 | 
   746 // using a path (passed as variable number of keys after first the argument):
 | 
| 
jbe@130
 | 
   747 static int json_type(lua_State *L) {
 | 
| 
jbe@137
 | 
   748   return json_path(L, 1);
 | 
| 
jbe@130
 | 
   749 }
 | 
| 
jbe@130
 | 
   750 
 | 
| 
jbe@173
 | 
   751 // special Lua stack indicies for json_set function:
 | 
| 
jbe@193
 | 
   752 #define json_set_objectmt_idx 1
 | 
| 
jbe@193
 | 
   753 #define json_set_arraymt_idx 2
 | 
| 
jbe@173
 | 
   754 
 | 
| 
jbe@173
 | 
   755 // stack offset of arguments to json_set function:
 | 
| 
jbe@193
 | 
   756 #define json_set_idxshift 2
 | 
| 
jbe@173
 | 
   757 
 | 
| 
jbe@173
 | 
   758 // sets a value (passed as second argument) in a JSON document (passed as first argument)
 | 
| 
jbe@175
 | 
   759 // using a path (passed as variable number of keys starting at third argument):
 | 
| 
jbe@173
 | 
   760 static int json_set(lua_State *L) {
 | 
| 
jbe@193
 | 
   761   int stacktop;  // stack index of top of stack (after shifting)
 | 
| 
jbe@193
 | 
   762   int idx;       // stack index of current argument to process
 | 
| 
jbe@199
 | 
   763   // require at least three arguments:
 | 
| 
jbe@173
 | 
   764   luaL_checkany(L, 1);
 | 
| 
jbe@173
 | 
   765   luaL_checkany(L, 2);
 | 
| 
jbe@199
 | 
   766   luaL_checkany(L, 3);
 | 
| 
jbe@193
 | 
   767   // insert objectmt into stack at position 1 (shifting the arguments):
 | 
| 
jbe@173
 | 
   768   json_regfetch(L, objectmt);
 | 
| 
jbe@193
 | 
   769   lua_insert(L, 1);
 | 
| 
jbe@193
 | 
   770   // insert arraymt into stack at position 2 (shifting the arguments):
 | 
| 
jbe@193
 | 
   771   json_regfetch(L, arraymt);
 | 
| 
jbe@173
 | 
   772   lua_insert(L, 2);
 | 
| 
jbe@173
 | 
   773   // store stack index of top of stack:
 | 
| 
jbe@173
 | 
   774   stacktop = lua_gettop(L);
 | 
| 
jbe@173
 | 
   775   // use nil as initial "parent value":
 | 
| 
jbe@173
 | 
   776   lua_pushnil(L);
 | 
| 
jbe@173
 | 
   777   // use first argument as "current value":
 | 
| 
jbe@173
 | 
   778   lua_pushvalue(L, 1 + json_set_idxshift);
 | 
| 
jbe@173
 | 
   779   // set all necessary values in path:
 | 
| 
jbe@173
 | 
   780   for (idx = 3 + json_set_idxshift; idx<=stacktop; idx++) {
 | 
| 
jbe@173
 | 
   781     // push metatable of "current value" onto stack:
 | 
| 
jbe@173
 | 
   782     if (!lua_getmetatable(L, -1)) lua_pushnil(L);
 | 
| 
jbe@173
 | 
   783     // distinguish according to type of path key:
 | 
| 
jbe@173
 | 
   784     switch (lua_type(L, idx)) {
 | 
| 
jbe@173
 | 
   785     case LUA_TSTRING:
 | 
| 
jbe@173
 | 
   786       // if path key is a string,
 | 
| 
jbe@173
 | 
   787       // check if "current value" is a JSON object (or table without metatable):
 | 
| 
jbe@173
 | 
   788       if (
 | 
| 
jbe@173
 | 
   789         lua_rawequal(L, -1, json_set_objectmt_idx) ||
 | 
| 
jbe@173
 | 
   790         (lua_isnil(L, -1) && lua_type(L, -2) == LUA_TTABLE)
 | 
| 
jbe@173
 | 
   791       ) {
 | 
| 
jbe@173
 | 
   792         // if "current value" is acceptable,
 | 
| 
jbe@173
 | 
   793         // pop metatable and leave "current value" on top of stack:
 | 
| 
jbe@173
 | 
   794         lua_pop(L, 1);
 | 
| 
jbe@173
 | 
   795       } else {
 | 
| 
jbe@173
 | 
   796         // if "current value" is not acceptable:
 | 
| 
jbe@173
 | 
   797         // pop metatable and "current value":
 | 
| 
jbe@173
 | 
   798         lua_pop(L, 2);
 | 
| 
jbe@173
 | 
   799         // throw error if parent element does not exist:
 | 
| 
jbe@173
 | 
   800         if (lua_isnil(L, -1)) return luaL_error(L, "Root element is not a JSON object");
 | 
| 
jbe@173
 | 
   801         // push new JSON object as "current value" onto stack:
 | 
| 
jbe@193
 | 
   802         json_createproxy(L);
 | 
| 
jbe@173
 | 
   803         // create and register shadow table:
 | 
| 
jbe@173
 | 
   804         lua_newtable(L);
 | 
| 
jbe@193
 | 
   805         json_setshadow(L, -2);
 | 
| 
jbe@173
 | 
   806         // set metatable of JSON object: 
 | 
| 
jbe@173
 | 
   807         lua_pushvalue(L, json_set_objectmt_idx);
 | 
| 
jbe@173
 | 
   808         lua_setmetatable(L, -2);
 | 
| 
jbe@173
 | 
   809         // set entry in "parent value":
 | 
| 
jbe@173
 | 
   810         lua_pushvalue(L, idx-1);
 | 
| 
jbe@173
 | 
   811         lua_pushvalue(L, -2);
 | 
| 
jbe@173
 | 
   812         lua_settable(L, -4);
 | 
| 
jbe@173
 | 
   813       }
 | 
| 
jbe@173
 | 
   814       break;
 | 
| 
jbe@173
 | 
   815     case LUA_TNUMBER:
 | 
| 
jbe@173
 | 
   816       // if path key is a number,
 | 
| 
jbe@173
 | 
   817       // check if "current value" is a JSON array (or table without metatable):
 | 
| 
jbe@173
 | 
   818       if (
 | 
| 
jbe@173
 | 
   819         lua_rawequal(L, -1, json_set_arraymt_idx) ||
 | 
| 
jbe@173
 | 
   820         (lua_isnil(L, -1) && lua_type(L, -2) == LUA_TTABLE)
 | 
| 
jbe@173
 | 
   821       ) {
 | 
| 
jbe@173
 | 
   822         // if "current value" is acceptable,
 | 
| 
jbe@173
 | 
   823         // pop metatable and leave "current value" on top of stack:
 | 
| 
jbe@173
 | 
   824         lua_pop(L, 1);
 | 
| 
jbe@173
 | 
   825       } else {
 | 
| 
jbe@173
 | 
   826         // if "current value" is not acceptable:
 | 
| 
jbe@173
 | 
   827         // pop metatable and "current value":
 | 
| 
jbe@173
 | 
   828         lua_pop(L, 2);
 | 
| 
jbe@173
 | 
   829         // throw error if parent element does not exist:
 | 
| 
jbe@173
 | 
   830         if (lua_isnil(L, -1)) return luaL_error(L, "Root element is not a JSON array");
 | 
| 
jbe@173
 | 
   831         // push new JSON array as "current value" onto stack:
 | 
| 
jbe@193
 | 
   832         json_createproxy(L);
 | 
| 
jbe@173
 | 
   833         // create and register shadow table:
 | 
| 
jbe@173
 | 
   834         lua_newtable(L);
 | 
| 
jbe@193
 | 
   835         json_setshadow(L, -2);
 | 
| 
jbe@173
 | 
   836         // set metatable of JSON array: 
 | 
| 
jbe@173
 | 
   837         lua_pushvalue(L, json_set_arraymt_idx);
 | 
| 
jbe@173
 | 
   838         lua_setmetatable(L, -2);
 | 
| 
jbe@173
 | 
   839         // set entry in "parent value":
 | 
| 
jbe@173
 | 
   840         lua_pushvalue(L, idx-1);
 | 
| 
jbe@173
 | 
   841         lua_pushvalue(L, -2);
 | 
| 
jbe@173
 | 
   842         lua_settable(L, -4);
 | 
| 
jbe@173
 | 
   843       }
 | 
| 
jbe@173
 | 
   844       break;
 | 
| 
jbe@173
 | 
   845     default:
 | 
| 
jbe@173
 | 
   846       return luaL_error(L, "Invalid path key of type %s", lua_typename(L, lua_type(L, idx)));
 | 
| 
jbe@173
 | 
   847     }
 | 
| 
jbe@173
 | 
   848     // check if last path element is being processed:
 | 
| 
jbe@173
 | 
   849     if (idx == stacktop) {
 | 
| 
jbe@173
 | 
   850       // if the last path element is being processed,
 | 
| 
jbe@173
 | 
   851       // set last path value in "current value" container:
 | 
| 
jbe@173
 | 
   852       lua_pushvalue(L, idx);
 | 
| 
jbe@173
 | 
   853       lua_pushvalue(L, 2 + json_set_idxshift);
 | 
| 
jbe@173
 | 
   854       lua_settable(L, -3);
 | 
| 
jbe@173
 | 
   855     } else {
 | 
| 
jbe@173
 | 
   856       // if the processed path element is not the last,
 | 
| 
jbe@173
 | 
   857       // use old "current value" as new "parent value"
 | 
| 
jbe@173
 | 
   858       lua_remove(L, -2);
 | 
| 
jbe@173
 | 
   859       // push new "current value" onto stack by performing a lookup:
 | 
| 
jbe@173
 | 
   860       lua_pushvalue(L, idx);
 | 
| 
jbe@173
 | 
   861       lua_gettable(L, -2);
 | 
| 
jbe@173
 | 
   862     }
 | 
| 
jbe@173
 | 
   863   }
 | 
| 
jbe@173
 | 
   864   // return first argument for convenience:
 | 
| 
jbe@173
 | 
   865   lua_settop(L, 1 + json_set_idxshift);
 | 
| 
jbe@173
 | 
   866   return 1;
 | 
| 
jbe@173
 | 
   867 }
 | 
| 
jbe@173
 | 
   868 
 | 
| 
jbe@147
 | 
   869 // returns the length of a JSON array (or zero for a table without numeric keys):
 | 
| 
jbe@130
 | 
   870 static int json_len(lua_State *L) {
 | 
| 
jbe@201
 | 
   871   // require table as first argument:
 | 
| 
jbe@201
 | 
   872   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@147
 | 
   873   // stack shall contain one function argument:
 | 
| 
jbe@130
 | 
   874   lua_settop(L, 1);
 | 
| 
jbe@193
 | 
   875   // push shadow table or nil onto stack:
 | 
| 
jbe@193
 | 
   876   json_getshadow(L, 1);
 | 
| 
jbe@193
 | 
   877   // pop nil from stack if no shadow table has been found:
 | 
| 
jbe@193
 | 
   878   if (lua_isnil(L, -1)) lua_pop(L, 1);
 | 
| 
jbe@193
 | 
   879   // return length of argument or shadow table:
 | 
| 
jbe@463
 | 
   880 #if LUA_VERSION_NUM >= 503
 | 
| 
jbe@463
 | 
   881   lua_pushinteger(L, lua_rawlen(L, -1));
 | 
| 
jbe@463
 | 
   882 #else
 | 
| 
jbe@193
 | 
   883   lua_pushnumber(L, lua_rawlen(L, -1));
 | 
| 
jbe@463
 | 
   884 #endif
 | 
| 
jbe@123
 | 
   885   return 1;
 | 
| 
jbe@123
 | 
   886 }
 | 
| 
jbe@123
 | 
   887 
 | 
| 
jbe@175
 | 
   888 // __index metamethod for JSON objects and JSON arrays:
 | 
| 
jbe@130
 | 
   889 static int json_index(lua_State *L) {
 | 
| 
jbe@201
 | 
   890   // require table as first argument:
 | 
| 
jbe@201
 | 
   891   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@148
 | 
   892   // stack shall contain two function arguments:
 | 
| 
jbe@130
 | 
   893   lua_settop(L, 2);
 | 
| 
jbe@193
 | 
   894   // replace first argument with its shadow table
 | 
| 
jbe@193
 | 
   895   // or throw error if no shadow table is found:
 | 
| 
jbe@193
 | 
   896   json_getshadow(L, 1);
 | 
| 
jbe@139
 | 
   897   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
 | 
| 
jbe@193
 | 
   898   lua_replace(L, 1);
 | 
| 
jbe@148
 | 
   899   // use key passed as second argument to lookup value in shadow table:
 | 
| 
jbe@193
 | 
   900   lua_rawget(L, 1);
 | 
| 
jbe@148
 | 
   901   // if value is null-marker, then push nil onto stack:
 | 
| 
jbe@193
 | 
   902   if (json_isnullmark(L, 2)) lua_pushnil(L);
 | 
| 
jbe@148
 | 
   903   // return either looked up value, or nil
 | 
| 
jbe@127
 | 
   904   return 1;
 | 
| 
jbe@127
 | 
   905 }
 | 
| 
jbe@127
 | 
   906 
 | 
| 
jbe@175
 | 
   907 // __newindex metamethod for JSON objects and JSON arrays:
 | 
| 
jbe@130
 | 
   908 static int json_newindex(lua_State *L) {
 | 
| 
jbe@201
 | 
   909   // require table as first argument
 | 
| 
jbe@201
 | 
   910   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@148
 | 
   911   // stack shall contain three function arguments:
 | 
| 
jbe@130
 | 
   912   lua_settop(L, 3);
 | 
| 
jbe@193
 | 
   913   // replace first argument with its shadow table
 | 
| 
jbe@193
 | 
   914   // or throw error if no shadow table is found:
 | 
| 
jbe@193
 | 
   915   json_getshadow(L, 1);
 | 
| 
jbe@130
 | 
   916   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
 | 
| 
jbe@130
 | 
   917   lua_replace(L, 1);
 | 
| 
jbe@193
 | 
   918   // second and third argument to write to shadow table:
 | 
| 
jbe@130
 | 
   919   lua_rawset(L, 1);
 | 
| 
jbe@148
 | 
   920   // return nothing:
 | 
| 
jbe@148
 | 
   921   return 0;
 | 
| 
jbe@121
 | 
   922 }
 | 
| 
jbe@121
 | 
   923 
 | 
| 
jbe@175
 | 
   924 // function returned as first value by json_pairs function:
 | 
| 
jbe@135
 | 
   925 static int json_pairs_iterfunc(lua_State *L) {
 | 
| 
jbe@201
 | 
   926   // require table as first argument
 | 
| 
jbe@201
 | 
   927   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@149
 | 
   928   // stack shall contain two function arguments:
 | 
| 
jbe@135
 | 
   929   lua_settop(L, 2);
 | 
| 
jbe@200
 | 
   930   // get next key value pair from shadow table (argument 1) using previous key (argument 2)
 | 
| 
jbe@149
 | 
   931   // and return nothing if there is no next pair:
 | 
| 
jbe@193
 | 
   932   if (!lua_next(L, 1)) return 0;
 | 
| 
jbe@149
 | 
   933   // replace null-marker with nil:
 | 
| 
jbe@155
 | 
   934   if (json_isnullmark(L, -1)) {
 | 
| 
jbe@135
 | 
   935     lua_pop(L, 1);
 | 
| 
jbe@135
 | 
   936     lua_pushnil(L);
 | 
| 
jbe@135
 | 
   937   }
 | 
| 
jbe@149
 | 
   938   // return key and value (or key and nil, if null-marker was found):
 | 
| 
jbe@135
 | 
   939   return 2;
 | 
| 
jbe@135
 | 
   940 }
 | 
| 
jbe@135
 | 
   941 
 | 
| 
jbe@149
 | 
   942 // returns a triple such that 'for key, value in pairs(obj) do ... end'
 | 
| 
jbe@175
 | 
   943 // iterates through all key value pairs (including JSON null values represented as Lua nil):
 | 
| 
jbe@135
 | 
   944 static int json_pairs(lua_State *L) {
 | 
| 
jbe@201
 | 
   945   // require table as first argument
 | 
| 
jbe@201
 | 
   946   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@200
 | 
   947   // return triple of function json_pairs_iterfunc, shadow table of first argument, and nil:
 | 
| 
jbe@139
 | 
   948   lua_pushcfunction(L, json_pairs_iterfunc);
 | 
| 
jbe@200
 | 
   949   json_getshadow(L, 1);
 | 
| 
jbe@200
 | 
   950   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
 | 
| 
jbe@135
 | 
   951   lua_pushnil(L);
 | 
| 
jbe@135
 | 
   952   return 3;
 | 
| 
jbe@135
 | 
   953 }
 | 
| 
jbe@135
 | 
   954 
 | 
| 
jbe@175
 | 
   955 // function returned as first value by json_ipairs function:
 | 
| 
jbe@134
 | 
   956 static int json_ipairs_iterfunc(lua_State *L) {
 | 
| 
jbe@152
 | 
   957   lua_Integer idx;
 | 
| 
jbe@201
 | 
   958   // require table as first argument
 | 
| 
jbe@201
 | 
   959   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@149
 | 
   960   // stack shall contain two function arguments:
 | 
| 
jbe@134
 | 
   961   lua_settop(L, 2);
 | 
| 
jbe@149
 | 
   962   // calculate new index by incrementing second argument:
 | 
| 
jbe@134
 | 
   963   idx = lua_tointeger(L, 2) + 1;
 | 
| 
jbe@200
 | 
   964   // do integer lookup in shadow table and store result on stack position 3:
 | 
| 
jbe@200
 | 
   965   lua_rawgeti(L, 1, idx);
 | 
| 
jbe@149
 | 
   966   // return nothing if there was no value:
 | 
| 
jbe@200
 | 
   967   if (lua_isnil(L, 3)) return 0;
 | 
| 
jbe@149
 | 
   968   // return new index and
 | 
| 
jbe@149
 | 
   969   // either the looked up value if it is not equal to the null-marker
 | 
| 
jbe@149
 | 
   970   // or nil instead of null-marker:
 | 
| 
jbe@134
 | 
   971   lua_pushinteger(L, idx);
 | 
| 
jbe@200
 | 
   972   if (json_isnullmark(L, 3)) lua_pushnil(L);
 | 
| 
jbe@200
 | 
   973   else lua_pushvalue(L, 3);
 | 
| 
jbe@134
 | 
   974   return 2;
 | 
| 
jbe@134
 | 
   975 }
 | 
| 
jbe@134
 | 
   976 
 | 
| 
jbe@149
 | 
   977 // returns a triple such that 'for idx, value in ipairs(ary) do ... end'
 | 
| 
jbe@175
 | 
   978 // iterates through all values (including JSON null values represented as Lua nil):
 | 
| 
jbe@134
 | 
   979 static int json_ipairs(lua_State *L) {
 | 
| 
jbe@201
 | 
   980   // require table as first argument
 | 
| 
jbe@201
 | 
   981   luaL_checktype(L, 1, LUA_TTABLE);
 | 
| 
jbe@200
 | 
   982   // return triple of function json_ipairs_iterfunc, shadow table of first argument, and zero:
 | 
| 
jbe@139
 | 
   983   lua_pushcfunction(L, json_ipairs_iterfunc);
 | 
| 
jbe@200
 | 
   984   json_getshadow(L, 1);
 | 
| 
jbe@200
 | 
   985   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
 | 
| 
jbe@134
 | 
   986   lua_pushinteger(L, 0);
 | 
| 
jbe@134
 | 
   987   return 3;
 | 
| 
jbe@134
 | 
   988 }
 | 
| 
jbe@134
 | 
   989 
 | 
| 
jbe@175
 | 
   990 // datatype representing a table key:
 | 
| 
jbe@175
 | 
   991 // (used for sorting)
 | 
| 
jbe@163
 | 
   992 typedef struct {
 | 
| 
jbe@163
 | 
   993   size_t length;
 | 
| 
jbe@163
 | 
   994   const char *data;
 | 
| 
jbe@163
 | 
   995 } json_key_t;
 | 
| 
jbe@163
 | 
   996 
 | 
| 
jbe@175
 | 
   997 // comparation function for table keys to be passed to qsort function:
 | 
| 
jbe@163
 | 
   998 static int json_key_cmp(json_key_t *key1, json_key_t *key2) {
 | 
| 
jbe@163
 | 
   999   size_t pos = 0;
 | 
| 
jbe@163
 | 
  1000   unsigned char c1, c2;
 | 
| 
jbe@163
 | 
  1001   while (1) {
 | 
| 
jbe@163
 | 
  1002     if (key1->length > pos) {
 | 
| 
jbe@163
 | 
  1003       if (key2->length > pos) {
 | 
| 
jbe@163
 | 
  1004         c1 = key1->data[pos];
 | 
| 
jbe@163
 | 
  1005         c2 = key2->data[pos];
 | 
| 
jbe@163
 | 
  1006         if (c1 < c2) return -1;
 | 
| 
jbe@163
 | 
  1007         else if (c1 > c2) return 1;
 | 
| 
jbe@163
 | 
  1008       } else {
 | 
| 
jbe@163
 | 
  1009         return 1;
 | 
| 
jbe@163
 | 
  1010       }
 | 
| 
jbe@163
 | 
  1011     } else {
 | 
| 
jbe@163
 | 
  1012       if (key2->length > pos) {
 | 
| 
jbe@163
 | 
  1013         return -1;
 | 
| 
jbe@163
 | 
  1014       } else {
 | 
| 
jbe@163
 | 
  1015         return 0;
 | 
| 
jbe@163
 | 
  1016       }
 | 
| 
jbe@163
 | 
  1017     }
 | 
| 
jbe@163
 | 
  1018     pos++;
 | 
| 
jbe@163
 | 
  1019   }
 | 
| 
jbe@163
 | 
  1020 }
 | 
| 
jbe@163
 | 
  1021 
 | 
| 
jbe@175
 | 
  1022 // constants for type detection of ambiguous tables:
 | 
| 
jbe@154
 | 
  1023 #define JSON_TABLETYPE_UNKNOWN 0
 | 
| 
jbe@154
 | 
  1024 #define JSON_TABLETYPE_OBJECT 1
 | 
| 
jbe@154
 | 
  1025 #define JSON_TABLETYPE_ARRAY 2
 | 
| 
jbe@154
 | 
  1026 
 | 
| 
jbe@183
 | 
  1027 typedef struct {
 | 
| 
jbe@183
 | 
  1028   int type;
 | 
| 
jbe@183
 | 
  1029   int pos;
 | 
| 
jbe@183
 | 
  1030   int count;
 | 
| 
jbe@183
 | 
  1031   json_key_t keys[1];  // or more
 | 
| 
jbe@183
 | 
  1032 } json_container_t;
 | 
| 
jbe@183
 | 
  1033 
 | 
| 
jbe@183
 | 
  1034 // special Lua stack indicies for json_export function:
 | 
| 
jbe@183
 | 
  1035 #define json_export_value_idx 1
 | 
| 
jbe@183
 | 
  1036 #define json_export_indentstring_idx 2
 | 
| 
jbe@183
 | 
  1037 #define json_export_objectmt_idx 3
 | 
| 
jbe@183
 | 
  1038 #define json_export_arraymt_idx 4
 | 
| 
jbe@193
 | 
  1039 #define json_export_stackswap_idx 5
 | 
| 
jbe@193
 | 
  1040 #define json_export_luacontainer_idx 6
 | 
| 
jbe@193
 | 
  1041 #define json_export_ccontainer_idx 7
 | 
| 
jbe@193
 | 
  1042 #define json_export_buffer_idx 8
 | 
| 
jbe@164
 | 
  1043 
 | 
| 
jbe@183
 | 
  1044 // encodes a JSON document (passed as first argument)
 | 
| 
jbe@187
 | 
  1045 // optionally using indentation (indentation string or true passed as second argument)
 | 
| 
jbe@183
 | 
  1046 static int json_export(lua_State *L) {
 | 
| 
jbe@183
 | 
  1047   int pretty;           // pretty printing on? (i.e. printing with indentation)
 | 
| 
jbe@183
 | 
  1048   luaL_Buffer buf;      // Lua buffer containing result string
 | 
| 
jbe@183
 | 
  1049   lua_Number num;       // number to encode
 | 
| 
jbe@428
 | 
  1050   char numstr[80];      // encoded number
 | 
| 
jbe@428
 | 
  1051                         // (21 chars needed for sign, zero, point, 17 significant digits, and NULL byte)
 | 
| 
jbe@428
 | 
  1052                         // (21 chars needed for sign, 19 digits INT64, and NULL byte)
 | 
| 
jbe@428
 | 
  1053                         // (80 chars needed for sign, 78 digits INT256, and NULL byte)
 | 
| 
jbe@428
 | 
  1054                         // (NOTE: we don't know the size of intmax_t and thus use 80)
 | 
| 
jbe@183
 | 
  1055   const char *str;      // string to encode
 | 
| 
jbe@183
 | 
  1056   size_t strlen;        // length of string to encode
 | 
| 
jbe@183
 | 
  1057   size_t strpos ;       // position in string or position of current key
 | 
| 
jbe@183
 | 
  1058   unsigned char c;      // character to encode (unsigned!)
 | 
| 
jbe@183
 | 
  1059   char hexcode[7];      // store for unicode hex escape sequence
 | 
| 
jbe@183
 | 
  1060                         // NOTE: 7 bytes due to backslash, character 'u', 4 hex digits, and terminating NULL byte
 | 
| 
jbe@183
 | 
  1061   int tabletype;        // table type: unknown, JSON object, or JSON array
 | 
| 
jbe@183
 | 
  1062   size_t keycount = 0;  // number of string keys in object
 | 
| 
jbe@185
 | 
  1063   json_key_t *key;      // pointer to C structure containing a string key
 | 
| 
jbe@183
 | 
  1064   int level = 0;        // current depth level
 | 
| 
jbe@183
 | 
  1065   int i;                // iteration variable for level dependent repetitions
 | 
| 
jbe@183
 | 
  1066   int stackswapidx = 0; // elements in stack swap table
 | 
| 
jbe@183
 | 
  1067   int containerkey = 0; // temporarily set to 1, if a container key is being encoded
 | 
| 
jbe@183
 | 
  1068   json_container_t *container = NULL; // pointer to current C struct for container information
 | 
| 
jbe@183
 | 
  1069   // stack shall contain two function arguments:
 | 
| 
jbe@183
 | 
  1070   lua_settop(L, 2);
 | 
| 
jbe@188
 | 
  1071   // check if pretty printing (with indentation) is desired:
 | 
| 
jbe@188
 | 
  1072   if (lua_toboolean(L, json_export_indentstring_idx)) {
 | 
| 
jbe@188
 | 
  1073     // if yes,
 | 
| 
jbe@188
 | 
  1074     // set pretty variable to 1:
 | 
| 
jbe@188
 | 
  1075     pretty = 1;
 | 
| 
jbe@188
 | 
  1076     // check if second argument is a boolean (true):
 | 
| 
jbe@188
 | 
  1077     if (lua_isboolean(L, json_export_indentstring_idx)) {
 | 
| 
jbe@188
 | 
  1078       // if yes,
 | 
| 
jbe@188
 | 
  1079       // use default indentation if indentation argument is boolean true:
 | 
| 
jbe@188
 | 
  1080       lua_pushliteral(L, "  ");
 | 
| 
jbe@188
 | 
  1081       lua_replace(L, json_export_indentstring_idx);
 | 
| 
jbe@188
 | 
  1082     } else {
 | 
| 
jbe@188
 | 
  1083       // if no,
 | 
| 
jbe@188
 | 
  1084       // require second argument to be a string:
 | 
| 
jbe@188
 | 
  1085       luaL_checktype(L, json_export_indentstring_idx, LUA_TSTRING);
 | 
| 
jbe@188
 | 
  1086     }
 | 
| 
jbe@188
 | 
  1087   } else {
 | 
| 
jbe@188
 | 
  1088     // if no,
 | 
| 
jbe@188
 | 
  1089     // set pretty variable to 0:
 | 
| 
jbe@188
 | 
  1090     pretty = 0;
 | 
| 
jbe@157
 | 
  1091   }
 | 
| 
jbe@183
 | 
  1092   // push objectmt onto stack position 3:
 | 
| 
jbe@183
 | 
  1093   json_regfetch(L, objectmt);
 | 
| 
jbe@183
 | 
  1094   // push arraymt onto stack position 4:
 | 
| 
jbe@183
 | 
  1095   json_regfetch(L, arraymt);
 | 
| 
jbe@193
 | 
  1096   // push table for stack swapping onto stack position 5:
 | 
| 
jbe@183
 | 
  1097   lua_newtable(L);
 | 
| 
jbe@193
 | 
  1098   // create placeholders on stack positions 6 through 7:
 | 
| 
jbe@187
 | 
  1099   lua_settop(L, json_export_buffer_idx);
 | 
| 
jbe@183
 | 
  1100   // create Lua string buffer:
 | 
| 
jbe@183
 | 
  1101   luaL_buffinit(L, &buf);
 | 
| 
jbe@183
 | 
  1102   // loop:
 | 
| 
jbe@183
 | 
  1103   while (1) {
 | 
| 
jbe@183
 | 
  1104     // if value to encode is the null-marker, then treat it the same as nil:
 | 
| 
jbe@183
 | 
  1105     if (json_isnullmark(L, json_export_value_idx)) {
 | 
| 
jbe@183
 | 
  1106       lua_pushnil(L);
 | 
| 
jbe@183
 | 
  1107       lua_replace(L, json_export_value_idx);
 | 
| 
jbe@164
 | 
  1108     }
 | 
| 
jbe@183
 | 
  1109     // distinguish between different Lua types:
 | 
| 
jbe@183
 | 
  1110     switch (lua_type(L, json_export_value_idx)) {
 | 
| 
jbe@183
 | 
  1111     // value to encode is nil:
 | 
| 
jbe@183
 | 
  1112     case LUA_TNIL:
 | 
| 
jbe@183
 | 
  1113       // add string "null" to output buffer:
 | 
| 
jbe@183
 | 
  1114       luaL_addstring(&buf, "null");
 | 
| 
jbe@183
 | 
  1115       break;
 | 
| 
jbe@183
 | 
  1116     // value to encode is of type number:
 | 
| 
jbe@183
 | 
  1117     case LUA_TNUMBER:
 | 
| 
jbe@428
 | 
  1118 #if LUA_VERSION_NUM >= 503
 | 
| 
jbe@428
 | 
  1119       // handle integers:
 | 
| 
jbe@428
 | 
  1120       if (lua_isinteger(L, json_export_value_idx)) {
 | 
| 
jbe@448
 | 
  1121         snprintf(numstr, sizeof(numstr), "%ji", (intmax_t)lua_tointeger(L, json_export_value_idx));
 | 
| 
jbe@428
 | 
  1122         luaL_addstring(&buf, numstr);
 | 
| 
jbe@428
 | 
  1123         break;
 | 
| 
jbe@428
 | 
  1124       }
 | 
| 
jbe@428
 | 
  1125 #endif
 | 
| 
jbe@183
 | 
  1126       // convert value to double precision number:
 | 
| 
jbe@183
 | 
  1127       num = lua_tonumber(L, json_export_value_idx);
 | 
| 
jbe@183
 | 
  1128       // throw error if number is not-a-number:
 | 
| 
jbe@183
 | 
  1129       if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value");
 | 
| 
jbe@183
 | 
  1130       // throw error if number is positive or negative infinity:
 | 
| 
jbe@183
 | 
  1131       if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers");
 | 
| 
jbe@429
 | 
  1132       // check if float is integral:
 | 
| 
jbe@432
 | 
  1133       if ((double)trunc((double)num) == (double)num) {
 | 
| 
jbe@433
 | 
  1134         // use maximum precision:
 | 
| 
jbe@448
 | 
  1135         snprintf(numstr, sizeof(numstr), "%.17g", num);  // NOTE: e.g. 12345678901234560
 | 
| 
jbe@429
 | 
  1136       } else {
 | 
| 
jbe@429
 | 
  1137         // determine necessary precision to represent double precision floating point number:
 | 
| 
jbe@448
 | 
  1138         snprintf(numstr, sizeof(numstr), "%.15g", num);  // NOTE: e.g. 0.009 should not be 0.008999999999999999
 | 
| 
jbe@448
 | 
  1139         if (strtod(numstr, NULL) != num) snprintf(numstr, sizeof(numstr), "%.16g", num);
 | 
| 
jbe@448
 | 
  1140         if (strtod(numstr, NULL) != num) snprintf(numstr, sizeof(numstr), "%.17g", num);
 | 
| 
jbe@429
 | 
  1141       }
 | 
| 
jbe@191
 | 
  1142       // add string encoding of the number to the output buffer:
 | 
| 
jbe@189
 | 
  1143       luaL_addstring(&buf, numstr);
 | 
| 
jbe@428
 | 
  1144 #if LUA_VERSION_NUM >= 503
 | 
| 
jbe@428
 | 
  1145       // enforce trailing ".0" for floats unless exponential notation was chosen:
 | 
| 
jbe@428
 | 
  1146       {
 | 
| 
jbe@428
 | 
  1147         char *p;
 | 
| 
jbe@428
 | 
  1148         if (numstr[0] == '-' || numstr[0] == '+') p = numstr+1;
 | 
| 
jbe@428
 | 
  1149         else p = numstr;
 | 
| 
jbe@428
 | 
  1150         for (; *p; p++) if (*p < '0' || *p > '9') break;
 | 
| 
jbe@428
 | 
  1151         if (!*p) luaL_addstring(&buf, ".0");
 | 
| 
jbe@428
 | 
  1152       }
 | 
| 
jbe@428
 | 
  1153 #endif
 | 
| 
jbe@183
 | 
  1154       break;
 | 
| 
jbe@183
 | 
  1155     // value to encode is of type boolean:
 | 
| 
jbe@183
 | 
  1156     case LUA_TBOOLEAN:
 | 
| 
jbe@183
 | 
  1157       // add string "true" or "false" according to boolean value:
 | 
| 
jbe@183
 | 
  1158       luaL_addstring(&buf, lua_toboolean(L, json_export_value_idx) ? "true" : "false");
 | 
| 
jbe@183
 | 
  1159       break;
 | 
| 
jbe@183
 | 
  1160     // value to encode is of type string:
 | 
| 
jbe@183
 | 
  1161     case LUA_TSTRING:
 | 
| 
jbe@183
 | 
  1162       // add quoted and escaped string to output buffer:
 | 
| 
jbe@183
 | 
  1163       str = lua_tolstring(L, json_export_value_idx, &strlen);
 | 
| 
jbe@183
 | 
  1164       luaL_addchar(&buf, '"');
 | 
| 
jbe@183
 | 
  1165       strpos = 0;
 | 
| 
jbe@183
 | 
  1166       while (strpos < strlen) {
 | 
| 
jbe@183
 | 
  1167         c = str[strpos++];
 | 
| 
jbe@183
 | 
  1168         if (c == '"')       luaL_addstring(&buf, "\\\"");
 | 
| 
jbe@183
 | 
  1169         else if (c == '\\') luaL_addstring(&buf, "\\\\");
 | 
| 
jbe@183
 | 
  1170         else if (c == 127)  luaL_addstring(&buf, "\\u007F");
 | 
| 
jbe@183
 | 
  1171         else if (c >= 32)   luaL_addchar(&buf, c);
 | 
| 
jbe@183
 | 
  1172         else if (c == '\b') luaL_addstring(&buf, "\\b");
 | 
| 
jbe@183
 | 
  1173         else if (c == '\f') luaL_addstring(&buf, "\\f");
 | 
| 
jbe@183
 | 
  1174         else if (c == '\n') luaL_addstring(&buf, "\\n");
 | 
| 
jbe@183
 | 
  1175         else if (c == '\r') luaL_addstring(&buf, "\\r");
 | 
| 
jbe@183
 | 
  1176         else if (c == '\t') luaL_addstring(&buf, "\\t");
 | 
| 
jbe@183
 | 
  1177         else if (c == '\v') luaL_addstring(&buf, "\\v");
 | 
| 
jbe@183
 | 
  1178         else {
 | 
| 
jbe@448
 | 
  1179           snprintf(hexcode, sizeof(hexcode), "\\u%04X", c);
 | 
| 
jbe@183
 | 
  1180           luaL_addstring(&buf, hexcode);
 | 
| 
jbe@154
 | 
  1181         }
 | 
| 
jbe@154
 | 
  1182       }
 | 
| 
jbe@183
 | 
  1183       luaL_addchar(&buf, '"');
 | 
| 
jbe@183
 | 
  1184       break;
 | 
| 
jbe@183
 | 
  1185     // value to encode is of type table (this includes JSON objects and JSON arrays):
 | 
| 
jbe@183
 | 
  1186     case LUA_TTABLE:
 | 
| 
jbe@183
 | 
  1187       // use table's metatable to try to determine type of table:
 | 
| 
jbe@183
 | 
  1188       tabletype = JSON_TABLETYPE_UNKNOWN;
 | 
| 
jbe@188
 | 
  1189       if (lua_getmetatable(L, json_export_value_idx)) {
 | 
| 
jbe@183
 | 
  1190         if (lua_rawequal(L, -1, json_export_objectmt_idx)) {
 | 
| 
jbe@183
 | 
  1191           tabletype = JSON_TABLETYPE_OBJECT;
 | 
| 
jbe@183
 | 
  1192         } else {
 | 
| 
jbe@183
 | 
  1193           if (lua_rawequal(L, -1, json_export_arraymt_idx)) {
 | 
| 
jbe@183
 | 
  1194             tabletype = JSON_TABLETYPE_ARRAY;
 | 
| 
jbe@183
 | 
  1195           } else {
 | 
| 
jbe@183
 | 
  1196             return luaL_error(L, "JSON export not possible for tables with nonsupported metatable");
 | 
| 
jbe@183
 | 
  1197           }
 | 
| 
jbe@183
 | 
  1198         }
 | 
| 
jbe@183
 | 
  1199         // reset stack (pop metatable from stack):
 | 
| 
jbe@183
 | 
  1200         lua_pop(L, 1);
 | 
| 
jbe@183
 | 
  1201       }
 | 
| 
jbe@193
 | 
  1202       // replace table with its shadow table if existent:
 | 
| 
jbe@193
 | 
  1203       json_getshadow(L, json_export_value_idx);
 | 
| 
jbe@183
 | 
  1204       if (lua_isnil(L, -1)) lua_pop(L, 1);
 | 
| 
jbe@193
 | 
  1205       else lua_replace(L, json_export_value_idx); 
 | 
| 
jbe@187
 | 
  1206       // check if type of table is still undetermined
 | 
| 
jbe@187
 | 
  1207       // and optionally calculate number of string keys (keycount)
 | 
| 
jbe@187
 | 
  1208       // or set keycount to zero:
 | 
| 
jbe@186
 | 
  1209       keycount = 0;
 | 
| 
jbe@183
 | 
  1210       if (tabletype == JSON_TABLETYPE_UNKNOWN) {
 | 
| 
jbe@187
 | 
  1211         // if type of table is undetermined,
 | 
| 
jbe@187
 | 
  1212         // iterate over all keys:
 | 
| 
jbe@188
 | 
  1213         for (lua_pushnil(L); lua_next(L, json_export_value_idx); lua_pop(L, 1)) {
 | 
| 
jbe@183
 | 
  1214           switch (lua_type(L, -2)) {
 | 
| 
jbe@183
 | 
  1215           case LUA_TSTRING:
 | 
| 
jbe@183
 | 
  1216             // for string keys,
 | 
| 
jbe@183
 | 
  1217             // increase keycount (may avoid another iteration):
 | 
| 
jbe@183
 | 
  1218             keycount++;
 | 
| 
jbe@183
 | 
  1219             // if type of table was unknown, then type of table is a JSON object now:
 | 
| 
jbe@183
 | 
  1220             if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_OBJECT;
 | 
| 
jbe@183
 | 
  1221             // if type of table was a JSON array, then the type of table is ambiguous now
 | 
| 
jbe@183
 | 
  1222             // and an error is thrown:
 | 
| 
jbe@183
 | 
  1223             else if (tabletype == JSON_TABLETYPE_ARRAY) goto json_export_tabletype_error;
 | 
| 
jbe@183
 | 
  1224             break;
 | 
| 
jbe@183
 | 
  1225           case LUA_TNUMBER:
 | 
| 
jbe@183
 | 
  1226             // for numeric keys,
 | 
| 
jbe@183
 | 
  1227             // if type of table was unknown, then type of table is a JSON array now:
 | 
| 
jbe@183
 | 
  1228             if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_ARRAY;
 | 
| 
jbe@183
 | 
  1229             // if type of table was a JSON object, then the type of table is ambiguous now
 | 
| 
jbe@183
 | 
  1230             // and an error is thrown:
 | 
| 
jbe@183
 | 
  1231             else if (tabletype == JSON_TABLETYPE_OBJECT) goto json_export_tabletype_error;
 | 
| 
jbe@183
 | 
  1232             break;
 | 
| 
jbe@183
 | 
  1233           }
 | 
| 
jbe@164
 | 
  1234         }
 | 
| 
jbe@163
 | 
  1235       }
 | 
| 
jbe@183
 | 
  1236       // raise error if too many nested levels:
 | 
| 
jbe@183
 | 
  1237       if (level >= JSON_MAXDEPTH) {
 | 
| 
jbe@183
 | 
  1238         return luaL_error(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
 | 
| 
jbe@163
 | 
  1239       }
 | 
| 
jbe@183
 | 
  1240       // store previous container information (if existent) on stack swap
 | 
| 
jbe@183
 | 
  1241       // and increase level variable:
 | 
| 
jbe@183
 | 
  1242       if (level++) {
 | 
| 
jbe@183
 | 
  1243         lua_pushvalue(L, json_export_luacontainer_idx);
 | 
| 
jbe@183
 | 
  1244         lua_rawseti(L, json_export_stackswap_idx, ++stackswapidx);
 | 
| 
jbe@183
 | 
  1245         lua_pushvalue(L, json_export_ccontainer_idx);
 | 
| 
jbe@183
 | 
  1246         lua_rawseti(L, json_export_stackswap_idx, ++stackswapidx);
 | 
| 
jbe@183
 | 
  1247       }
 | 
| 
jbe@188
 | 
  1248       // use value as current container:
 | 
| 
jbe@188
 | 
  1249       lua_pushvalue(L, json_export_value_idx);
 | 
| 
jbe@188
 | 
  1250       lua_replace(L, json_export_luacontainer_idx);
 | 
| 
jbe@183
 | 
  1251       // distinguish between JSON objects and JSON arrays:
 | 
| 
jbe@183
 | 
  1252       switch (tabletype) {
 | 
| 
jbe@183
 | 
  1253       // JSON object:
 | 
| 
jbe@183
 | 
  1254       case JSON_TABLETYPE_OBJECT:
 | 
| 
jbe@183
 | 
  1255         // calculate count of string keys unless it has been calculated before:
 | 
| 
jbe@183
 | 
  1256         if (!keycount) {
 | 
| 
jbe@183
 | 
  1257           for (lua_pushnil(L); lua_next(L, json_export_luacontainer_idx); lua_pop(L, 1)) {
 | 
| 
jbe@183
 | 
  1258             if (lua_type(L, -2) == LUA_TSTRING) keycount++;
 | 
| 
jbe@164
 | 
  1259           }
 | 
| 
jbe@164
 | 
  1260         }
 | 
| 
jbe@186
 | 
  1261         // allocate memory for C structure containing string keys and container iteration state:
 | 
| 
jbe@186
 | 
  1262         container = lua_newuserdata(L, sizeof(json_container_t) + (keycount-1) * sizeof(json_key_t));
 | 
| 
jbe@187
 | 
  1263         // store reference to C structure on designated stack position:
 | 
| 
jbe@186
 | 
  1264         lua_replace(L, json_export_ccontainer_idx);
 | 
| 
jbe@186
 | 
  1265         // initialize C structure for container state:
 | 
| 
jbe@186
 | 
  1266         container->type = JSON_TABLETYPE_OBJECT;
 | 
| 
jbe@186
 | 
  1267         container->count = keycount;
 | 
| 
jbe@186
 | 
  1268         container->pos = 0;
 | 
| 
jbe@187
 | 
  1269         // check if object contains any keys:
 | 
| 
jbe@183
 | 
  1270         if (keycount) {
 | 
| 
jbe@187
 | 
  1271           // if yes,
 | 
| 
jbe@187
 | 
  1272           // copy all string keys to the C structure (and reset container->pos again):
 | 
| 
jbe@183
 | 
  1273           for (lua_pushnil(L); lua_next(L, json_export_luacontainer_idx); lua_pop(L, 1)) {
 | 
| 
jbe@183
 | 
  1274             if (lua_type(L, -2) == LUA_TSTRING) {
 | 
| 
jbe@183
 | 
  1275               json_key_t *key = &container->keys[container->pos++];
 | 
| 
jbe@183
 | 
  1276               key->data = lua_tolstring(L, -2, &key->length);
 | 
| 
jbe@183
 | 
  1277             }
 | 
| 
jbe@183
 | 
  1278           }
 | 
| 
jbe@183
 | 
  1279           container->pos = 0;
 | 
| 
jbe@183
 | 
  1280           // sort C array using quicksort:
 | 
| 
jbe@183
 | 
  1281           qsort(container->keys, keycount, sizeof(json_key_t), (void *)json_key_cmp);
 | 
| 
jbe@154
 | 
  1282         }
 | 
| 
jbe@183
 | 
  1283         // add opening bracket to output buffer:
 | 
| 
jbe@183
 | 
  1284         luaL_addchar(&buf, '{');
 | 
| 
jbe@183
 | 
  1285         break;
 | 
| 
jbe@183
 | 
  1286       // JSON array:
 | 
| 
jbe@183
 | 
  1287       case JSON_TABLETYPE_ARRAY:
 | 
| 
jbe@187
 | 
  1288         // allocate memory for C structure for container iteration state:
 | 
| 
jbe@183
 | 
  1289         container = lua_newuserdata(L, sizeof(json_container_t) - sizeof(json_key_t));
 | 
| 
jbe@187
 | 
  1290         // store reference to C structure on designated stack position:
 | 
| 
jbe@183
 | 
  1291         lua_replace(L, json_export_ccontainer_idx);
 | 
| 
jbe@187
 | 
  1292         // initialize C structure for container state:
 | 
| 
jbe@183
 | 
  1293         container->type = JSON_TABLETYPE_ARRAY;
 | 
| 
jbe@183
 | 
  1294         container->pos = 0;
 | 
| 
jbe@183
 | 
  1295         // add opening bracket to output buffer:
 | 
| 
jbe@183
 | 
  1296         luaL_addchar(&buf, '[');
 | 
| 
jbe@183
 | 
  1297         break;
 | 
| 
jbe@183
 | 
  1298       default:
 | 
| 
jbe@183
 | 
  1299         // throw error if table type is unknown:
 | 
| 
jbe@183
 | 
  1300         json_export_tabletype_error:
 | 
| 
jbe@183
 | 
  1301         return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)");
 | 
| 
jbe@183
 | 
  1302       }
 | 
| 
jbe@183
 | 
  1303       break;
 | 
| 
jbe@183
 | 
  1304     default:
 | 
| 
jbe@183
 | 
  1305     // all other datatypes are considered an error:
 | 
| 
jbe@183
 | 
  1306     return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, json_export_value_idx)));
 | 
| 
jbe@183
 | 
  1307     }
 | 
| 
jbe@187
 | 
  1308     // check if a container is being processed:
 | 
| 
jbe@183
 | 
  1309     if (container) {
 | 
| 
jbe@187
 | 
  1310       // if yes,
 | 
| 
jbe@187
 | 
  1311       // execute code for container iteration:
 | 
| 
jbe@184
 | 
  1312       json_export_container:
 | 
| 
jbe@187
 | 
  1313       // distinguish between JSON objects and JSON arrays:
 | 
| 
jbe@183
 | 
  1314       switch (container->type) {
 | 
| 
jbe@187
 | 
  1315       // JSON object:
 | 
| 
jbe@183
 | 
  1316       case JSON_TABLETYPE_OBJECT:
 | 
| 
jbe@187
 | 
  1317         // finish iteration if all string keys have been processed:
 | 
| 
jbe@185
 | 
  1318         if (container->pos == container->count) goto json_export_close;
 | 
| 
jbe@187
 | 
  1319         // check if the key has already been exported:
 | 
| 
jbe@185
 | 
  1320         if (!containerkey) {
 | 
| 
jbe@187
 | 
  1321           // if no,
 | 
| 
jbe@187
 | 
  1322           // add a comma to the output buffer if necessary:
 | 
| 
jbe@185
 | 
  1323           if (container->pos) luaL_addchar(&buf, ',');
 | 
| 
jbe@445
 | 
  1324           // push current string key on top of stack:
 | 
| 
jbe@445
 | 
  1325           key = &container->keys[container->pos];
 | 
| 
jbe@445
 | 
  1326           lua_pushlstring(L, key->data, key->length);
 | 
| 
jbe@187
 | 
  1327           // set containerkey variable to true:
 | 
| 
jbe@185
 | 
  1328           containerkey = 1;
 | 
| 
jbe@183
 | 
  1329         } else {
 | 
| 
jbe@187
 | 
  1330           // if a key has already been exported,
 | 
| 
jbe@187
 | 
  1331           // add a colon to the output buffer:
 | 
| 
jbe@185
 | 
  1332           luaL_addchar(&buf, ':');
 | 
| 
jbe@187
 | 
  1333           // add a space to the output buffer for pretty results:
 | 
| 
jbe@185
 | 
  1334           if (pretty) luaL_addchar(&buf, ' ');
 | 
| 
jbe@445
 | 
  1335           // push current string key on top of stack:
 | 
| 
jbe@445
 | 
  1336           key = &container->keys[container->pos];
 | 
| 
jbe@445
 | 
  1337           lua_pushlstring(L, key->data, key->length);
 | 
| 
jbe@187
 | 
  1338           // replace string key on top of stack with corresponding value:
 | 
| 
jbe@185
 | 
  1339           lua_rawget(L, json_export_luacontainer_idx);
 | 
| 
jbe@187
 | 
  1340           // reset containerkey variable
 | 
| 
jbe@185
 | 
  1341           containerkey = 0;
 | 
| 
jbe@187
 | 
  1342           // increase number of processed key value pairs:
 | 
| 
jbe@185
 | 
  1343           container->pos++;
 | 
| 
jbe@163
 | 
  1344         }
 | 
| 
jbe@187
 | 
  1345         // store key or value on top of stack in designated stack position:
 | 
| 
jbe@185
 | 
  1346         lua_replace(L, json_export_value_idx);
 | 
| 
jbe@183
 | 
  1347         break;
 | 
| 
jbe@187
 | 
  1348       // JSON array:
 | 
| 
jbe@183
 | 
  1349       case JSON_TABLETYPE_ARRAY:
 | 
| 
jbe@187
 | 
  1350         // store next value in designated stack position:
 | 
| 
jbe@185
 | 
  1351         lua_rawgeti(L, json_export_luacontainer_idx, container->pos+1);
 | 
| 
jbe@183
 | 
  1352         lua_replace(L, json_export_value_idx);
 | 
| 
jbe@187
 | 
  1353         // finish iteration if value is nil:
 | 
| 
jbe@185
 | 
  1354         if (lua_isnil(L, json_export_value_idx)) goto json_export_close;
 | 
| 
jbe@187
 | 
  1355         // add a comma to the output buffer if necessary:
 | 
| 
jbe@185
 | 
  1356         if (container->pos) luaL_addchar(&buf, ',');
 | 
| 
jbe@187
 | 
  1357         // increase number of processed values:
 | 
| 
jbe@185
 | 
  1358         container->pos++;
 | 
| 
jbe@183
 | 
  1359         break;
 | 
| 
jbe@187
 | 
  1360       // common code for closing JSON objects or JSON arrays:
 | 
| 
jbe@183
 | 
  1361       json_export_close:
 | 
| 
jbe@187
 | 
  1362         // decrement level variable:
 | 
| 
jbe@185
 | 
  1363         level--;
 | 
| 
jbe@187
 | 
  1364         // handle indentation for pretty results:
 | 
| 
jbe@187
 | 
  1365         if (pretty && container->pos) {
 | 
| 
jbe@187
 | 
  1366           luaL_addchar(&buf, '\n');
 | 
| 
jbe@187
 | 
  1367           for (i=0; i<level; i++) {
 | 
| 
jbe@187
 | 
  1368             lua_pushvalue(L, json_export_indentstring_idx);
 | 
| 
jbe@187
 | 
  1369             luaL_addvalue(&buf);
 | 
| 
jbe@185
 | 
  1370           }
 | 
| 
jbe@164
 | 
  1371         }
 | 
| 
jbe@187
 | 
  1372         // add closing bracket to output buffer:
 | 
| 
jbe@185
 | 
  1373         luaL_addchar(&buf, container->type == JSON_TABLETYPE_OBJECT ? '}' : ']');
 | 
| 
jbe@187
 | 
  1374         // finish export if last level has been closed:
 | 
| 
jbe@185
 | 
  1375         if (!level) goto json_export_finish;
 | 
| 
jbe@187
 | 
  1376         // otherwise,
 | 
| 
jbe@187
 | 
  1377         // recall previous container information from stack swap
 | 
| 
jbe@187
 | 
  1378         // and set C pointer to corresponding C struct:
 | 
| 
jbe@185
 | 
  1379         lua_rawgeti(L, json_export_stackswap_idx, stackswapidx--);
 | 
| 
jbe@185
 | 
  1380         lua_replace(L, json_export_ccontainer_idx);
 | 
| 
jbe@185
 | 
  1381         container = lua_touserdata(L, json_export_ccontainer_idx);
 | 
| 
jbe@185
 | 
  1382         lua_rawgeti(L, json_export_stackswap_idx, stackswapidx--);
 | 
| 
jbe@185
 | 
  1383         lua_replace(L, json_export_luacontainer_idx);
 | 
| 
jbe@187
 | 
  1384         // repeat code for container iteration:
 | 
| 
jbe@185
 | 
  1385         goto json_export_container;
 | 
| 
jbe@164
 | 
  1386       }
 | 
| 
jbe@184
 | 
  1387       // handle indentation for pretty results:
 | 
| 
jbe@185
 | 
  1388       if (pretty && (containerkey || container->type == JSON_TABLETYPE_ARRAY)) {
 | 
| 
jbe@185
 | 
  1389         luaL_addchar(&buf, '\n');
 | 
| 
jbe@185
 | 
  1390         for (i=0; i<level; i++) {
 | 
| 
jbe@185
 | 
  1391           lua_pushvalue(L, json_export_indentstring_idx);
 | 
| 
jbe@185
 | 
  1392           luaL_addvalue(&buf);
 | 
| 
jbe@164
 | 
  1393         }
 | 
| 
jbe@154
 | 
  1394       }
 | 
| 
jbe@183
 | 
  1395     } else {
 | 
| 
jbe@187
 | 
  1396       // if no container is being processed,
 | 
| 
jbe@187
 | 
  1397       // finish export:
 | 
| 
jbe@185
 | 
  1398       json_export_finish:
 | 
| 
jbe@185
 | 
  1399       // for pretty results, add final newline character if outermost container is processed:
 | 
| 
jbe@185
 | 
  1400       if (pretty) luaL_addchar(&buf, '\n');
 | 
| 
jbe@187
 | 
  1401       // create and return Lua string from buffer contents
 | 
| 
jbe@154
 | 
  1402       luaL_pushresult(&buf);
 | 
| 
jbe@154
 | 
  1403       return 1;
 | 
| 
jbe@154
 | 
  1404     }
 | 
| 
jbe@154
 | 
  1405   }
 | 
| 
jbe@164
 | 
  1406 }
 | 
| 
jbe@164
 | 
  1407 
 | 
| 
jbe@149
 | 
  1408 // functions in library module:
 | 
| 
jbe@121
 | 
  1409 static const struct luaL_Reg json_module_functions[] = {
 | 
| 
jbe@133
 | 
  1410   {"object", json_object},
 | 
| 
jbe@173
 | 
  1411   {"array",  json_array},
 | 
| 
jbe@121
 | 
  1412   {"import", json_import},
 | 
| 
jbe@154
 | 
  1413   {"export", json_export},
 | 
| 
jbe@173
 | 
  1414   {"get",    json_get},
 | 
| 
jbe@173
 | 
  1415   {"type",   json_type},
 | 
| 
jbe@173
 | 
  1416   {"set",    json_set},
 | 
| 
jbe@121
 | 
  1417   {NULL, NULL}
 | 
| 
jbe@121
 | 
  1418 };
 | 
| 
jbe@121
 | 
  1419 
 | 
| 
jbe@149
 | 
  1420 // metamethods for JSON objects, JSON arrays, and unknown JSON collections (object or array):
 | 
| 
jbe@126
 | 
  1421 static const struct luaL_Reg json_metatable_functions[] = {
 | 
| 
jbe@130
 | 
  1422   {"__len", json_len},
 | 
| 
jbe@130
 | 
  1423   {"__index", json_index},
 | 
| 
jbe@130
 | 
  1424   {"__newindex", json_newindex},
 | 
| 
jbe@135
 | 
  1425   {"__pairs", json_pairs},
 | 
| 
jbe@134
 | 
  1426   {"__ipairs", json_ipairs},
 | 
| 
jbe@160
 | 
  1427   {"__tostring", json_export},
 | 
| 
jbe@126
 | 
  1428   {NULL, NULL}
 | 
| 
jbe@126
 | 
  1429 };
 | 
| 
jbe@126
 | 
  1430 
 | 
| 
jbe@157
 | 
  1431 // metamethods for JSON null marker:
 | 
| 
jbe@157
 | 
  1432 static const struct luaL_Reg json_nullmark_metamethods[] = {
 | 
| 
jbe@157
 | 
  1433   {"__tostring", json_nullmark_tostring},
 | 
| 
jbe@157
 | 
  1434   {NULL, NULL}
 | 
| 
jbe@157
 | 
  1435 };
 | 
| 
jbe@157
 | 
  1436 
 | 
| 
jbe@149
 | 
  1437 // initializes json library:
 | 
| 
jbe@121
 | 
  1438 int luaopen_json(lua_State *L) {
 | 
| 
jbe@149
 | 
  1439   // empty stack:
 | 
| 
jbe@126
 | 
  1440   lua_settop(L, 0);
 | 
| 
jbe@149
 | 
  1441   // push library module onto stack position 1:
 | 
| 
jbe@149
 | 
  1442   lua_newtable(L);
 | 
| 
jbe@149
 | 
  1443   // register library functions:
 | 
| 
jbe@149
 | 
  1444   luaL_setfuncs(L, json_module_functions, 0);
 | 
| 
jbe@149
 | 
  1445   // create and store objectmt:
 | 
| 
jbe@138
 | 
  1446   lua_newtable(L);
 | 
| 
jbe@138
 | 
  1447   luaL_setfuncs(L, json_metatable_functions, 0);
 | 
| 
jbe@144
 | 
  1448   json_regstore(L, objectmt);
 | 
| 
jbe@149
 | 
  1449   // create and store arraymt:
 | 
| 
jbe@138
 | 
  1450   lua_newtable(L);
 | 
| 
jbe@138
 | 
  1451   luaL_setfuncs(L, json_metatable_functions, 0);
 | 
| 
jbe@144
 | 
  1452   json_regstore(L, arraymt);
 | 
| 
jbe@157
 | 
  1453   // set metatable of null marker and make it available through library module:
 | 
| 
jbe@157
 | 
  1454   json_pushnullmark(L);
 | 
| 
jbe@157
 | 
  1455   lua_newtable(L);
 | 
| 
jbe@157
 | 
  1456   luaL_setfuncs(L, json_nullmark_metamethods, 0);
 | 
| 
jbe@157
 | 
  1457   lua_setmetatable(L, -2);
 | 
| 
jbe@157
 | 
  1458   lua_setfield(L, 1, "null");
 | 
| 
jbe@157
 | 
  1459   // return library module (that's expected on top of stack):
 | 
| 
jbe@121
 | 
  1460   return 1;
 | 
| 
jbe@121
 | 
  1461 }
 |