Merge pull request #393 from nmav/no-group-match
[project/luci.git] / libs / luci-lib-jsonc / src / jsonc.c
1 /*
2 Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <math.h>
20 #include <stdbool.h>
21 #include <json-c/json.h>
22
23 #include <lua.h>
24 #include <lualib.h>
25 #include <lauxlib.h>
26
27 #define LUCI_JSONC "luci.jsonc"
28 #define LUCI_JSONC_PARSER "luci.jsonc.parser"
29
30 struct json_state {
31 struct json_object *obj;
32 struct json_tokener *tok;
33 enum json_tokener_error err;
34 };
35
36 static void _json_to_lua(lua_State *L, struct json_object *obj);
37 static struct json_object * _lua_to_json(lua_State *L, int index);
38
39 static int json_new(lua_State *L)
40 {
41 struct json_state *s;
42 struct json_tokener *tok = json_tokener_new();
43
44 if (!tok)
45 return 0;
46
47 s = lua_newuserdata(L, sizeof(*s));
48
49 if (!s)
50 {
51 json_tokener_free(tok);
52 return 0;
53 }
54
55 s->tok = tok;
56 s->obj = NULL;
57 s->err = json_tokener_continue;
58
59 luaL_getmetatable(L, LUCI_JSONC_PARSER);
60 lua_setmetatable(L, -2);
61
62 return 1;
63 }
64
65 static int json_parse(lua_State *L)
66 {
67 size_t len;
68 const char *json = luaL_checklstring(L, 1, &len);
69 struct json_state s = {
70 .tok = json_tokener_new()
71 };
72
73 if (!s.tok)
74 return 0;
75
76 s.obj = json_tokener_parse_ex(s.tok, json, len);
77 s.err = json_tokener_get_error(s.tok);
78
79 if (s.obj)
80 {
81 _json_to_lua(L, s.obj);
82 json_object_put(s.obj);
83 }
84 else
85 {
86 lua_pushnil(L);
87 }
88
89 if (s.err == json_tokener_continue)
90 s.err = json_tokener_error_parse_eof;
91
92 if (s.err)
93 lua_pushstring(L, json_tokener_error_desc(s.err));
94
95 json_tokener_free(s.tok);
96 return (1 + !!s.err);
97 }
98
99 static int json_stringify(lua_State *L)
100 {
101 struct json_object *obj = _lua_to_json(L, 1);
102 bool pretty = lua_toboolean(L, 2);
103 int flags = 0;
104
105 if (pretty)
106 flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
107
108 lua_pushstring(L, json_object_to_json_string_ext(obj, flags));
109 return 1;
110 }
111
112
113 static int json_parse_chunk(lua_State *L)
114 {
115 size_t len;
116 struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
117 const char *chunk = luaL_checklstring(L, 2, &len);
118
119 s->obj = json_tokener_parse_ex(s->tok, chunk, len);
120 s->err = json_tokener_get_error(s->tok);
121
122 if (!s->err)
123 {
124 lua_pushboolean(L, true);
125 return 1;
126 }
127 else if (s->err == json_tokener_continue)
128 {
129 lua_pushboolean(L, false);
130 return 1;
131 }
132
133 lua_pushnil(L);
134 lua_pushstring(L, json_tokener_error_desc(s->err));
135 return 2;
136 }
137
138 static void _json_to_lua(lua_State *L, struct json_object *obj)
139 {
140 int n;
141
142 switch (json_object_get_type(obj))
143 {
144 case json_type_object:
145 lua_newtable(L);
146 json_object_object_foreach(obj, key, val)
147 {
148 _json_to_lua(L, val);
149 lua_setfield(L, -2, key);
150 }
151 break;
152
153 case json_type_array:
154 lua_newtable(L);
155 for (n = 0; n < json_object_array_length(obj); n++)
156 {
157 _json_to_lua(L, json_object_array_get_idx(obj, n));
158 lua_rawseti(L, -2, n + 1);
159 }
160 break;
161
162 case json_type_boolean:
163 lua_pushboolean(L, json_object_get_boolean(obj));
164 break;
165
166 case json_type_int:
167 lua_pushinteger(L, json_object_get_int(obj));
168 break;
169
170 case json_type_double:
171 lua_pushnumber(L, json_object_get_double(obj));
172 break;
173
174 case json_type_string:
175 lua_pushstring(L, json_object_get_string(obj));
176 break;
177
178 case json_type_null:
179 lua_pushnil(L);
180 break;
181 }
182 }
183
184 static int json_parse_get(lua_State *L)
185 {
186 struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
187
188 if (!s->obj || s->err)
189 lua_pushnil(L);
190 else
191 _json_to_lua(L, s->obj);
192
193 return 1;
194 }
195
196 static int _lua_test_array(lua_State *L, int index)
197 {
198 int max = 0;
199 lua_Number idx;
200
201 lua_pushnil(L);
202
203 /* check for non-integer keys */
204 while (lua_next(L, index))
205 {
206 if (lua_type(L, -2) != LUA_TNUMBER)
207 goto out;
208
209 idx = lua_tonumber(L, -2);
210
211 if (idx != (lua_Number)(lua_Integer)idx)
212 goto out;
213
214 if (idx <= 0)
215 goto out;
216
217 if (idx > max)
218 max = idx;
219
220 lua_pop(L, 1);
221 continue;
222
223 out:
224 lua_pop(L, 2);
225 return -1;
226 }
227
228 /* check for holes */
229 //for (i = 1; i <= max; i++)
230 //{
231 // lua_rawgeti(L, index, i);
232 //
233 // if (lua_isnil(L, -1))
234 // {
235 // lua_pop(L, 1);
236 // return 0;
237 // }
238 //
239 // lua_pop(L, 1);
240 //}
241
242 return max;
243 }
244
245 static struct json_object * _lua_to_json(lua_State *L, int index)
246 {
247 lua_Number nd, ni;
248 struct json_object *obj;
249 const char *key;
250 int i, max;
251
252 switch (lua_type(L, index))
253 {
254 case LUA_TTABLE:
255 max = _lua_test_array(L, index);
256
257 if (max >= 0)
258 {
259 obj = json_object_new_array();
260
261 if (!obj)
262 return NULL;
263
264 for (i = 1; i <= max; i++)
265 {
266 lua_rawgeti(L, index, i);
267
268 json_object_array_put_idx(obj, i - 1,
269 _lua_to_json(L, lua_gettop(L)));
270
271 lua_pop(L, 1);
272 }
273
274 return obj;
275 }
276
277 obj = json_object_new_object();
278
279 if (!obj)
280 return NULL;
281
282 lua_pushnil(L);
283
284 while (lua_next(L, index))
285 {
286 lua_pushvalue(L, -2);
287 key = lua_tostring(L, -1);
288
289 if (key)
290 json_object_object_add(obj, key,
291 _lua_to_json(L, lua_gettop(L) - 1));
292
293 lua_pop(L, 2);
294 }
295
296 return obj;
297
298 case LUA_TNIL:
299 return NULL;
300
301 case LUA_TBOOLEAN:
302 return json_object_new_boolean(lua_toboolean(L, index));
303
304 case LUA_TNUMBER:
305 nd = lua_tonumber(L, index);
306 ni = lua_tointeger(L, index);
307
308 if (nd == ni)
309 return json_object_new_int(nd);
310
311 return json_object_new_double(nd);
312
313 case LUA_TSTRING:
314 return json_object_new_string(lua_tostring(L, index));
315 }
316
317 return NULL;
318 }
319
320 static int json_parse_set(lua_State *L)
321 {
322 struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
323
324 s->err = 0;
325 s->obj = _lua_to_json(L, 2);
326
327 return 0;
328 }
329
330 static int json_tostring(lua_State *L)
331 {
332 struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
333 bool pretty = lua_toboolean(L, 2);
334 int flags = 0;
335
336 if (pretty)
337 flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
338
339 lua_pushstring(L, json_object_to_json_string_ext(s->obj, flags));
340 return 1;
341 }
342
343 static int json_gc(lua_State *L)
344 {
345 struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
346
347 if (s->obj)
348 json_object_put(s->obj);
349
350 if (s->tok)
351 json_tokener_free(s->tok);
352
353 return 0;
354 }
355
356
357 static const luaL_reg jsonc_methods[] = {
358 { "new", json_new },
359 { "parse", json_parse },
360 { "stringify", json_stringify },
361
362 { }
363 };
364
365 static const luaL_reg jsonc_parser_methods[] = {
366 { "parse", json_parse_chunk },
367 { "get", json_parse_get },
368 { "set", json_parse_set },
369 { "stringify", json_tostring },
370
371 { "__gc", json_gc },
372 { "__tostring", json_tostring },
373
374 { }
375 };
376
377
378 int luaopen_luci_jsonc(lua_State *L)
379 {
380 luaL_register(L, LUCI_JSONC, jsonc_methods);
381
382 luaL_newmetatable(L, LUCI_JSONC_PARSER);
383 luaL_register(L, NULL, jsonc_parser_methods);
384 lua_pushvalue(L, -1);
385 lua_setfield(L, -2, "__index");
386 lua_pop(L, 1);
387
388 return 1;
389 }