webmcp

view libraries/json/json.c @ 124:ece4e6f683c9

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

Impressum / About Us