1 /* Copyright (c) 2014, Vsevolod Stakhov
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 /**
25 * @file lua ucl bindings
26 */
27
28 #include "ucl.h"
29 #include "ucl_internal.h"
30 #include "lua_ucl.h"
31 #include <strings.h>
32
33 /***
34 * @module ucl
35 * This lua module allows to parse objects from strings and to store data into
36 * ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
37 * @example
38 local ucl = require("ucl")
39
40 local parser = ucl.parser()
41 local res,err = parser:parse_string('{key=value}')
42
43 if not res then
44 print('parser error: ' .. err)
45 else
46 local obj = parser:get_object()
47 local got = ucl.to_format(obj, 'json')
48 endif
49
50 local table = {
51 str = 'value',
52 num = 100500,
53 null = ucl.null,
54 func = function ()
55 return 'huh'
56 end
57 }
58
59 print(ucl.to_format(table, 'ucl'))
60 -- Output:
61 --[[
62 num = 100500;
63 str = "value";
64 null = null;
65 func = "huh";
66 --]]
67 */
68
69 #define PARSER_META "ucl.parser.meta"
70 #define EMITTER_META "ucl.emitter.meta"
71 #define NULL_META "ucl.null.meta"
72 #define OBJECT_META "ucl.object.meta"
73 #define UCL_OBJECT_TYPE_META "ucl.type.object"
74 #define UCL_ARRAY_TYPE_META "ucl.type.array"
75 #define UCL_IMPL_ARRAY_TYPE_META "ucl.type.impl_array"
76
77 static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags);
78 static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, int flags);
79 static int ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags);
80 static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags);
81 static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags);
82
83 static void *ucl_null;
84
85 struct _rspamd_lua_text {
86 const char *start;
87 unsigned int len;
88 unsigned int flags;
89 };
90
91 enum lua_ucl_push_flags {
92 LUA_UCL_DEFAULT_FLAGS = 0,
93 LUA_UCL_ALLOW_ARRAY = (1u << 0u),
94 LUA_UCL_CONVERT_NIL = (1u << 1u),
95 };
96
97 /**
98 * Push a single element of an object to lua
99 * @param L
100 * @param key
101 * @param obj
102 */
103 static void
ucl_object_lua_push_element(lua_State * L,const char * key,const ucl_object_t * obj,int flags)104 ucl_object_lua_push_element (lua_State *L, const char *key,
105 const ucl_object_t *obj, int flags)
106 {
107 lua_pushstring (L, key);
108 ucl_object_push_lua_common (L, obj, flags|LUA_UCL_ALLOW_ARRAY);
109 lua_settable (L, -3);
110 }
111
112 static void
lua_ucl_userdata_dtor(void * ud)113 lua_ucl_userdata_dtor (void *ud)
114 {
115 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
116
117 luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
118 if (fd->ret != NULL) {
119 free (fd->ret);
120 }
121 free (fd);
122 }
123
124 static const char *
lua_ucl_userdata_emitter(void * ud)125 lua_ucl_userdata_emitter (void *ud)
126 {
127 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
128 const char *out = "";
129
130 lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
131
132 lua_pcall (fd->L, 0, 1, 0);
133 out = lua_tostring (fd->L, -1);
134
135 if (out != NULL) {
136 /* We need to store temporary string in a more appropriate place */
137 if (fd->ret) {
138 free (fd->ret);
139 }
140 fd->ret = strdup (out);
141 }
142
143 lua_settop (fd->L, 0);
144
145 return fd->ret;
146 }
147
148 /**
149 * Push a single object to lua
150 * @param L
151 * @param obj
152 * @return
153 */
154 static int
ucl_object_lua_push_object(lua_State * L,const ucl_object_t * obj,int flags)155 ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
156 int flags)
157 {
158 const ucl_object_t *cur;
159 ucl_object_iter_t it = NULL;
160
161 if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
162 /* Actually we need to push this as an array */
163 return ucl_object_lua_push_array (L, obj, flags);
164 }
165
166 lua_createtable (L, 0, obj->len);
167 it = NULL;
168
169 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
170 ucl_object_lua_push_element (L, ucl_object_key (cur), cur, flags);
171 }
172
173 luaL_getmetatable (L, UCL_OBJECT_TYPE_META);
174 lua_setmetatable (L, -2);
175
176 return 1;
177 }
178
179 /**
180 * Push an array to lua as table indexed by integers
181 * @param L
182 * @param obj
183 * @return
184 */
185 static int
ucl_object_lua_push_array(lua_State * L,const ucl_object_t * obj,int flags)186 ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags)
187 {
188 const ucl_object_t *cur;
189 ucl_object_iter_t it;
190 int i = 1, nelt = 0;
191
192 if (obj->type == UCL_ARRAY) {
193 nelt = obj->len;
194 it = ucl_object_iterate_new (obj);
195 lua_createtable (L, nelt, 0);
196
197 while ((cur = ucl_object_iterate_safe (it, true))) {
198 ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
199 lua_rawseti (L, -2, i);
200 i ++;
201 }
202
203 luaL_getmetatable (L, UCL_ARRAY_TYPE_META);
204 lua_setmetatable (L, -2);
205
206 ucl_object_iterate_free (it);
207 }
208 else {
209 /* Optimize allocation by preallocation of table */
210 LL_FOREACH (obj, cur) {
211 nelt ++;
212 }
213
214 lua_createtable (L, nelt, 0);
215
216 LL_FOREACH (obj, cur) {
217 ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
218 lua_rawseti (L, -2, i);
219 i ++;
220 }
221
222 luaL_getmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
223 lua_setmetatable (L, -2);
224 }
225
226 return 1;
227 }
228
229 /**
230 * Push a simple object to lua depending on its actual type
231 */
232 static int
ucl_object_lua_push_scalar(lua_State * L,const ucl_object_t * obj,int flags)233 ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
234 int flags)
235 {
236 struct ucl_lua_funcdata *fd;
237
238 if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
239 /* Actually we need to push this as an array */
240 return ucl_object_lua_push_array (L, obj, flags);
241 }
242
243 switch (obj->type) {
244 case UCL_BOOLEAN:
245 lua_pushboolean (L, ucl_obj_toboolean (obj));
246 break;
247 case UCL_STRING:
248 lua_pushlstring (L, ucl_obj_tostring (obj), obj->len);
249 break;
250 case UCL_INT:
251 #if LUA_VERSION_NUM >= 501
252 lua_pushinteger (L, ucl_obj_toint (obj));
253 #else
254 lua_pushnumber (L, ucl_obj_toint (obj));
255 #endif
256 break;
257 case UCL_FLOAT:
258 case UCL_TIME:
259 lua_pushnumber (L, ucl_obj_todouble (obj));
260 break;
261 case UCL_NULL:
262 if (flags & LUA_UCL_CONVERT_NIL) {
263 lua_pushboolean (L, false);
264 }
265 else {
266 lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
267 }
268 break;
269 case UCL_USERDATA:
270 fd = (struct ucl_lua_funcdata *)obj->value.ud;
271 lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
272 break;
273 default:
274 lua_pushnil (L);
275 break;
276 }
277
278 return 1;
279 }
280
281 static int
ucl_object_push_lua_common(lua_State * L,const ucl_object_t * obj,int flags)282 ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags)
283 {
284 switch (obj->type) {
285 case UCL_OBJECT:
286 return ucl_object_lua_push_object (L, obj, flags);
287 case UCL_ARRAY:
288 return ucl_object_lua_push_array (L, obj, flags);
289 default:
290 return ucl_object_lua_push_scalar (L, obj, flags);
291 }
292 }
293
294 /***
295 * @function ucl_object_push_lua(L, obj, allow_array)
296 * This is a `C` function to push `UCL` object as lua variable. This function
297 * converts `obj` to lua representation using the following conversions:
298 *
299 * - *scalar* values are directly presented by lua objects
300 * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
301 * this can be used to pass functions from lua to c and vice-versa
302 * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
303 * - *objects* are converted to lua tables with string indicies
304 * @param {lua_State} L lua state pointer
305 * @param {ucl_object_t} obj object to push
306 * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
307 * @return {int} `1` if an object is pushed to lua
308 */
309 int
ucl_object_push_lua(lua_State * L,const ucl_object_t * obj,bool allow_array)310 ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
311 {
312 return ucl_object_push_lua_common (L, obj,
313 allow_array ? LUA_UCL_ALLOW_ARRAY : LUA_UCL_DEFAULT_FLAGS);
314 }
315
316 int
ucl_object_push_lua_filter_nil(lua_State * L,const ucl_object_t * obj,bool allow_array)317 ucl_object_push_lua_filter_nil (lua_State *L, const ucl_object_t *obj, bool allow_array)
318 {
319 return ucl_object_push_lua_common (L, obj,
320 allow_array ? (LUA_UCL_ALLOW_ARRAY|LUA_UCL_CONVERT_NIL) :
321 (LUA_UCL_DEFAULT_FLAGS|LUA_UCL_CONVERT_NIL));
322 }
323
324 /**
325 * Parse lua table into object top
326 * @param L
327 * @param top
328 * @param idx
329 */
330 static ucl_object_t *
ucl_object_lua_fromtable(lua_State * L,int idx,ucl_string_flags_t flags)331 ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)
332 {
333 ucl_object_t *obj, *top = NULL, *cur;
334 size_t keylen;
335 const char *k;
336 bool is_array = true, is_implicit = false, found_mt = false;
337 size_t max = 0, nelts = 0;
338
339 if (idx < 0) {
340 /* For negative indicies we want to invert them */
341 idx = lua_gettop (L) + idx + 1;
342 }
343
344 /* First, we check from metatable */
345 if (luaL_getmetafield (L, idx, "class") != 0) {
346
347 if (lua_type (L, -1) == LUA_TSTRING) {
348 const char *classname = lua_tostring (L, -1);
349
350 if (strcmp (classname, UCL_OBJECT_TYPE_META) == 0) {
351 is_array = false;
352 found_mt = true;
353 } else if (strcmp (classname, UCL_ARRAY_TYPE_META) == 0) {
354 is_array = true;
355 found_mt = true;
356 #if LUA_VERSION_NUM >= 502
357 max = lua_rawlen (L, idx);
358 #else
359 max = lua_objlen (L, idx);
360 #endif
361 nelts = max;
362 } else if (strcmp (classname, UCL_IMPL_ARRAY_TYPE_META) == 0) {
363 is_array = true;
364 is_implicit = true;
365 found_mt = true;
366 #if LUA_VERSION_NUM >= 502
367 max = lua_rawlen (L, idx);
368 #else
369 max = lua_objlen (L, idx);
370 #endif
371 nelts = max;
372 }
373 }
374
375 lua_pop (L, 1);
376 }
377
378 if (!found_mt) {
379 /* Check for array (it is all inefficient) */
380 lua_pushnil (L);
381
382 while (lua_next (L, idx) != 0) {
383 lua_pushvalue (L, -2);
384
385 if (lua_type (L, -1) == LUA_TNUMBER) {
386 double num = lua_tonumber (L, -1);
387 if (num == (int) num) {
388 if (num > max) {
389 max = num;
390 }
391 }
392 else {
393 /* Keys are not integer */
394 is_array = false;
395 }
396 }
397 else {
398 /* Keys are not numeric */
399 is_array = false;
400 }
401
402 lua_pop (L, 2);
403 nelts ++;
404 }
405 }
406
407 /* Table iterate */
408 if (is_array) {
409 int i;
410
411 if (!is_implicit) {
412 top = ucl_object_typed_new (UCL_ARRAY);
413 ucl_object_reserve (top, nelts);
414 }
415 else {
416 top = NULL;
417 }
418
419 for (i = 1; i <= max; i ++) {
420 lua_pushinteger (L, i);
421 lua_gettable (L, idx);
422
423 obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags);
424
425 if (obj != NULL) {
426 if (is_implicit) {
427 DL_APPEND (top, obj);
428 }
429 else {
430 ucl_array_append (top, obj);
431 }
432 }
433 lua_pop (L, 1);
434 }
435 }
436 else {
437 lua_pushnil (L);
438 top = ucl_object_typed_new (UCL_OBJECT);
439 ucl_object_reserve (top, nelts);
440
441 while (lua_next (L, idx) != 0) {
442 /* copy key to avoid modifications */
443 lua_pushvalue (L, -2);
444 k = lua_tolstring (L, -1, &keylen);
445 obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags);
446
447 if (obj != NULL) {
448 ucl_object_insert_key (top, obj, k, keylen, true);
449
450 DL_FOREACH (obj, cur) {
451 if (cur->keylen == 0) {
452 cur->keylen = obj->keylen;
453 cur->key = obj->key;
454 }
455 }
456 }
457 lua_pop (L, 2);
458 }
459 }
460
461 return top;
462 }
463
464 /**
465 * Get a single element from lua to object obj
466 * @param L
467 * @param obj
468 * @param idx
469 */
470 static ucl_object_t *
ucl_object_lua_fromelt(lua_State * L,int idx,ucl_string_flags_t flags)471 ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)
472 {
473 int type;
474 double num;
475 ucl_object_t *obj = NULL;
476 struct ucl_lua_funcdata *fd;
477 const char *str;
478 size_t sz;
479
480 type = lua_type (L, idx);
481
482 switch (type) {
483 case LUA_TSTRING:
484 str = lua_tolstring (L, idx, &sz);
485
486 if (str) {
487 obj = ucl_object_fromstring_common (str, sz, flags);
488 }
489 else {
490 obj = ucl_object_typed_new (UCL_NULL);
491 }
492 break;
493 case LUA_TNUMBER:
494 num = lua_tonumber (L, idx);
495 if (num == (int64_t)num) {
496 obj = ucl_object_fromint (num);
497 }
498 else {
499 obj = ucl_object_fromdouble (num);
500 }
501 break;
502 case LUA_TBOOLEAN:
503 obj = ucl_object_frombool (lua_toboolean (L, idx));
504 break;
505 case LUA_TUSERDATA:
506 if (lua_topointer (L, idx) == ucl_null) {
507 obj = ucl_object_typed_new (UCL_NULL);
508 }
509 else {
510 /* Assume it is a text like object */
511 struct _rspamd_lua_text *t = lua_touserdata (L, idx);
512
513 if (t) {
514 obj = ucl_object_fromstring_common(t->start, t->len, 0);
515 }
516 }
517 break;
518 case LUA_TTABLE:
519 case LUA_TFUNCTION:
520 case LUA_TTHREAD:
521 if (luaL_getmetafield (L, idx, "__gen_ucl")) {
522 if (lua_isfunction (L, -1)) {
523 lua_settop (L, 3); /* gen, obj, func */
524 lua_insert (L, 1); /* func, gen, obj */
525 lua_insert (L, 2); /* func, obj, gen */
526 lua_call(L, 2, 1);
527 obj = ucl_object_lua_fromelt (L, 1, flags);
528 }
529 lua_pop (L, 2);
530 }
531 else {
532 if (type == LUA_TTABLE) {
533 obj = ucl_object_lua_fromtable (L, idx, flags);
534 }
535 else if (type == LUA_TFUNCTION) {
536 fd = malloc (sizeof (*fd));
537 if (fd != NULL) {
538 lua_pushvalue (L, idx);
539 fd->L = L;
540 fd->ret = NULL;
541 fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
542
543 obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
544 lua_ucl_userdata_emitter, (void *)fd);
545 }
546 }
547 }
548 break;
549 }
550
551 return obj;
552 }
553
554 /**
555 * @function ucl_object_lua_import(L, idx)
556 * Extracts ucl object from lua variable at `idx` position,
557 * @see ucl_object_push_lua for conversion definitions
558 * @param {lua_state} L lua state machine pointer
559 * @param {int} idx index where the source variable is placed
560 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
561 * this object thus needs to be unref'ed after usage.
562 */
563 ucl_object_t *
ucl_object_lua_import(lua_State * L,int idx)564 ucl_object_lua_import (lua_State *L, int idx)
565 {
566 ucl_object_t *obj;
567 int t;
568
569 t = lua_type (L, idx);
570 switch (t) {
571 case LUA_TTABLE:
572 obj = ucl_object_lua_fromtable (L, idx, 0);
573 break;
574 default:
575 obj = ucl_object_lua_fromelt (L, idx, 0);
576 break;
577 }
578
579 return obj;
580 }
581
582 /**
583 * @function ucl_object_lua_import_escape(L, idx)
584 * Extracts ucl object from lua variable at `idx` position escaping JSON strings
585 * @see ucl_object_push_lua for conversion definitions
586 * @param {lua_state} L lua state machine pointer
587 * @param {int} idx index where the source variable is placed
588 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
589 * this object thus needs to be unref'ed after usage.
590 */
591 ucl_object_t *
ucl_object_lua_import_escape(lua_State * L,int idx)592 ucl_object_lua_import_escape (lua_State *L, int idx)
593 {
594 ucl_object_t *obj;
595 int t;
596
597 t = lua_type (L, idx);
598 switch (t) {
599 case LUA_TTABLE:
600 obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);
601 break;
602 default:
603 obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);
604 break;
605 }
606
607 return obj;
608 }
609
610 static int
lua_ucl_to_string(lua_State * L,const ucl_object_t * obj,enum ucl_emitter type)611 lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
612 {
613 unsigned char *result;
614 size_t outlen;
615
616 result = ucl_object_emit_len (obj, type, &outlen);
617
618 if (result != NULL) {
619 lua_pushlstring (L, (const char *)result, outlen);
620 free (result);
621 }
622 else {
623 lua_pushnil (L);
624 }
625
626 return 1;
627 }
628
629 static int
lua_ucl_parser_init(lua_State * L)630 lua_ucl_parser_init (lua_State *L)
631 {
632 struct ucl_parser *parser, **pparser;
633 int flags = UCL_PARSER_NO_FILEVARS;
634
635 if (lua_gettop (L) >= 1) {
636 flags = lua_tonumber (L, 1);
637 }
638
639 parser = ucl_parser_new (flags);
640 if (parser == NULL) {
641 lua_pushnil (L);
642 }
643
644 pparser = lua_newuserdata (L, sizeof (parser));
645 *pparser = parser;
646 luaL_getmetatable (L, PARSER_META);
647 lua_setmetatable (L, -2);
648
649 return 1;
650 }
651
652 static struct ucl_parser *
lua_ucl_parser_get(lua_State * L,int index)653 lua_ucl_parser_get (lua_State *L, int index)
654 {
655 return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
656 }
657
658 static ucl_object_t *
lua_ucl_object_get(lua_State * L,int index)659 lua_ucl_object_get (lua_State *L, int index)
660 {
661 return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
662 }
663
664 static void
lua_ucl_push_opaque(lua_State * L,ucl_object_t * obj)665 lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
666 {
667 ucl_object_t **pobj;
668
669 pobj = lua_newuserdata (L, sizeof (*pobj));
670 *pobj = obj;
671 luaL_getmetatable (L, OBJECT_META);
672 lua_setmetatable (L, -2);
673 }
674
675 static inline enum ucl_parse_type
lua_ucl_str_to_parse_type(const char * str)676 lua_ucl_str_to_parse_type (const char *str)
677 {
678 enum ucl_parse_type type = UCL_PARSE_UCL;
679
680 if (str != NULL) {
681 if (strcasecmp (str, "msgpack") == 0) {
682 type = UCL_PARSE_MSGPACK;
683 }
684 else if (strcasecmp (str, "sexp") == 0 ||
685 strcasecmp (str, "csexp") == 0) {
686 type = UCL_PARSE_CSEXP;
687 }
688 else if (strcasecmp (str, "auto") == 0) {
689 type = UCL_PARSE_AUTO;
690 }
691 }
692
693 return type;
694 }
695
696 /***
697 * @method parser:parse_file(name)
698 * Parse UCL object from file.
699 * @param {string} name filename to parse
700 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
701 @example
702 local parser = ucl.parser()
703 local res,err = parser:parse_file('/some/file.conf')
704
705 if not res then
706 print('parser error: ' .. err)
707 else
708 -- Do something with object
709 end
710 */
711 static int
lua_ucl_parser_parse_file(lua_State * L)712 lua_ucl_parser_parse_file (lua_State *L)
713 {
714 struct ucl_parser *parser;
715 const char *file;
716 int ret = 2;
717
718 parser = lua_ucl_parser_get (L, 1);
719 file = luaL_checkstring (L, 2);
720
721 if (parser != NULL && file != NULL) {
722 if (ucl_parser_add_file (parser, file)) {
723 lua_pushboolean (L, true);
724 ret = 1;
725 }
726 else {
727 lua_pushboolean (L, false);
728 lua_pushstring (L, ucl_parser_get_error (parser));
729 }
730 }
731 else {
732 lua_pushboolean (L, false);
733 lua_pushstring (L, "invalid arguments");
734 }
735
736 return ret;
737 }
738
739 /***
740 * @method parser:register_variable(name, value)
741 * Register parser variable
742 * @param {string} name name of variable
743 * @param {string} value value of variable
744 * @return {bool} success
745 @example
746 local parser = ucl.parser()
747 local res = parser:register_variable('CONFDIR', '/etc/foo')
748 */
749 static int
lua_ucl_parser_register_variable(lua_State * L)750 lua_ucl_parser_register_variable (lua_State *L)
751 {
752 struct ucl_parser *parser;
753 const char *name, *value;
754 int ret = 2;
755
756 parser = lua_ucl_parser_get (L, 1);
757 name = luaL_checkstring (L, 2);
758 value = luaL_checkstring (L, 3);
759
760 if (parser != NULL && name != NULL && value != NULL) {
761 ucl_parser_register_variable (parser, name, value);
762 lua_pushboolean (L, true);
763 ret = 1;
764 }
765 else {
766 return luaL_error (L, "invalid arguments");
767 }
768
769 return ret;
770 }
771
772 /***
773 * @method parser:register_variables(vars)
774 * Register parser variables
775 * @param {table} vars names/values of variables
776 * @return {bool} success
777 @example
778 local parser = ucl.parser()
779 local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'})
780 */
781 static int
lua_ucl_parser_register_variables(lua_State * L)782 lua_ucl_parser_register_variables (lua_State *L)
783 {
784 struct ucl_parser *parser;
785 const char *name, *value;
786 int ret = 2;
787
788 parser = lua_ucl_parser_get (L, 1);
789
790 if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) {
791 for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
792 lua_pushvalue (L, -2);
793 name = luaL_checkstring (L, -1);
794 value = luaL_checkstring (L, -2);
795 ucl_parser_register_variable (parser, name, value);
796 lua_pop (L, 1);
797 }
798
799 lua_pushboolean (L, true);
800 ret = 1;
801 }
802 else {
803 return luaL_error (L, "invalid arguments");
804 }
805
806 return ret;
807 }
808
809 /***
810 * @method parser:parse_string(input)
811 * Parse UCL object from file.
812 * @param {string} input string to parse
813 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
814 */
815 static int
lua_ucl_parser_parse_string(lua_State * L)816 lua_ucl_parser_parse_string (lua_State *L)
817 {
818 struct ucl_parser *parser;
819 const char *string;
820 size_t llen;
821 enum ucl_parse_type type = UCL_PARSE_UCL;
822 int ret = 2;
823
824 parser = lua_ucl_parser_get (L, 1);
825 string = luaL_checklstring (L, 2, &llen);
826
827 if (lua_type (L, 3) == LUA_TSTRING) {
828 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
829 }
830
831 if (parser != NULL && string != NULL) {
832 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string,
833 llen, 0, UCL_DUPLICATE_APPEND, type)) {
834 lua_pushboolean (L, true);
835 ret = 1;
836 }
837 else {
838 lua_pushboolean (L, false);
839 lua_pushstring (L, ucl_parser_get_error (parser));
840 }
841 }
842 else {
843 lua_pushboolean (L, false);
844 lua_pushstring (L, "invalid arguments");
845 }
846
847 return ret;
848 }
849
850 /***
851 * @method parser:parse_text(input)
852 * Parse UCL object from text object (Rspamd specific).
853 * @param {rspamd_text} input text to parse
854 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
855 */
856 static int
lua_ucl_parser_parse_text(lua_State * L)857 lua_ucl_parser_parse_text (lua_State *L)
858 {
859 struct ucl_parser *parser;
860 struct _rspamd_lua_text *t;
861 enum ucl_parse_type type = UCL_PARSE_UCL;
862 int ret = 2;
863
864 parser = lua_ucl_parser_get (L, 1);
865
866 if (lua_type (L, 2) == LUA_TUSERDATA) {
867 t = lua_touserdata (L, 2);
868 }
869 else {
870 const gchar *s;
871 gsize len;
872 static struct _rspamd_lua_text st_t;
873
874 s = lua_tolstring (L, 2, &len);
875 st_t.start = s;
876 st_t.len = len;
877
878 t = &st_t;
879 }
880
881 if (lua_type (L, 3) == LUA_TSTRING) {
882 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
883 }
884
885 if (parser != NULL && t != NULL) {
886 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start,
887 t->len, 0, UCL_DUPLICATE_APPEND, type)) {
888 lua_pushboolean (L, true);
889 ret = 1;
890 }
891 else {
892 lua_pushboolean (L, false);
893 lua_pushstring (L, ucl_parser_get_error (parser));
894 }
895 }
896 else {
897 lua_pushboolean (L, false);
898 lua_pushstring (L, "invalid arguments");
899 }
900
901 return ret;
902 }
903
904 /***
905 * @method parser:get_object()
906 * Get top object from parser and export it to lua representation.
907 * @return {variant or nil} ucl object as lua native variable
908 */
909 static int
lua_ucl_parser_get_object(lua_State * L)910 lua_ucl_parser_get_object (lua_State *L)
911 {
912 struct ucl_parser *parser;
913 ucl_object_t *obj;
914 int ret = 1;
915
916 parser = lua_ucl_parser_get (L, 1);
917 obj = ucl_parser_get_object (parser);
918
919 if (obj != NULL) {
920 ret = ucl_object_push_lua (L, obj, false);
921 /* no need to keep reference */
922 ucl_object_unref (obj);
923 }
924 else {
925 lua_pushnil (L);
926 }
927
928 return ret;
929 }
930
931 /***
932 * @method parser:get_object_wrapped()
933 * Get top object from parser and export it to userdata object without
934 * unwrapping to lua.
935 * @return {ucl.object or nil} ucl object wrapped variable
936 */
937 static int
lua_ucl_parser_get_object_wrapped(lua_State * L)938 lua_ucl_parser_get_object_wrapped (lua_State *L)
939 {
940 struct ucl_parser *parser;
941 ucl_object_t *obj;
942 int ret = 1;
943
944 parser = lua_ucl_parser_get (L, 1);
945 obj = ucl_parser_get_object (parser);
946
947 if (obj != NULL) {
948 lua_ucl_push_opaque (L, obj);
949 }
950 else {
951 lua_pushnil (L);
952 }
953
954 return ret;
955 }
956
957 /***
958 * @method parser:validate(schema)
959 * Validates the top object in the parser against schema. Schema might be
960 * another object or a string that represents file to load schema from.
961 *
962 * @param {string/table} schema input schema
963 * @return {result,err} two values: boolean result and the corresponding error
964 *
965 */
966 static int
lua_ucl_parser_validate(lua_State * L)967 lua_ucl_parser_validate (lua_State *L)
968 {
969 struct ucl_parser *parser, *schema_parser;
970 ucl_object_t *schema;
971 const char *schema_file;
972 struct ucl_schema_error err;
973
974 parser = lua_ucl_parser_get (L, 1);
975
976 if (parser && parser->top_obj) {
977 if (lua_type (L, 2) == LUA_TTABLE) {
978 schema = ucl_object_lua_import (L, 2);
979
980 if (schema == NULL) {
981 lua_pushboolean (L, false);
982 lua_pushstring (L, "cannot load schema from lua table");
983
984 return 2;
985 }
986 }
987 else if (lua_type (L, 2) == LUA_TSTRING) {
988 schema_parser = ucl_parser_new (0);
989 schema_file = luaL_checkstring (L, 2);
990
991 if (!ucl_parser_add_file (schema_parser, schema_file)) {
992 lua_pushboolean (L, false);
993 lua_pushfstring (L, "cannot parse schema file \"%s\": "
994 "%s", schema_file, ucl_parser_get_error (parser));
995 ucl_parser_free (schema_parser);
996
997 return 2;
998 }
999
1000 schema = ucl_parser_get_object (schema_parser);
1001 ucl_parser_free (schema_parser);
1002 }
1003 else {
1004 lua_pushboolean (L, false);
1005 lua_pushstring (L, "invalid schema argument");
1006
1007 return 2;
1008 }
1009
1010 if (!ucl_object_validate (schema, parser->top_obj, &err)) {
1011 lua_pushboolean (L, false);
1012 lua_pushfstring (L, "validation error: "
1013 "%s", err.msg);
1014 }
1015 else {
1016 lua_pushboolean (L, true);
1017 lua_pushnil (L);
1018 }
1019
1020 ucl_object_unref (schema);
1021 }
1022 else {
1023 lua_pushboolean (L, false);
1024 lua_pushstring (L, "invalid parser or empty top object");
1025 }
1026
1027 return 2;
1028 }
1029
1030 static int
lua_ucl_parser_gc(lua_State * L)1031 lua_ucl_parser_gc (lua_State *L)
1032 {
1033 struct ucl_parser *parser;
1034
1035 parser = lua_ucl_parser_get (L, 1);
1036 ucl_parser_free (parser);
1037
1038 return 0;
1039 }
1040
1041 /***
1042 * @method object:unwrap()
1043 * Unwraps opaque ucl object to the native lua object (performing copying)
1044 * @return {variant} any lua object
1045 */
1046 static int
lua_ucl_object_unwrap(lua_State * L)1047 lua_ucl_object_unwrap (lua_State *L)
1048 {
1049 ucl_object_t *obj;
1050
1051 obj = lua_ucl_object_get (L, 1);
1052
1053 if (obj) {
1054 ucl_object_push_lua (L, obj, true);
1055 }
1056 else {
1057 lua_pushnil (L);
1058 }
1059
1060 return 1;
1061 }
1062
1063 static inline enum ucl_emitter
lua_ucl_str_to_emit_type(const char * strtype)1064 lua_ucl_str_to_emit_type (const char *strtype)
1065 {
1066 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
1067
1068 if (strcasecmp (strtype, "json") == 0) {
1069 format = UCL_EMIT_JSON;
1070 }
1071 else if (strcasecmp (strtype, "json-compact") == 0) {
1072 format = UCL_EMIT_JSON_COMPACT;
1073 }
1074 else if (strcasecmp (strtype, "yaml") == 0) {
1075 format = UCL_EMIT_YAML;
1076 }
1077 else if (strcasecmp (strtype, "config") == 0 ||
1078 strcasecmp (strtype, "ucl") == 0) {
1079 format = UCL_EMIT_CONFIG;
1080 }
1081
1082 return format;
1083 }
1084
1085 /***
1086 * @method object:tostring(type)
1087 * Unwraps opaque ucl object to string (json by default). Optionally you can
1088 * specify output format:
1089 *
1090 * - `json` - fine printed json
1091 * - `json-compact` - compacted json
1092 * - `config` - fine printed configuration
1093 * - `ucl` - same as `config`
1094 * - `yaml` - embedded yaml
1095 * @param {string} type optional
1096 * @return {string} string representation of the opaque ucl object
1097 */
1098 static int
lua_ucl_object_tostring(lua_State * L)1099 lua_ucl_object_tostring (lua_State *L)
1100 {
1101 ucl_object_t *obj;
1102 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
1103
1104 obj = lua_ucl_object_get (L, 1);
1105
1106 if (obj) {
1107 if (lua_gettop (L) > 1) {
1108 if (lua_type (L, 2) == LUA_TSTRING) {
1109 const char *strtype = lua_tostring (L, 2);
1110
1111 format = lua_ucl_str_to_emit_type (strtype);
1112 }
1113 }
1114
1115 return lua_ucl_to_string (L, obj, format);
1116 }
1117 else {
1118 lua_pushnil (L);
1119 }
1120
1121 return 1;
1122 }
1123
1124 /***
1125 * @method object:validate(schema[, path[, ext_refs]])
1126 * Validates the given ucl object using schema object represented as another
1127 * opaque ucl object. You can also specify path in the form `#/path/def` to
1128 * specify the specific schema element to perform validation.
1129 *
1130 * @param {ucl.object} schema schema object
1131 * @param {string} path optional path for validation procedure
1132 * @return {result,err} two values: boolean result and the corresponding
1133 * error, if `ext_refs` are also specified, then they are returned as opaque
1134 * ucl object as {result,err,ext_refs}
1135 */
1136 static int
lua_ucl_object_validate(lua_State * L)1137 lua_ucl_object_validate (lua_State *L)
1138 {
1139 ucl_object_t *obj, *schema, *ext_refs = NULL;
1140 const ucl_object_t *schema_elt;
1141 bool res = false;
1142 struct ucl_schema_error err;
1143 const char *path = NULL;
1144
1145 obj = lua_ucl_object_get (L, 1);
1146 schema = lua_ucl_object_get (L, 2);
1147
1148 if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
1149 if (lua_gettop (L) > 2) {
1150 if (lua_type (L, 3) == LUA_TSTRING) {
1151 path = lua_tostring (L, 3);
1152 if (path[0] == '#') {
1153 path++;
1154 }
1155 }
1156 else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) ==
1157 LUA_TTABLE) {
1158 /* External refs */
1159 ext_refs = lua_ucl_object_get (L, 3);
1160 }
1161
1162 if (lua_gettop (L) > 3) {
1163 if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) ==
1164 LUA_TTABLE) {
1165 /* External refs */
1166 ext_refs = lua_ucl_object_get (L, 4);
1167 }
1168 }
1169 }
1170
1171 if (path) {
1172 schema_elt = ucl_object_lookup_path_char (schema, path, '/');
1173 }
1174 else {
1175 /* Use the top object */
1176 schema_elt = schema;
1177 }
1178
1179 if (schema_elt) {
1180 res = ucl_object_validate_root_ext (schema_elt, obj, schema,
1181 ext_refs, &err);
1182
1183 if (res) {
1184 lua_pushboolean (L, res);
1185 lua_pushnil (L);
1186
1187 if (ext_refs) {
1188 lua_ucl_push_opaque (L, ext_refs);
1189 }
1190 }
1191 else {
1192 lua_pushboolean (L, res);
1193 lua_pushfstring (L, "validation error: %s", err.msg);
1194
1195 if (ext_refs) {
1196 lua_ucl_push_opaque (L, ext_refs);
1197 }
1198 }
1199 }
1200 else {
1201 lua_pushboolean (L, res);
1202
1203 lua_pushfstring (L, "cannot find the requested path: %s", path);
1204
1205 if (ext_refs) {
1206 lua_ucl_push_opaque (L, ext_refs);
1207 }
1208 }
1209 }
1210 else {
1211 lua_pushboolean (L, res);
1212 lua_pushstring (L, "invalid object or schema");
1213 }
1214
1215 if (ext_refs) {
1216 return 3;
1217 }
1218
1219 return 2;
1220 }
1221
1222 static int
lua_ucl_object_gc(lua_State * L)1223 lua_ucl_object_gc (lua_State *L)
1224 {
1225 ucl_object_t *obj;
1226
1227 obj = lua_ucl_object_get (L, 1);
1228
1229 ucl_object_unref (obj);
1230
1231 return 0;
1232 }
1233
1234 static void
lua_ucl_parser_mt(lua_State * L)1235 lua_ucl_parser_mt (lua_State *L)
1236 {
1237 luaL_newmetatable (L, PARSER_META);
1238
1239 lua_pushvalue(L, -1);
1240 lua_setfield(L, -2, "__index");
1241
1242 lua_pushcfunction (L, lua_ucl_parser_gc);
1243 lua_setfield (L, -2, "__gc");
1244
1245 lua_pushcfunction (L, lua_ucl_parser_parse_file);
1246 lua_setfield (L, -2, "parse_file");
1247
1248 lua_pushcfunction (L, lua_ucl_parser_parse_string);
1249 lua_setfield (L, -2, "parse_string");
1250
1251 lua_pushcfunction (L, lua_ucl_parser_parse_text);
1252 lua_setfield (L, -2, "parse_text");
1253
1254 lua_pushcfunction (L, lua_ucl_parser_register_variable);
1255 lua_setfield (L, -2, "register_variable");
1256
1257 lua_pushcfunction (L, lua_ucl_parser_register_variables);
1258 lua_setfield (L, -2, "register_variables");
1259
1260 lua_pushcfunction (L, lua_ucl_parser_get_object);
1261 lua_setfield (L, -2, "get_object");
1262
1263 lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
1264 lua_setfield (L, -2, "get_object_wrapped");
1265
1266 lua_pushcfunction (L, lua_ucl_parser_validate);
1267 lua_setfield (L, -2, "validate");
1268
1269 lua_pop (L, 1);
1270 }
1271
1272 static void
lua_ucl_object_mt(lua_State * L)1273 lua_ucl_object_mt (lua_State *L)
1274 {
1275 luaL_newmetatable (L, OBJECT_META);
1276
1277 lua_pushvalue(L, -1);
1278 lua_setfield(L, -2, "__index");
1279
1280 lua_pushcfunction (L, lua_ucl_object_gc);
1281 lua_setfield (L, -2, "__gc");
1282
1283 lua_pushcfunction (L, lua_ucl_object_tostring);
1284 lua_setfield (L, -2, "__tostring");
1285
1286 lua_pushcfunction (L, lua_ucl_object_tostring);
1287 lua_setfield (L, -2, "tostring");
1288
1289 lua_pushcfunction (L, lua_ucl_object_unwrap);
1290 lua_setfield (L, -2, "unwrap");
1291
1292 lua_pushcfunction (L, lua_ucl_object_unwrap);
1293 lua_setfield (L, -2, "tolua");
1294
1295 lua_pushcfunction (L, lua_ucl_object_validate);
1296 lua_setfield (L, -2, "validate");
1297
1298 lua_pushstring (L, OBJECT_META);
1299 lua_setfield (L, -2, "class");
1300
1301 lua_pop (L, 1);
1302 }
1303
1304 static void
lua_ucl_types_mt(lua_State * L)1305 lua_ucl_types_mt (lua_State *L)
1306 {
1307 luaL_newmetatable (L, UCL_OBJECT_TYPE_META);
1308
1309 lua_pushcfunction (L, lua_ucl_object_tostring);
1310 lua_setfield (L, -2, "__tostring");
1311
1312 lua_pushcfunction (L, lua_ucl_object_tostring);
1313 lua_setfield (L, -2, "tostring");
1314
1315 lua_pushstring (L, UCL_OBJECT_TYPE_META);
1316 lua_setfield (L, -2, "class");
1317
1318 lua_pop (L, 1);
1319
1320 luaL_newmetatable (L, UCL_ARRAY_TYPE_META);
1321
1322 lua_pushcfunction (L, lua_ucl_object_tostring);
1323 lua_setfield (L, -2, "__tostring");
1324
1325 lua_pushcfunction (L, lua_ucl_object_tostring);
1326 lua_setfield (L, -2, "tostring");
1327
1328 lua_pushstring (L, UCL_ARRAY_TYPE_META);
1329 lua_setfield (L, -2, "class");
1330
1331 lua_pop (L, 1);
1332
1333 luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
1334
1335 lua_pushcfunction (L, lua_ucl_object_tostring);
1336 lua_setfield (L, -2, "__tostring");
1337
1338 lua_pushcfunction (L, lua_ucl_object_tostring);
1339 lua_setfield (L, -2, "tostring");
1340
1341 lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META);
1342 lua_setfield (L, -2, "class");
1343
1344 lua_pop (L, 1);
1345 }
1346
1347 static int
lua_ucl_to_json(lua_State * L)1348 lua_ucl_to_json (lua_State *L)
1349 {
1350 ucl_object_t *obj;
1351 int format = UCL_EMIT_JSON;
1352
1353 if (lua_gettop (L) > 1) {
1354 if (lua_toboolean (L, 2)) {
1355 format = UCL_EMIT_JSON_COMPACT;
1356 }
1357 }
1358
1359 obj = ucl_object_lua_import (L, 1);
1360 if (obj != NULL) {
1361 lua_ucl_to_string (L, obj, format);
1362 ucl_object_unref (obj);
1363 }
1364 else {
1365 lua_pushnil (L);
1366 }
1367
1368 return 1;
1369 }
1370
1371 static int
lua_ucl_to_config(lua_State * L)1372 lua_ucl_to_config (lua_State *L)
1373 {
1374 ucl_object_t *obj;
1375
1376 obj = ucl_object_lua_import (L, 1);
1377 if (obj != NULL) {
1378 lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
1379 ucl_object_unref (obj);
1380 }
1381 else {
1382 lua_pushnil (L);
1383 }
1384
1385 return 1;
1386 }
1387
1388 /***
1389 * @function ucl.to_format(var, format)
1390 * Converts lua variable `var` to the specified `format`. Formats supported are:
1391 *
1392 * - `json` - fine printed json
1393 * - `json-compact` - compacted json
1394 * - `config` - fine printed configuration
1395 * - `ucl` - same as `config`
1396 * - `yaml` - embedded yaml
1397 *
1398 * If `var` contains function, they are called during output formatting and if
1399 * they return string value, then this value is used for output.
1400 * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
1401 * @param {string} format any available format
1402 * @return {string} string representation of `var` in the specific `format`.
1403 * @example
1404 local table = {
1405 str = 'value',
1406 num = 100500,
1407 null = ucl.null,
1408 func = function ()
1409 return 'huh'
1410 end
1411 }
1412
1413 print(ucl.to_format(table, 'ucl'))
1414 -- Output:
1415 --[[
1416 num = 100500;
1417 str = "value";
1418 null = null;
1419 func = "huh";
1420 --]]
1421 */
1422 static int
lua_ucl_to_format(lua_State * L)1423 lua_ucl_to_format (lua_State *L)
1424 {
1425 ucl_object_t *obj;
1426 int format = UCL_EMIT_JSON;
1427 bool sort = false;
1428
1429 if (lua_gettop (L) > 1) {
1430 if (lua_type (L, 2) == LUA_TNUMBER) {
1431 format = lua_tonumber (L, 2);
1432 if (format < 0 || format >= UCL_EMIT_YAML) {
1433 lua_pushnil (L);
1434 return 1;
1435 }
1436 }
1437 else if (lua_type (L, 2) == LUA_TSTRING) {
1438 const char *strtype = lua_tostring (L, 2);
1439
1440 if (strcasecmp (strtype, "json") == 0) {
1441 format = UCL_EMIT_JSON;
1442 }
1443 else if (strcasecmp (strtype, "json-compact") == 0) {
1444 format = UCL_EMIT_JSON_COMPACT;
1445 }
1446 else if (strcasecmp (strtype, "yaml") == 0) {
1447 format = UCL_EMIT_YAML;
1448 }
1449 else if (strcasecmp (strtype, "config") == 0 ||
1450 strcasecmp (strtype, "ucl") == 0) {
1451 format = UCL_EMIT_CONFIG;
1452 }
1453 else if (strcasecmp (strtype, "msgpack") == 0 ||
1454 strcasecmp (strtype, "messagepack") == 0) {
1455 format = UCL_EMIT_MSGPACK;
1456 }
1457 }
1458
1459 if (lua_isboolean (L, 3)) {
1460 sort = lua_toboolean (L, 3);
1461 }
1462 }
1463
1464 obj = ucl_object_lua_import (L, 1);
1465
1466 if (obj != NULL) {
1467
1468 if (sort) {
1469 if (ucl_object_type (obj) == UCL_OBJECT) {
1470 ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE);
1471 }
1472 }
1473
1474 lua_ucl_to_string (L, obj, format);
1475 ucl_object_unref (obj);
1476 }
1477 else {
1478 lua_pushnil (L);
1479 }
1480
1481 return 1;
1482 }
1483
1484 static int
lua_ucl_null_tostring(lua_State * L)1485 lua_ucl_null_tostring (lua_State* L)
1486 {
1487 lua_pushstring (L, "null");
1488 return 1;
1489 }
1490
1491 static void
lua_ucl_null_mt(lua_State * L)1492 lua_ucl_null_mt (lua_State *L)
1493 {
1494 luaL_newmetatable (L, NULL_META);
1495
1496 lua_pushcfunction (L, lua_ucl_null_tostring);
1497 lua_setfield (L, -2, "__tostring");
1498
1499 lua_pop (L, 1);
1500 }
1501
1502 int
luaopen_ucl(lua_State * L)1503 luaopen_ucl (lua_State *L)
1504 {
1505 lua_ucl_parser_mt (L);
1506 lua_ucl_null_mt (L);
1507 lua_ucl_object_mt (L);
1508 lua_ucl_types_mt (L);
1509
1510 /* Create the refs weak table: */
1511 lua_createtable (L, 0, 2);
1512 lua_pushliteral (L, "v"); /* tbl, "v" */
1513 lua_setfield (L, -2, "__mode");
1514 lua_pushvalue (L, -1); /* tbl, tbl */
1515 lua_setmetatable (L, -2); /* tbl */
1516 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
1517
1518 lua_newtable (L);
1519
1520 lua_pushcfunction (L, lua_ucl_parser_init);
1521 lua_setfield (L, -2, "parser");
1522
1523 lua_pushcfunction (L, lua_ucl_to_json);
1524 lua_setfield (L, -2, "to_json");
1525
1526 lua_pushcfunction (L, lua_ucl_to_config);
1527 lua_setfield (L, -2, "to_config");
1528
1529 lua_pushcfunction (L, lua_ucl_to_format);
1530 lua_setfield (L, -2, "to_format");
1531
1532 ucl_null = lua_newuserdata (L, 0);
1533 luaL_getmetatable (L, NULL_META);
1534 lua_setmetatable (L, -2);
1535
1536 lua_pushvalue (L, -1);
1537 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
1538
1539 lua_setfield (L, -2, "null");
1540
1541 return 1;
1542 }
1543
1544 struct ucl_lua_funcdata*
ucl_object_toclosure(const ucl_object_t * obj)1545 ucl_object_toclosure (const ucl_object_t *obj)
1546 {
1547 if (obj == NULL || obj->type != UCL_USERDATA) {
1548 return NULL;
1549 }
1550
1551 return (struct ucl_lua_funcdata*)obj->value.ud;
1552 }
1553