webmcp

view libraries/json/json.c @ 123:402fce94f98c

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

Impressum / About Us