webmcp

annotate libraries/json/json.c @ 122:ff39d4a310b9

Float parser for JSON library (non strict)
author jbe
date Fri Jul 25 22:50:12 2014 +0200 (2014-07-25)
parents 9ad1165cf3a1
children 402fce94f98c
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@121 5
jbe@121 6 #define JSON_VALUE 0
jbe@121 7 #define JSON_OBJECT_KEY 1
jbe@121 8 #define JSON_OBJECT_KEY_TERMINATOR 2
jbe@121 9 #define JSON_OBJECT_VALUE 3
jbe@121 10 #define JSON_OBJECT_SEPARATOR 4
jbe@121 11 #define JSON_ARRAY_VALUE 5
jbe@121 12 #define JSON_ARRAY_SEPARATOR 6
jbe@121 13 #define JSON_END 7
jbe@121 14
jbe@121 15 static int json_import(lua_State *L) {
jbe@121 16 const char *str;
jbe@121 17 size_t total;
jbe@121 18 size_t pos = 0;
jbe@121 19 size_t level = 0;
jbe@121 20 int mode = JSON_VALUE;
jbe@121 21 char c;
jbe@121 22 luaL_Buffer luabuf;
jbe@121 23 char *cbuf;
jbe@121 24 size_t writepos;
jbe@121 25 int aryidx;
jbe@121 26 lua_settop(L, 1);
jbe@121 27 str = lua_tostring(L, 1);
jbe@121 28 total = strlen(str);
jbe@121 29 json_import_loop:
jbe@121 30 while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++;
jbe@121 31 switch (c) {
jbe@121 32 case 0:
jbe@121 33 if (mode == JSON_END) return 1;
jbe@121 34 json_import_unexpected_eof:
jbe@121 35 lua_pushnil(L);
jbe@121 36 if (level == 0) lua_pushliteral(L, "Empty string");
jbe@121 37 else lua_pushliteral(L, "Unexpected end of JSON document");
jbe@121 38 return 2;
jbe@121 39 case '{':
jbe@121 40 if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE)
jbe@121 41 goto json_import_syntax_error;
jbe@121 42 pos++;
jbe@121 43 lua_newtable(L);
jbe@121 44 mode = JSON_OBJECT_KEY;
jbe@121 45 level++;
jbe@121 46 goto json_import_loop;
jbe@121 47 case '[':
jbe@121 48 if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE)
jbe@121 49 goto json_import_syntax_error;
jbe@121 50 pos++;
jbe@121 51 lua_newtable(L);
jbe@121 52 lua_pushinteger(L, 0); // length of array (since it may contain nil's)
jbe@121 53 mode = JSON_ARRAY_VALUE;
jbe@121 54 level++;
jbe@121 55 goto json_import_loop;
jbe@121 56 case '}':
jbe@121 57 if (mode != JSON_OBJECT_KEY && mode != JSON_OBJECT_SEPARATOR)
jbe@121 58 goto json_import_syntax_error;
jbe@121 59 goto json_import_close;
jbe@121 60 case ']':
jbe@121 61 if (mode != JSON_ARRAY_VALUE && mode != JSON_ARRAY_SEPARATOR)
jbe@121 62 goto json_import_syntax_error;
jbe@121 63 lua_pushvalue(L, -2); // use array table as key
jbe@121 64 lua_insert(L, -2); // use length of array as value
jbe@121 65 lua_rawset(L, lua_upvalueindex(1)); // store length in ephemeron table
jbe@121 66 // leaves array table on top of stack
jbe@121 67 json_import_close:
jbe@121 68 pos++;
jbe@121 69 if (--level) {
jbe@121 70 if (lua_type(L, -2) == LUA_TNUMBER) {
jbe@121 71 mode = JSON_ARRAY_VALUE;
jbe@121 72 } else {
jbe@121 73 mode = JSON_OBJECT_VALUE;
jbe@121 74 }
jbe@121 75 goto json_import_process_value;
jbe@121 76 } else {
jbe@121 77 mode = JSON_END;
jbe@121 78 }
jbe@121 79 goto json_import_loop;
jbe@121 80 case ':':
jbe@121 81 if (mode != JSON_OBJECT_KEY_TERMINATOR)
jbe@121 82 goto json_import_syntax_error;
jbe@121 83 pos++;
jbe@121 84 mode = JSON_OBJECT_VALUE;
jbe@121 85 goto json_import_loop;
jbe@121 86 case ',':
jbe@121 87 if (mode == JSON_OBJECT_SEPARATOR) {
jbe@121 88 mode = JSON_OBJECT_KEY;
jbe@121 89 } else if (mode == JSON_ARRAY_SEPARATOR) {
jbe@121 90 mode = JSON_ARRAY_VALUE;
jbe@121 91 } else {
jbe@121 92 goto json_import_syntax_error;
jbe@121 93 }
jbe@121 94 pos++;
jbe@121 95 goto json_import_loop;
jbe@121 96 case '"':
jbe@121 97 cbuf = luaL_buffinitsize(L, &luabuf, total-pos);
jbe@121 98 writepos = 0;
jbe@121 99 pos++;
jbe@121 100 while ((c = str[pos++]) != '"') {
jbe@121 101 if (c == 0) {
jbe@121 102 goto json_import_unexpected_eof;
jbe@121 103 } else if (c < 32 || c == 127) {
jbe@121 104 lua_pushnil(L);
jbe@121 105 lua_pushliteral(L, "Unexpected control character in JSON string");
jbe@121 106 return 2;
jbe@121 107 } else if (c == '\\') {
jbe@121 108 c = str[pos++];
jbe@121 109 switch (c) {
jbe@121 110 case 0:
jbe@121 111 goto json_import_unexpected_eof;
jbe@121 112 case '"':
jbe@121 113 case '/':
jbe@121 114 case '\\':
jbe@121 115 cbuf[writepos++] = c;
jbe@121 116 break;
jbe@121 117 case 'b':
jbe@121 118 cbuf[writepos++] = '\b';
jbe@121 119 break;
jbe@121 120 case 'f':
jbe@121 121 cbuf[writepos++] = '\f';
jbe@121 122 break;
jbe@121 123 case 'n':
jbe@121 124 cbuf[writepos++] = '\n';
jbe@121 125 break;
jbe@121 126 case 'r':
jbe@121 127 cbuf[writepos++] = '\r';
jbe@121 128 break;
jbe@121 129 case 't':
jbe@121 130 cbuf[writepos++] = '\t';
jbe@121 131 break;
jbe@121 132 case 'u':
jbe@121 133 lua_pushnil(L);
jbe@121 134 lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet"); // TODO
jbe@121 135 return 2;
jbe@121 136 default:
jbe@121 137 lua_pushnil(L);
jbe@121 138 lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
jbe@121 139 return 2;
jbe@121 140 }
jbe@121 141 } else {
jbe@121 142 cbuf[writepos++] = c;
jbe@121 143 }
jbe@121 144 }
jbe@121 145 if (!c) goto json_import_unexpected_eof;
jbe@121 146 luaL_pushresultsize(&luabuf, writepos);
jbe@121 147 goto json_import_process_value;
jbe@121 148 }
jbe@122 149 if (c == '-' || (c >= '0' && c <= '9')) {
jbe@122 150 char *endptr;
jbe@122 151 double numval;
jbe@122 152 numval = strtod(str+pos, &endptr);
jbe@122 153 if (endptr == str+pos) goto json_import_syntax_error;
jbe@122 154 pos += endptr - (str+pos);
jbe@122 155 lua_pushnumber(L, numval);
jbe@122 156 } else if (!strncmp(str+pos, "true", 4)) {
jbe@121 157 lua_pushboolean(L, 1);
jbe@121 158 pos += 4;
jbe@121 159 } else if (!strncmp(str+pos, "false", 5)) {
jbe@121 160 lua_pushboolean(L, 0);
jbe@121 161 pos += 5;
jbe@121 162 } else if (!strncmp(str+pos, "null", 4)) {
jbe@121 163 lua_pushnil(L);
jbe@121 164 pos += 4;
jbe@121 165 } else {
jbe@121 166 goto json_import_syntax_error;
jbe@121 167 }
jbe@121 168 json_import_process_value:
jbe@121 169 switch (mode) {
jbe@121 170 case JSON_OBJECT_KEY:
jbe@121 171 if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
jbe@121 172 mode = JSON_OBJECT_KEY_TERMINATOR;
jbe@121 173 goto json_import_loop;
jbe@121 174 case JSON_OBJECT_VALUE:
jbe@121 175 lua_rawset(L, -3);
jbe@121 176 mode = JSON_OBJECT_SEPARATOR;
jbe@121 177 goto json_import_loop;
jbe@121 178 case JSON_ARRAY_VALUE:
jbe@121 179 aryidx = lua_tointeger(L, -2) + 1;
jbe@121 180 lua_rawseti(L, -3, aryidx);
jbe@121 181 lua_pop(L, 1);
jbe@121 182 lua_pushinteger(L, aryidx);
jbe@121 183 mode = JSON_ARRAY_SEPARATOR;
jbe@121 184 goto json_import_loop;
jbe@121 185 case JSON_VALUE:
jbe@121 186 mode = JSON_END;
jbe@121 187 goto json_import_loop;
jbe@121 188 }
jbe@121 189 json_import_syntax_error:
jbe@121 190 lua_pushnil(L);
jbe@121 191 lua_pushliteral(L, "Syntax error in JSON document");
jbe@121 192 return 2;
jbe@121 193 }
jbe@121 194
jbe@121 195 static int json_arylen(lua_State *L) {
jbe@121 196 lua_settop(L, 1);
jbe@121 197 lua_rawget(L, lua_upvalueindex(1));
jbe@121 198 return 1;
jbe@121 199 }
jbe@121 200
jbe@121 201 static const struct luaL_Reg json_module_functions[] = {
jbe@121 202 {"import", json_import},
jbe@121 203 {"arylen", json_arylen},
jbe@121 204 {NULL, NULL}
jbe@121 205 };
jbe@121 206
jbe@121 207 int luaopen_json(lua_State *L) {
jbe@121 208 lua_newtable(L); // library table
jbe@121 209 lua_newtable(L); // ephemeron table to store the length of arrays (that may contain nil's)
jbe@121 210 lua_newtable(L); // meta table for ephemeron table
jbe@121 211 lua_pushliteral(L, "__mode");
jbe@121 212 lua_pushliteral(L, "k");
jbe@121 213 lua_rawset(L, -3);
jbe@121 214 lua_setmetatable(L, -2);
jbe@121 215 luaL_setfuncs(L, json_module_functions, 1);
jbe@121 216 return 1;
jbe@121 217 }

Impressum / About Us