webmcp

changeset 154:c8669dde9ce2

Added JSON export function
author jbe
date Thu Jul 31 03:01:53 2014 +0200 (2014-07-31)
parents c8c91216255f
children 185e944182cb
files libraries/json/json.c
line diff
     1.1 --- a/libraries/json/json.c	Thu Jul 31 01:21:33 2014 +0200
     1.2 +++ b/libraries/json/json.c	Thu Jul 31 03:01:53 2014 +0200
     1.3 @@ -2,6 +2,7 @@
     1.4  #include <lauxlib.h>
     1.5  #include <stdlib.h>
     1.6  #include <string.h>
     1.7 +#include <math.h>
     1.8  
     1.9  // maximum number of nested JSON values (objects and arrays):
    1.10  // NOTE: The Lua reference states that the stack may typically contain at least
    1.11 @@ -17,6 +18,7 @@
    1.12  #define JSON_REGENT char
    1.13  #define JSON_REGPOINTER void *
    1.14  #define json_pushlightref(L, x) lua_pushlightuserdata((L), &json_reference.x)
    1.15 +#define json_islightref(L, i, x) (lua_touserdata((L), (i)) == &json_reference.x)
    1.16  #define json_regpointer(x) (&json_registry.x)
    1.17  #define json_regfetchpointer(L, x) lua_rawgetp((L), LUA_REGISTRYINDEX, (x))
    1.18  #define json_regfetch(L, x) json_regfetchpointer(L, json_regpointer(x))
    1.19 @@ -27,7 +29,6 @@
    1.20    JSON_REGENT nullmark;  // magic value to indicate JSON null value in shadow table
    1.21  } json_reference;
    1.22  
    1.23 -
    1.24  // generate dummy memory addresses that represent Lua objects
    1.25  // via lightuserdata keys and LUA_REGISTRYINDEX:
    1.26  static struct {
    1.27 @@ -751,11 +752,156 @@
    1.28    return 3;
    1.29  }
    1.30  
    1.31 +#define JSON_TABLETYPE_UNKNOWN 0
    1.32 +#define JSON_TABLETYPE_OBJECT 1
    1.33 +#define JSON_TABLETYPE_ARRAY 2
    1.34 +
    1.35 +static int json_export(lua_State *L) {
    1.36 +  lua_Number num;
    1.37 +  const char *str;
    1.38 +  unsigned char c;
    1.39 +  size_t strlen;
    1.40 +  size_t pos = 0;
    1.41 +  luaL_Buffer buf;
    1.42 +  char hexcode[7];  // backslash, character 'u', 4 hex digits, and terminating NULL byte
    1.43 +  int luatype;
    1.44 +  int tabletype = JSON_TABLETYPE_UNKNOWN;
    1.45 +  int needsep = 0;
    1.46 +  lua_Integer idx;
    1.47 +  lua_settop(L, 1);
    1.48 +  switch (lua_type(L, 1)) {
    1.49 +  case LUA_TNIL:
    1.50 +    lua_pushliteral(L, "null");
    1.51 +    return 1;
    1.52 +  case LUA_TNUMBER:
    1.53 +    num = lua_tonumber(L, 1);
    1.54 +    if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value");
    1.55 +    if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers");
    1.56 +    lua_tostring(L, 1);
    1.57 +    return 1;
    1.58 +  case LUA_TBOOLEAN:
    1.59 +    if (lua_toboolean(L, 1)) lua_pushliteral(L, "true");
    1.60 +    else lua_pushliteral(L, "false");
    1.61 +    return 1;
    1.62 +  case LUA_TSTRING:
    1.63 +    str = lua_tolstring(L, 1, &strlen);
    1.64 +    luaL_buffinit(L, &buf);
    1.65 +    luaL_addchar(&buf, '"');
    1.66 +    while (pos < strlen) {
    1.67 +      c = str[pos++];
    1.68 +      if (c == '"')       luaL_addstring(&buf, "\\\"");
    1.69 +      else if (c == '\\') luaL_addstring(&buf, "\\\\");
    1.70 +      else if (c == 127)  luaL_addstring(&buf, "\\u007F");
    1.71 +      else if (c >= 32)   luaL_addchar(&buf, c);
    1.72 +      else if (c == '\b') luaL_addstring(&buf, "\\b");
    1.73 +      else if (c == '\f') luaL_addstring(&buf, "\\f");
    1.74 +      else if (c == '\n') luaL_addstring(&buf, "\\n");
    1.75 +      else if (c == '\r') luaL_addstring(&buf, "\\r");
    1.76 +      else if (c == '\t') luaL_addstring(&buf, "\\t");
    1.77 +      else if (c == '\v') luaL_addstring(&buf, "\\v");
    1.78 +      else {
    1.79 +        sprintf(hexcode, "\\u%04X", c);
    1.80 +        luaL_addstring(&buf, hexcode);
    1.81 +      }
    1.82 +    }
    1.83 +    luaL_addchar(&buf, '"');
    1.84 +    luaL_pushresult(&buf);
    1.85 +    return 1;
    1.86 +  case LUA_TTABLE:
    1.87 +    if (lua_getmetatable(L, 1)) {
    1.88 +      json_regfetch(L, objectmt);
    1.89 +      if (lua_rawequal(L, -2, -1)) {
    1.90 +        tabletype = JSON_TABLETYPE_OBJECT;
    1.91 +      } else {
    1.92 +        json_regfetch(L, arraymt);
    1.93 +        if (lua_rawequal(L, -3, -1)) tabletype = JSON_TABLETYPE_ARRAY;
    1.94 +      }
    1.95 +    }
    1.96 +    json_regfetch(L, shadowtbl);
    1.97 +    lua_pushvalue(L, 1);
    1.98 +    lua_rawget(L, -2);
    1.99 +    if (!lua_isnil(L, -1)) lua_replace(L, 1);
   1.100 +    lua_settop(L, 1);
   1.101 +    if (tabletype == JSON_TABLETYPE_UNKNOWN) {
   1.102 +      for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
   1.103 +        luatype = lua_type(L, -2);
   1.104 +        if (tabletype == JSON_TABLETYPE_UNKNOWN) {
   1.105 +          if (luatype == LUA_TSTRING) tabletype = JSON_TABLETYPE_OBJECT;
   1.106 +          else if (luatype == LUA_TNUMBER) tabletype = JSON_TABLETYPE_ARRAY;
   1.107 +        } else if (
   1.108 +          (tabletype == JSON_TABLETYPE_OBJECT && luatype == LUA_TNUMBER) ||
   1.109 +          (tabletype == JSON_TABLETYPE_ARRAY && luatype == LUA_TSTRING)
   1.110 +        ) {
   1.111 +          goto json_export_tabletype_error;
   1.112 +        }
   1.113 +      }
   1.114 +    }
   1.115 +    switch (tabletype) {
   1.116 +    case JSON_TABLETYPE_OBJECT:
   1.117 +      lua_settop(L, 3);
   1.118 +      luaL_buffinit(L, &buf);
   1.119 +      luaL_addchar(&buf, '{');
   1.120 +      for (lua_pushnil(L); lua_next(L, 1); ) {
   1.121 +        if (lua_type(L, -2) == LUA_TSTRING) {
   1.122 +          lua_replace(L, 3);
   1.123 +          lua_replace(L, 2);
   1.124 +          if (needsep) luaL_addchar(&buf, ',');
   1.125 +          else needsep = 1;
   1.126 +          lua_pushcfunction(L, json_export);
   1.127 +          lua_pushvalue(L, 2);
   1.128 +          lua_call(L, 1, 1);
   1.129 +          luaL_addvalue(&buf);
   1.130 +          luaL_addchar(&buf, ':');
   1.131 +          if (json_islightref(L, 3, nullmark)) {
   1.132 +            luaL_addstring(&buf, "null");
   1.133 +          } else {
   1.134 +            lua_pushcfunction(L, json_export);
   1.135 +            lua_pushvalue(L, 3);
   1.136 +            lua_call(L, 1, 1);
   1.137 +            luaL_addvalue(&buf);
   1.138 +          }
   1.139 +          lua_pushvalue(L, 2);
   1.140 +        } else {
   1.141 +          lua_pop(L, 1);
   1.142 +        }
   1.143 +      }
   1.144 +      luaL_addchar(&buf, '}');
   1.145 +      luaL_pushresult(&buf);
   1.146 +      return 1;
   1.147 +    case JSON_TABLETYPE_ARRAY:
   1.148 +      lua_settop(L, 2);
   1.149 +      luaL_buffinit(L, &buf);
   1.150 +      luaL_addchar(&buf, '[');
   1.151 +      for (idx = 1; ; idx++) {
   1.152 +        lua_rawgeti(L, 1, idx);
   1.153 +        if (lua_isnil(L, -1)) {
   1.154 +          lua_pop(L, 1);
   1.155 +          break;
   1.156 +        }
   1.157 +        lua_replace(L, 2);
   1.158 +        if (needsep) luaL_addchar(&buf, ',');
   1.159 +        else needsep = 1;
   1.160 +        lua_pushcfunction(L, json_export);
   1.161 +        lua_pushvalue(L, 2);
   1.162 +        lua_call(L, 1, 1);
   1.163 +        luaL_addvalue(&buf);
   1.164 +      }
   1.165 +      luaL_addchar(&buf, ']');
   1.166 +      luaL_pushresult(&buf);
   1.167 +      return 1;
   1.168 +    }
   1.169 +    json_export_tabletype_error:
   1.170 +    return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)");
   1.171 +  }
   1.172 +  return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, 1)));
   1.173 +}
   1.174 +
   1.175  // functions in library module:
   1.176  static const struct luaL_Reg json_module_functions[] = {
   1.177    {"object", json_object},
   1.178    {"array", json_array},
   1.179    {"import", json_import},
   1.180 +  {"export", json_export},
   1.181    {"get", json_get},
   1.182    {"type", json_type},
   1.183    {"isnull", json_isnull},

Impressum / About Us