webmcp

changeset 175:20e393d2e6e1

Completed comments and minor code cleanup in JSON library; Added emergency garbage collection for memory allocation in json.export function
author jbe
date Fri Aug 01 21:54:45 2014 +0200 (2014-08-01)
parents 070edea2a92f
children 8d7665e0d490
files libraries/json/json.c
line diff
     1.1 --- a/libraries/json/json.c	Fri Aug 01 20:29:30 2014 +0200
     1.2 +++ b/libraries/json/json.c	Fri Aug 01 21:54:45 2014 +0200
     1.3 @@ -48,7 +48,7 @@
     1.4  #define json_convert_iterfun_idx 5
     1.5  #define json_convert_itertbl_idx 6
     1.6  
     1.7 -// converts a Lua table to a  JSON object or JSON array:
     1.8 +// converts a Lua table (or any other iterable value) to a JSON object or JSON array:
     1.9  // (does never modify the argument, returns an empty object or array if argument is nil)
    1.10  static int json_convert(lua_State *L, int array) {
    1.11    int arrayidx = 0;
    1.12 @@ -100,6 +100,7 @@
    1.13        } else {
    1.14          // for an array, copy consecutive integer value pairs to shadow table:
    1.15          while (1) {
    1.16 +          // throw error if array would exceed INT_MAX elements:
    1.17            // TODO: Lua 5.3 may support more elements
    1.18            if (arrayidx == INT_MAX) {
    1.19              lua_pushnumber(L, (size_t)INT_MAX+1);
    1.20 @@ -107,9 +108,12 @@
    1.21              if (lua_isnil(L, -1)) break;
    1.22              return luaL_error(L, "Array exceeded length of %d elements", INT_MAX);
    1.23            }
    1.24 +          // get next array entry:
    1.25            arrayidx++;
    1.26            lua_rawgeti(L, json_convert_source_idx, arrayidx);
    1.27 +          // break if value is nil:
    1.28            if (lua_isnil(L, -1)) break;
    1.29 +          // store value in shadow table:
    1.30            lua_rawseti(L, json_convert_shadow_idx, arrayidx);
    1.31          }
    1.32        }
    1.33 @@ -120,21 +124,30 @@
    1.34        lua_pushvalue(L, json_convert_iterator_idx);
    1.35        lua_pushvalue(L, 1);
    1.36        lua_call(L, 1, 3);
    1.37 -      // iterate through key value pairs and store them in shadow table
    1.38 +      // iterate through key value pairs and store some of them in shadow table
    1.39        // while replacing nil values with null-marker:
    1.40        while (1) {
    1.41 +        // call iterfun function:
    1.42          lua_pushvalue(L, json_convert_iterfun_idx);
    1.43          lua_pushvalue(L, json_convert_itertbl_idx);
    1.44          lua_pushvalue(L, -3);
    1.45          lua_remove(L, -4);
    1.46          lua_call(L, 2, 2);
    1.47 +        // break iteration loop if key is nil:
    1.48          if (lua_isnil(L, -2)) break;
    1.49 +        // store key value pair only if key type is correct:
    1.50          if (lua_type(L, -2) == (array ? LUA_TNUMBER : LUA_TSTRING)) {
    1.51 +          // if key type is correct,
    1.52 +          // push key onto stack:
    1.53            lua_pushvalue(L, -2);
    1.54 +          // if value is nil, push null-marker onto stack (as value):
    1.55            if (lua_isnil(L, -2)) json_pushnullmark(L);
    1.56 +          // else push value onto stack:
    1.57            else lua_pushvalue(L, -2);
    1.58 +          // set key value pair in shadow table:
    1.59            lua_rawset(L, json_convert_shadow_idx);
    1.60          }
    1.61 +        // pop value from stack, but leave key on stack:
    1.62          lua_pop(L, 1);
    1.63        }
    1.64      }
    1.65 @@ -149,10 +162,14 @@
    1.66    return 1;
    1.67  }
    1.68  
    1.69 +// converts a Lua table (or any other iterable value) to a JSON object:
    1.70 +// (does never modify the argument, returns an empty object or array if argument is nil)
    1.71  static int json_object(lua_State *L) {
    1.72    return json_convert(L, 0);
    1.73  }
    1.74  
    1.75 +// converts a Lua table (or any other iterable value) to a JSON array:
    1.76 +// (does never modify the argument, returns an empty object or array if argument is nil)
    1.77  static int json_array(lua_State *L) {
    1.78    return json_convert(L, 1);
    1.79  }
    1.80 @@ -595,7 +612,7 @@
    1.81  #define json_path_idxshift 1
    1.82  
    1.83  // gets a value or its type from a JSON document (passed as first argument)
    1.84 -// using a path (passed as variable number of keys after first argument):
    1.85 +// using a path (passed as variable number of keys after the first argument):
    1.86  static int json_path(lua_State *L, int type_mode) {
    1.87    int stacktop;                      // stack index of top of stack (after shifting)
    1.88    int idx = 2 + json_path_idxshift;  // stack index of current argument to process
    1.89 @@ -680,13 +697,13 @@
    1.90  }
    1.91  
    1.92  // gets a value from a JSON document (passed as first argument)
    1.93 -// using a path (passed as variable number of keys after first argument):
    1.94 +// using a path (passed as variable number of keys after the first argument):
    1.95  static int json_get(lua_State *L) {
    1.96    return json_path(L, 0);
    1.97  }
    1.98  
    1.99  // gets a value's type from a JSON document (passed as first argument)
   1.100 -// using a path (variable number of keys after first argument):
   1.101 +// using a path (passed as variable number of keys after first the argument):
   1.102  static int json_type(lua_State *L) {
   1.103    return json_path(L, 1);
   1.104  }
   1.105 @@ -700,7 +717,7 @@
   1.106  #define json_set_idxshift 3
   1.107  
   1.108  // sets a value (passed as second argument) in a JSON document (passed as first argument)
   1.109 -// using a path (variable number of keys starting at third argument):
   1.110 +// using a path (passed as variable number of keys starting at third argument):
   1.111  static int json_set(lua_State *L) {
   1.112    int stacktop;   // stack index of top of stack (after shifting)
   1.113    int idx = 3;    // stack index of current argument to process
   1.114 @@ -827,6 +844,7 @@
   1.115    return 1;
   1.116  }
   1.117  
   1.118 +// __index metamethod for JSON objects and JSON arrays:
   1.119  static int json_index(lua_State *L) {
   1.120    // stack shall contain two function arguments:
   1.121    lua_settop(L, 2);
   1.122 @@ -845,6 +863,7 @@
   1.123    return 1;
   1.124  }
   1.125  
   1.126 +// __newindex metamethod for JSON objects and JSON arrays:
   1.127  static int json_newindex(lua_State *L) {
   1.128    // stack shall contain three function arguments:
   1.129    lua_settop(L, 3);
   1.130 @@ -863,6 +882,7 @@
   1.131    return 0;
   1.132  }
   1.133  
   1.134 +// function returned as first value by json_pairs function:
   1.135  static int json_pairs_iterfunc(lua_State *L) {
   1.136    // stack shall contain two function arguments:
   1.137    lua_settop(L, 2);
   1.138 @@ -886,7 +906,7 @@
   1.139  }
   1.140  
   1.141  // returns a triple such that 'for key, value in pairs(obj) do ... end'
   1.142 -// iterates through all key value pairs (including JSON null keys represented as Lua nil):
   1.143 +// iterates through all key value pairs (including JSON null values represented as Lua nil):
   1.144  static int json_pairs(lua_State *L) {
   1.145    // require one argument to function
   1.146    luaL_checkany(L, 1);
   1.147 @@ -897,6 +917,7 @@
   1.148    return 3;
   1.149  }
   1.150  
   1.151 +// function returned as first value by json_ipairs function:
   1.152  static int json_ipairs_iterfunc(lua_State *L) {
   1.153    lua_Integer idx;
   1.154    // stack shall contain two function arguments:
   1.155 @@ -923,7 +944,7 @@
   1.156  }
   1.157  
   1.158  // returns a triple such that 'for idx, value in ipairs(ary) do ... end'
   1.159 -// iterates through all values (including JSON null represented as Lua nil):
   1.160 +// iterates through all values (including JSON null values represented as Lua nil):
   1.161  static int json_ipairs(lua_State *L) {
   1.162    // require one argument to function
   1.163    luaL_checkany(L, 1);
   1.164 @@ -934,11 +955,14 @@
   1.165    return 3;
   1.166  }
   1.167  
   1.168 +// datatype representing a table key:
   1.169 +// (used for sorting)
   1.170  typedef struct {
   1.171    size_t length;
   1.172    const char *data;
   1.173  } json_key_t;
   1.174  
   1.175 +// comparation function for table keys to be passed to qsort function:
   1.176  static int json_key_cmp(json_key_t *key1, json_key_t *key2) {
   1.177    size_t pos = 0;
   1.178    unsigned char c1, c2;
   1.179 @@ -963,55 +987,74 @@
   1.180    }
   1.181  }
   1.182  
   1.183 +// constants for type detection of ambiguous tables:
   1.184  #define JSON_TABLETYPE_UNKNOWN 0
   1.185  #define JSON_TABLETYPE_OBJECT 1
   1.186  #define JSON_TABLETYPE_ARRAY 2
   1.187  
   1.188 +// special Lua stack indicies for json_export_internal function:
   1.189  #define json_export_internal_indentstring_idx 1
   1.190  #define json_export_internal_level_idx 2
   1.191  #define json_export_internal_value_idx 3
   1.192  #define json_export_internal_tmp_idx 4
   1.193  
   1.194 +// encodes a JSON document (passed as third argument)
   1.195 +// optionally using indentation (indentation string passed as first argument)
   1.196 +// for a certain depth level (passed as second argument):
   1.197  static int json_export_internal(lua_State *L) {
   1.198 -  int level;
   1.199 -  int pretty;
   1.200 -  int i;
   1.201 -  lua_Number num;
   1.202 -  const char *str;
   1.203 -  unsigned char c;
   1.204 -  size_t strlen;
   1.205 -  size_t pos = 0;
   1.206 -  luaL_Buffer buf;
   1.207 -  char hexcode[7];  // backslash, character 'u', 4 hex digits, and terminating NULL byte
   1.208 -  int tabletype = JSON_TABLETYPE_UNKNOWN;
   1.209 -  int anyelement = 0;
   1.210 -  size_t keycount = 0;
   1.211 -  size_t keypos = 0;
   1.212 -  json_key_t *keybuf = NULL;
   1.213 -  lua_Integer idx;
   1.214 +  int level;        // current depth level
   1.215 +  int pretty;       // pretty printing on? (i.e. printing with indentation)
   1.216 +  int i;            // iteration variable for level dependent repetitions:
   1.217 +  lua_Number num;   // number to encode
   1.218 +  const char *str;  // string to encode
   1.219 +  size_t strlen;    // length of string to encode
   1.220 +  unsigned char c;  // character to encode (unsigned!)
   1.221 +  size_t pos = 0;   // position in string or position of current key (initialized with zero!)
   1.222 +  luaL_Buffer buf;  // Lua buffer to create strings
   1.223 +  char hexcode[7];  // store for unicode hex escape sequence
   1.224 +                    // NOTE: 7 bytes due to backslash, character 'u', 4 hex digits, and terminating NULL byte
   1.225 +  int tabletype = JSON_TABLETYPE_UNKNOWN;  // table type: unknown, JSON object, or JSON array
   1.226 +  int anyelement = 0;         // set to 1 if at least one array element has been processed
   1.227 +  size_t keycount = 0;        // number of string keys in object
   1.228 +  json_key_t *keybuf = NULL;  // temporary buffer to store (and sort) string keys of objects
   1.229 +  lua_Integer arrayidx;       // index to iterate through arrays
   1.230 +  // stack shall contain three function arguments:
   1.231    lua_settop(L, json_export_internal_value_idx);
   1.232 +  // if value to encode is the null-marker, then treat it the same as nil:
   1.233    if (json_isnullmark(L, json_export_internal_value_idx)) {
   1.234      lua_pop(L, 1);
   1.235      lua_pushnil(L);
   1.236    }
   1.237 +  // distinguish between different Lua types:
   1.238    switch (lua_type(L, json_export_internal_value_idx)) {
   1.239 +  // value to encode is nil:
   1.240    case LUA_TNIL:
   1.241 +    // return string "null":
   1.242      lua_pushliteral(L, "null");
   1.243      return 1;
   1.244 +  // value to encode is of type number:
   1.245    case LUA_TNUMBER:
   1.246 +    // convert value to double precision number:
   1.247      num = lua_tonumber(L, json_export_internal_value_idx);
   1.248 +    // throw error if number is not-a-number:
   1.249      if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value");
   1.250 +    // throw error if number is positive or negative infinity:
   1.251      if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers");
   1.252 +    // return Lua's string encoding of the number:
   1.253      lua_tostring(L, json_export_internal_value_idx);
   1.254      return 1;
   1.255 +  // value to encode is of type boolean:
   1.256    case LUA_TBOOLEAN:
   1.257 +    // return string "true" or "false" according to boolean value:
   1.258      if (lua_toboolean(L, json_export_internal_value_idx)) {
   1.259        lua_pushliteral(L, "true");
   1.260      } else {
   1.261        lua_pushliteral(L, "false");
   1.262      }
   1.263      return 1;
   1.264 +  // value to encode is of type string:
   1.265    case LUA_TSTRING:
   1.266 +    // quote, escape and return string:
   1.267      str = lua_tolstring(L, 3, &strlen);
   1.268      luaL_buffinit(L, &buf);
   1.269      luaL_addchar(&buf, '"');
   1.270 @@ -1035,7 +1078,9 @@
   1.271      luaL_addchar(&buf, '"');
   1.272      luaL_pushresult(&buf);
   1.273      return 1;
   1.274 +  // value to encode is of type table (this includes JSON objects and JSON arrays):
   1.275    case LUA_TTABLE:
   1.276 +    // use table's metatable to try to determine type of table:
   1.277      if (lua_getmetatable(L, json_export_internal_value_idx)) {
   1.278        json_regfetch(L, objectmt);
   1.279        if (lua_rawequal(L, -2, -1)) {
   1.280 @@ -1049,54 +1094,91 @@
   1.281          }
   1.282        }
   1.283      }
   1.284 +    // replace table with its shadow table if existent, and reset stack:
   1.285      json_regfetch(L, shadowtbl);
   1.286      lua_pushvalue(L, json_export_internal_value_idx);
   1.287      lua_rawget(L, -2);
   1.288      if (!lua_isnil(L, -1)) lua_replace(L, json_export_internal_value_idx);
   1.289      lua_settop(L, json_export_internal_value_idx);
   1.290 +    // check if type of table is still undetermined:
   1.291      if (tabletype == JSON_TABLETYPE_UNKNOWN) {
   1.292 +      // if yes, iterate over all keys:
   1.293        for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
   1.294          switch (lua_type(L, -2)) {
   1.295          case LUA_TSTRING:
   1.296 +          // for string keys,
   1.297 +          // increase keycount (may avoid another iteration):
   1.298            keycount++;
   1.299 +          // if type of table was unknown, then type of table is a JSON object now:
   1.300            if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_OBJECT;
   1.301 +          // if type of table was a JSON array, then the type of table is ambiguous now
   1.302 +          // and an error is thrown:
   1.303            else if (tabletype == JSON_TABLETYPE_ARRAY) goto json_export_tabletype_error;
   1.304            break;
   1.305          case LUA_TNUMBER:
   1.306 +          // for numeric keys,
   1.307 +          // if type of table was unknown, then type of table is a JSON array now:
   1.308            if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_ARRAY;
   1.309 +          // if type of table was a JSON object, then the type of table is ambiguous now
   1.310 +          // and an error is thrown:
   1.311            else if (tabletype == JSON_TABLETYPE_OBJECT) goto json_export_tabletype_error;
   1.312            break;
   1.313          }
   1.314        }
   1.315      }
   1.316 +    // set pretty variable to 1 if pretty printing (with indentation) is desired:
   1.317      pretty = lua_toboolean(L, json_export_internal_indentstring_idx);
   1.318 +    // set level variable to corresponding function argument increased by one:
   1.319      level = lua_tointeger(L, json_export_internal_level_idx) + 1;
   1.320 +    // throw error if there are more levels that could be imported by this library:
   1.321      if (level > JSON_MAXDEPTH) {
   1.322        return luaL_error(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
   1.323      }
   1.324 +    // distinguish between JSON objects and JSON arrays:
   1.325      switch (tabletype) {
   1.326 +    // JSON object:
   1.327      case JSON_TABLETYPE_OBJECT:
   1.328 +      // calculate count of string keys unless it has been calculated before:
   1.329        if (!keycount) {
   1.330          for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
   1.331            if (lua_type(L, -2) == LUA_TSTRING) keycount++;
   1.332          }
   1.333        }
   1.334 +      // create a sorted list of all string keys in memory:
   1.335        if (keycount) {
   1.336 +        // allocate memory for string keys:
   1.337          keybuf = calloc(keycount, sizeof(json_key_t));
   1.338 -        if (!keybuf) return luaL_error(L, "Memory allocation failed in JSON library");
   1.339 +        // check if memory allocation was successful:
   1.340 +        if (!keybuf) {
   1.341 +          // in case of memory exhaustion, try to collect garbage:
   1.342 +          lua_gc(L, LUA_GCCOLLECT, 0);
   1.343 +          // try to allocate memory again:
   1.344 +          keybuf = calloc(keycount, sizeof(json_key_t));
   1.345 +          // throw error if memory allocation failed again:
   1.346 +          if (!keybuf) {
   1.347 +            return luaL_error(L, "Memory allocation failed in JSON library");
   1.348 +          }
   1.349 +        }
   1.350 +        // copy all string keys to the C array:
   1.351          for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
   1.352            if (lua_type(L, -2) == LUA_TSTRING) {
   1.353 -            json_key_t *key = keybuf + (keypos++);
   1.354 +            json_key_t *key = keybuf + (pos++);
   1.355              key->data = lua_tolstring(L, -2, &key->length);
   1.356            }
   1.357          }
   1.358 +        // sort C array using quicksort:
   1.359          qsort(keybuf, keycount, sizeof(json_key_t), (void *)json_key_cmp);
   1.360        }
   1.361 +      // create Lua string buffer:
   1.362        luaL_buffinit(L, &buf);
   1.363 +      // add opening bracket to output buffer:
   1.364        luaL_addchar(&buf, '{');
   1.365 -      for (keypos=0; keypos<keycount; keypos++) {
   1.366 -        json_key_t *key = keybuf + keypos;
   1.367 -        if (keypos) luaL_addchar(&buf, ',');
   1.368 +      // iterate through all (sorted) string keys:
   1.369 +      for (pos=0; pos<keycount; pos++) {
   1.370 +        json_key_t *key = keybuf + pos;
   1.371 +        // add comma to output buffer unless we process the first key:
   1.372 +        if (pos) luaL_addchar(&buf, ',');
   1.373 +        // handle indentation for pretty results:
   1.374          if (pretty) {
   1.375            luaL_addchar(&buf, '\n');
   1.376            for (i=0; i<level; i++) {
   1.377 @@ -1104,53 +1186,81 @@
   1.378              luaL_addvalue(&buf);
   1.379            }
   1.380          }
   1.381 +        // recursive call to encode key:
   1.382          lua_pushcfunction(L, json_export_internal);
   1.383          lua_pushvalue(L, json_export_internal_indentstring_idx);
   1.384          lua_pushinteger(L, level);
   1.385          lua_pushlstring(L, key->data, key->length);
   1.386          if (lua_pcall(L, 3, 1, 0)) {
   1.387 +          // free memory of sorted string keys on error:
   1.388            if (keybuf) free(keybuf);
   1.389 +          // rethrow error:
   1.390            return lua_error(L);
   1.391          }
   1.392 +        // add encoded key to output buffer:
   1.393          luaL_addvalue(&buf);
   1.394 +        // add colon to output buffer:
   1.395          luaL_addchar(&buf, ':');
   1.396 +        // handle indentation for pretty results:
   1.397          if (pretty) luaL_addchar(&buf, ' ');
   1.398 +        // recursive call to encode value:
   1.399          lua_pushcfunction(L, json_export_internal);
   1.400          lua_pushvalue(L, json_export_internal_indentstring_idx);
   1.401          lua_pushinteger(L, level);
   1.402          lua_pushlstring(L, key->data, key->length);
   1.403          lua_rawget(L, json_export_internal_value_idx);
   1.404          if (lua_pcall(L, 3, 1, 0)) {
   1.405 +          // free memory of sorted string keys on error:
   1.406            if (keybuf) free(keybuf);
   1.407 +          // rethrow error:
   1.408            return lua_error(L);
   1.409          }
   1.410 +        // add encoded value to output buffer:
   1.411          luaL_addvalue(&buf);
   1.412        }
   1.413 +      // decrement level variable for all following statements:
   1.414 +      level--;
   1.415 +      // free memory of sorted string keys:
   1.416        if (keybuf) free(keybuf);
   1.417 +      // handle indentation for pretty results:
   1.418        if (pretty && keycount != 0) {
   1.419          luaL_addchar(&buf, '\n');
   1.420 -        for (i=0; i<level-1; i++) {
   1.421 +        for (i=0; i<level; i++) {
   1.422            lua_pushvalue(L, json_export_internal_indentstring_idx);
   1.423            luaL_addvalue(&buf);
   1.424          }
   1.425        }
   1.426 +      // add closing bracket to output buffer:
   1.427        luaL_addchar(&buf, '}');
   1.428 -      if (pretty && level == 1) luaL_addchar(&buf, '\n');
   1.429 +      // for pretty results, add final newline character if outermost container is processed:
   1.430 +      if (pretty && level == 0) luaL_addchar(&buf, '\n');
   1.431 +      // convert and return buffer:
   1.432        luaL_pushresult(&buf);
   1.433        return 1;
   1.434 +    // JSON array:
   1.435      case JSON_TABLETYPE_ARRAY:
   1.436 +      // reserve an extra element on the stack (needed because Lua buffer has unknown size on stack):
   1.437        lua_settop(L, json_export_internal_tmp_idx);
   1.438 +      // create Lua string buffer:
   1.439        luaL_buffinit(L, &buf);
   1.440 +      // add opening bracket to output buffer:
   1.441        luaL_addchar(&buf, '[');
   1.442 -      for (idx = 1; ; idx++) {
   1.443 -        lua_rawgeti(L, json_export_internal_value_idx, idx);
   1.444 +      // iterate through integer keys:
   1.445 +      for (arrayidx = 1; ; arrayidx++) {
   1.446 +        // get value in array, and break if nil:
   1.447 +        lua_rawgeti(L, json_export_internal_value_idx, arrayidx);
   1.448          if (lua_isnil(L, -1)) {
   1.449            lua_pop(L, 1);
   1.450            break;
   1.451          }
   1.452 +        // store value below Lua string buffer on stack (to allow operation on string buffer):
   1.453          lua_replace(L, json_export_internal_tmp_idx);
   1.454 +        //
   1.455 +        // add comma to output buffer unless we process the first element:
   1.456          if (anyelement) luaL_addchar(&buf, ',');
   1.457 +        // remember that we processed an element:
   1.458          anyelement = 1;
   1.459 +        // handle indentation for pretty results:
   1.460          if (pretty) {
   1.461            luaL_addchar(&buf, '\n');
   1.462            for (i=0; i<level; i++) {
   1.463 @@ -1158,49 +1268,68 @@
   1.464              luaL_addvalue(&buf);
   1.465            }
   1.466          }
   1.467 +        // recursive call to encode previously stored value:
   1.468          lua_pushcfunction(L, json_export_internal);
   1.469          lua_pushvalue(L, json_export_internal_indentstring_idx);
   1.470          lua_pushinteger(L, level);
   1.471          lua_pushvalue(L, json_export_internal_tmp_idx);
   1.472          lua_call(L, 3, 1);
   1.473 +        // add encoded value to output buffer:
   1.474          luaL_addvalue(&buf);
   1.475        }
   1.476 +      // decrement level variable for all following statements:
   1.477 +      level--;
   1.478 +      // handle indentation for pretty results:
   1.479        if (pretty && anyelement) {
   1.480          luaL_addchar(&buf, '\n');
   1.481 -        for (i=0; i<level-1; i++) {
   1.482 +        for (i=0; i<level; i++) {
   1.483            lua_pushvalue(L, json_export_internal_indentstring_idx);
   1.484            luaL_addvalue(&buf);
   1.485          }
   1.486        }
   1.487 +      // add closing bracket to output buffer:
   1.488        luaL_addchar(&buf, ']');
   1.489 -      if (pretty && level == 1) luaL_addchar(&buf, '\n');
   1.490 +      // for pretty results, add final newline character if outermost container is processed:
   1.491 +      if (pretty && level == 0) luaL_addchar(&buf, '\n');
   1.492 +      // convert and return buffer:
   1.493        luaL_pushresult(&buf);
   1.494        return 1;
   1.495      }
   1.496 +    // throw error if table type is unknown:
   1.497      json_export_tabletype_error:
   1.498      return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)");
   1.499    }
   1.500 +  // all other datatypes are considered an error:
   1.501    return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, json_export_internal_value_idx)));
   1.502  }
   1.503  
   1.504 +// encodes a JSON document (passed as argument):
   1.505  static int json_export(lua_State *L) {
   1.506 +  // stack shall contain one function argument:
   1.507    lua_settop(L, 1);
   1.508 +  // call json_export_internal function with proper arguments:
   1.509    lua_pushcfunction(L, json_export_internal);
   1.510    lua_pushnil(L);
   1.511    lua_pushinteger(L, 0);
   1.512    lua_pushvalue(L, 1);
   1.513    lua_call(L, 3, 1);
   1.514 +  // return result:
   1.515    return 1;
   1.516  }
   1.517  
   1.518 +// encodes a JSON document (passed as first argument)
   1.519 +// with indentation (indentation string may be passed as second argument):
   1.520  static int json_pretty(lua_State *L) {
   1.521 +  // stack shall contain two function arguments:
   1.522    lua_settop(L, 2);
   1.523 +  // call json_export_internal function with proper arguments:
   1.524    lua_pushcfunction(L, json_export_internal);
   1.525    if (lua_isnil(L, 2)) lua_pushliteral(L, "  ");
   1.526    else lua_pushvalue(L, 2);
   1.527    lua_pushinteger(L, 0);
   1.528    lua_pushvalue(L, 1);
   1.529    lua_call(L, 3, 1);
   1.530 +  // return result:
   1.531    return 1;
   1.532  }
   1.533  

Impressum / About Us