statistics: remove references to Lucid from scripts
[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 0;
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                         json_object_object_add(obj, key,
290                                                                    _lua_to_json(L, lua_gettop(L) - 1));
291
292                         lua_pop(L, 2);
293                 }
294
295                 return obj;
296
297         case LUA_TNIL:
298                 return NULL;
299
300         case LUA_TBOOLEAN:
301                 return json_object_new_boolean(lua_toboolean(L, index));
302
303         case LUA_TNUMBER:
304                 nd = lua_tonumber(L, index);
305                 ni = lua_tointeger(L, index);
306
307                 if (nd == ni)
308                         return json_object_new_int(nd);
309
310                 return json_object_new_double(nd);
311
312         case LUA_TSTRING:
313                 return json_object_new_string(lua_tostring(L, index));
314         }
315
316         return NULL;
317 }
318
319 static int json_parse_set(lua_State *L)
320 {
321         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
322
323         s->err = 0;
324         s->obj = _lua_to_json(L, 2);
325
326         return 0;
327 }
328
329 static int json_tostring(lua_State *L)
330 {
331         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
332         bool pretty = lua_toboolean(L, 2);
333         int flags = 0;
334
335         if (pretty)
336                 flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
337
338         lua_pushstring(L, json_object_to_json_string_ext(s->obj, flags));
339         return 1;
340 }
341
342 static int json_gc(lua_State *L)
343 {
344         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
345
346         if (s->obj)
347                 json_object_put(s->obj);
348
349         if (s->tok)
350                 json_tokener_free(s->tok);
351
352         return 0;
353 }
354
355
356 static const luaL_reg jsonc_methods[] = {
357         { "new",                        json_new          },
358         { "parse",                      json_parse        },
359         { "stringify",          json_stringify    },
360
361         { }
362 };
363
364 static const luaL_reg jsonc_parser_methods[] = {
365         { "parse",                      json_parse_chunk  },
366         { "get",                        json_parse_get    },
367         { "set",                        json_parse_set    },
368         { "stringify",          json_tostring     },
369
370         { "__gc",                       json_gc           },
371         { "__tostring",         json_tostring     },
372
373         { }
374 };
375
376
377 int luaopen_luci_jsonc(lua_State *L)
378 {
379         luaL_register(L, LUCI_JSONC, jsonc_methods);
380
381         luaL_newmetatable(L, LUCI_JSONC_PARSER);
382         luaL_register(L, NULL, jsonc_parser_methods);
383         lua_pushvalue(L, -1);
384         lua_setfield(L, -2, "__index");
385         lua_pop(L, 1);
386
387         return 1;
388 }