]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/lua/lua_ucl.c
Import sqlite3 3.12.1
[FreeBSD/FreeBSD.git] / contrib / libucl / lua / lua_ucl.c
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 "null.emitter.meta"
72 #define OBJECT_META "ucl.object.meta"
73
74 static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
75 static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
76 static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
77 static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
78
79 static void *ucl_null;
80
81 /**
82  * Push a single element of an object to lua
83  * @param L
84  * @param key
85  * @param obj
86  */
87 static void
88 ucl_object_lua_push_element (lua_State *L, const char *key,
89                 const ucl_object_t *obj)
90 {
91         lua_pushstring (L, key);
92         ucl_object_push_lua (L, obj, true);
93         lua_settable (L, -3);
94 }
95
96 static void
97 lua_ucl_userdata_dtor (void *ud)
98 {
99         struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
100
101         luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
102         if (fd->ret != NULL) {
103                 free (fd->ret);
104         }
105         free (fd);
106 }
107
108 static const char *
109 lua_ucl_userdata_emitter (void *ud)
110 {
111         struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
112         const char *out = "";
113
114         lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
115
116         lua_pcall (fd->L, 0, 1, 0);
117         out = lua_tostring (fd->L, -1);
118
119         if (out != NULL) {
120                 /* We need to store temporary string in a more appropriate place */
121                 if (fd->ret) {
122                         free (fd->ret);
123                 }
124                 fd->ret = strdup (out);
125         }
126
127         lua_settop (fd->L, 0);
128
129         return fd->ret;
130 }
131
132 /**
133  * Push a single object to lua
134  * @param L
135  * @param obj
136  * @return
137  */
138 static int
139 ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
140                 bool allow_array)
141 {
142         const ucl_object_t *cur;
143         ucl_object_iter_t it = NULL;
144         int nelt = 0;
145
146         if (allow_array && obj->next != NULL) {
147                 /* Actually we need to push this as an array */
148                 return ucl_object_lua_push_array (L, obj);
149         }
150
151         /* Optimize allocation by preallocation of table */
152         while (ucl_iterate_object (obj, &it, true) != NULL) {
153                 nelt ++;
154         }
155
156         lua_createtable (L, 0, nelt);
157         it = NULL;
158
159         while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
160                 ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
161         }
162
163         return 1;
164 }
165
166 /**
167  * Push an array to lua as table indexed by integers
168  * @param L
169  * @param obj
170  * @return
171  */
172 static int
173 ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
174 {
175         const ucl_object_t *cur;
176         ucl_object_iter_t it;
177         int i = 1, nelt = 0;
178
179         if (obj->type == UCL_ARRAY) {
180                 nelt = obj->len;
181                 it = ucl_object_iterate_new (obj);
182                 lua_createtable (L, nelt, 0);
183
184                 while ((cur = ucl_object_iterate_safe (it, true))) {
185                         ucl_object_push_lua (L, cur, false);
186                         lua_rawseti (L, -2, i);
187                         i ++;
188                 }
189         }
190         else {
191                 /* Optimize allocation by preallocation of table */
192                 LL_FOREACH (obj, cur) {
193                         nelt ++;
194                 }
195
196                 lua_createtable (L, nelt, 0);
197
198                 LL_FOREACH (obj, cur) {
199                         ucl_object_push_lua (L, cur, false);
200                         lua_rawseti (L, -2, i);
201                         i ++;
202                 }
203         }
204
205         return 1;
206 }
207
208 /**
209  * Push a simple object to lua depending on its actual type
210  */
211 static int
212 ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
213                 bool allow_array)
214 {
215         struct ucl_lua_funcdata *fd;
216
217         if (allow_array && obj->next != NULL) {
218                 /* Actually we need to push this as an array */
219                 return ucl_object_lua_push_array (L, obj);
220         }
221
222         switch (obj->type) {
223         case UCL_BOOLEAN:
224                 lua_pushboolean (L, ucl_obj_toboolean (obj));
225                 break;
226         case UCL_STRING:
227                 lua_pushstring (L, ucl_obj_tostring (obj));
228                 break;
229         case UCL_INT:
230 #if LUA_VERSION_NUM >= 501
231                 lua_pushinteger (L, ucl_obj_toint (obj));
232 #else
233                 lua_pushnumber (L, ucl_obj_toint (obj));
234 #endif
235                 break;
236         case UCL_FLOAT:
237         case UCL_TIME:
238                 lua_pushnumber (L, ucl_obj_todouble (obj));
239                 break;
240         case UCL_NULL:
241                 lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
242                 break;
243         case UCL_USERDATA:
244                 fd = (struct ucl_lua_funcdata *)obj->value.ud;
245                 lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
246                 break;
247         default:
248                 lua_pushnil (L);
249                 break;
250         }
251
252         return 1;
253 }
254
255 /***
256  * @function ucl_object_push_lua(L, obj, allow_array)
257  * This is a `C` function to push `UCL` object as lua variable. This function
258  * converts `obj` to lua representation using the following conversions:
259  *
260  * - *scalar* values are directly presented by lua objects
261  * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
262  * this can be used to pass functions from lua to c and vice-versa
263  * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
264  * - *objects* are converted to lua tables with string indicies
265  * @param {lua_State} L lua state pointer
266  * @param {ucl_object_t} obj object to push
267  * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
268  * @return {int} `1` if an object is pushed to lua
269  */
270 int
271 ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
272 {
273         switch (obj->type) {
274         case UCL_OBJECT:
275                 return ucl_object_lua_push_object (L, obj, allow_array);
276         case UCL_ARRAY:
277                 return ucl_object_lua_push_array (L, obj);
278         default:
279                 return ucl_object_lua_push_scalar (L, obj, allow_array);
280         }
281 }
282
283 /**
284  * Parse lua table into object top
285  * @param L
286  * @param top
287  * @param idx
288  */
289 static ucl_object_t *
290 ucl_object_lua_fromtable (lua_State *L, int idx)
291 {
292         ucl_object_t *obj, *top = NULL;
293         size_t keylen;
294         const char *k;
295         bool is_array = true;
296         int max = INT_MIN;
297
298         if (idx < 0) {
299                 /* For negative indicies we want to invert them */
300                 idx = lua_gettop (L) + idx + 1;
301         }
302         /* Check for array */
303         lua_pushnil (L);
304         while (lua_next (L, idx) != 0) {
305                 if (lua_type (L, -2) == LUA_TNUMBER) {
306                         double num = lua_tonumber (L, -2);
307                         if (num == (int)num) {
308                                 if (num > max) {
309                                         max = num;
310                                 }
311                         }
312                         else {
313                                 /* Keys are not integer */
314                                 lua_pop (L, 2);
315                                 is_array = false;
316                                 break;
317                         }
318                 }
319                 else {
320                         /* Keys are not numeric */
321                         lua_pop (L, 2);
322                         is_array = false;
323                         break;
324                 }
325                 lua_pop (L, 1);
326         }
327
328         /* Table iterate */
329         if (is_array) {
330                 int i;
331
332                 top = ucl_object_typed_new (UCL_ARRAY);
333                 for (i = 1; i <= max; i ++) {
334                         lua_pushinteger (L, i);
335                         lua_gettable (L, idx);
336                         obj = ucl_object_lua_fromelt (L, lua_gettop (L));
337                         if (obj != NULL) {
338                                 ucl_array_append (top, obj);
339                         }
340                         lua_pop (L, 1);
341                 }
342         }
343         else {
344                 lua_pushnil (L);
345                 top = ucl_object_typed_new (UCL_OBJECT);
346                 while (lua_next (L, idx) != 0) {
347                         /* copy key to avoid modifications */
348                         k = lua_tolstring (L, -2, &keylen);
349                         obj = ucl_object_lua_fromelt (L, lua_gettop (L));
350
351                         if (obj != NULL) {
352                                 ucl_object_insert_key (top, obj, k, keylen, true);
353                         }
354                         lua_pop (L, 1);
355                 }
356         }
357
358         return top;
359 }
360
361 /**
362  * Get a single element from lua to object obj
363  * @param L
364  * @param obj
365  * @param idx
366  */
367 static ucl_object_t *
368 ucl_object_lua_fromelt (lua_State *L, int idx)
369 {
370         int type;
371         double num;
372         ucl_object_t *obj = NULL;
373         struct ucl_lua_funcdata *fd;
374
375         type = lua_type (L, idx);
376
377         switch (type) {
378         case LUA_TSTRING:
379                 obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
380                 break;
381         case LUA_TNUMBER:
382                 num = lua_tonumber (L, idx);
383                 if (num == (int64_t)num) {
384                         obj = ucl_object_fromint (num);
385                 }
386                 else {
387                         obj = ucl_object_fromdouble (num);
388                 }
389                 break;
390         case LUA_TBOOLEAN:
391                 obj = ucl_object_frombool (lua_toboolean (L, idx));
392                 break;
393         case LUA_TUSERDATA:
394                 if (lua_topointer (L, idx) == ucl_null) {
395                         obj = ucl_object_typed_new (UCL_NULL);
396                 }
397                 break;
398         case LUA_TTABLE:
399         case LUA_TFUNCTION:
400         case LUA_TTHREAD:
401                 if (luaL_getmetafield (L, idx, "__gen_ucl")) {
402                         if (lua_isfunction (L, -1)) {
403                                 lua_settop (L, 3); /* gen, obj, func */
404                                 lua_insert (L, 1); /* func, gen, obj */
405                                 lua_insert (L, 2); /* func, obj, gen */
406                                 lua_call(L, 2, 1);
407                                 obj = ucl_object_lua_fromelt (L, 1);
408                         }
409                         lua_pop (L, 2);
410                 }
411                 else {
412                         if (type == LUA_TTABLE) {
413                                 obj = ucl_object_lua_fromtable (L, idx);
414                         }
415                         else if (type == LUA_TFUNCTION) {
416                                 fd = malloc (sizeof (*fd));
417                                 if (fd != NULL) {
418                                         lua_pushvalue (L, idx);
419                                         fd->L = L;
420                                         fd->ret = NULL;
421                                         fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
422
423                                         obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
424                                                         lua_ucl_userdata_emitter);
425                                         obj->type = UCL_USERDATA;
426                                         obj->value.ud = (void *)fd;
427                                 }
428                         }
429                 }
430                 break;
431         }
432
433         return obj;
434 }
435
436 /**
437  * @function ucl_object_lua_import(L, idx)
438  * Extracts ucl object from lua variable at `idx` position,
439  * @see ucl_object_push_lua for conversion definitions
440  * @param {lua_state} L lua state machine pointer
441  * @param {int} idx index where the source variable is placed
442  * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
443  * this object thus needs to be unref'ed after usage.
444  */
445 ucl_object_t *
446 ucl_object_lua_import (lua_State *L, int idx)
447 {
448         ucl_object_t *obj;
449         int t;
450
451         t = lua_type (L, idx);
452         switch (t) {
453         case LUA_TTABLE:
454                 obj = ucl_object_lua_fromtable (L, idx);
455                 break;
456         default:
457                 obj = ucl_object_lua_fromelt (L, idx);
458                 break;
459         }
460
461         return obj;
462 }
463
464 static int
465 lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
466 {
467         unsigned char *result;
468
469         result = ucl_object_emit (obj, type);
470
471         if (result != NULL) {
472                 lua_pushstring (L, (const char *)result);
473                 free (result);
474         }
475         else {
476                 lua_pushnil (L);
477         }
478
479         return 1;
480 }
481
482 static int
483 lua_ucl_parser_init (lua_State *L)
484 {
485         struct ucl_parser *parser, **pparser;
486         int flags = 0;
487
488         if (lua_gettop (L) >= 1) {
489                 flags = lua_tonumber (L, 1);
490         }
491
492         parser = ucl_parser_new (flags);
493         if (parser == NULL) {
494                 lua_pushnil (L);
495         }
496
497         pparser = lua_newuserdata (L, sizeof (parser));
498         *pparser = parser;
499         luaL_getmetatable (L, PARSER_META);
500         lua_setmetatable (L, -2);
501
502         return 1;
503 }
504
505 static struct ucl_parser *
506 lua_ucl_parser_get (lua_State *L, int index)
507 {
508         return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
509 }
510
511 static ucl_object_t *
512 lua_ucl_object_get (lua_State *L, int index)
513 {
514         return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
515 }
516
517 /***
518  * @method parser:parse_file(name)
519  * Parse UCL object from file.
520  * @param {string} name filename to parse
521  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
522 @example
523 local parser = ucl.parser()
524 local res,err = parser:parse_file('/some/file.conf')
525
526 if not res then
527         print('parser error: ' .. err)
528 else
529         -- Do something with object
530 end
531  */
532 static int
533 lua_ucl_parser_parse_file (lua_State *L)
534 {
535         struct ucl_parser *parser;
536         const char *file;
537         int ret = 2;
538
539         parser = lua_ucl_parser_get (L, 1);
540         file = luaL_checkstring (L, 2);
541
542         if (parser != NULL && file != NULL) {
543                 if (ucl_parser_add_file (parser, file)) {
544                         lua_pushboolean (L, true);
545                         ret = 1;
546                 }
547                 else {
548                         lua_pushboolean (L, false);
549                         lua_pushstring (L, ucl_parser_get_error (parser));
550                 }
551         }
552         else {
553                 lua_pushboolean (L, false);
554                 lua_pushstring (L, "invalid arguments");
555         }
556
557         return ret;
558 }
559
560 /***
561  * @method parser:parse_string(input)
562  * Parse UCL object from file.
563  * @param {string} input string to parse
564  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
565  */
566 static int
567 lua_ucl_parser_parse_string (lua_State *L)
568 {
569         struct ucl_parser *parser;
570         const char *string;
571         size_t llen;
572         int ret = 2;
573
574         parser = lua_ucl_parser_get (L, 1);
575         string = luaL_checklstring (L, 2, &llen);
576
577         if (parser != NULL && string != NULL) {
578                 if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) {
579                         lua_pushboolean (L, true);
580                         ret = 1;
581                 }
582                 else {
583                         lua_pushboolean (L, false);
584                         lua_pushstring (L, ucl_parser_get_error (parser));
585                 }
586         }
587         else {
588                 lua_pushboolean (L, false);
589                 lua_pushstring (L, "invalid arguments");
590         }
591
592         return ret;
593 }
594
595 /***
596  * @method parser:get_object()
597  * Get top object from parser and export it to lua representation.
598  * @return {variant or nil} ucl object as lua native variable
599  */
600 static int
601 lua_ucl_parser_get_object (lua_State *L)
602 {
603         struct ucl_parser *parser;
604         ucl_object_t *obj;
605         int ret = 1;
606
607         parser = lua_ucl_parser_get (L, 1);
608         obj = ucl_parser_get_object (parser);
609
610         if (obj != NULL) {
611                 ret = ucl_object_push_lua (L, obj, false);
612                 /* no need to keep reference */
613                 ucl_object_unref (obj);
614         }
615         else {
616                 lua_pushnil (L);
617         }
618
619         return ret;
620 }
621
622 /***
623  * @method parser:get_object_wrapped()
624  * Get top object from parser and export it to userdata object without
625  * unwrapping to lua.
626  * @return {ucl.object or nil} ucl object wrapped variable
627  */
628 static int
629 lua_ucl_parser_get_object_wrapped (lua_State *L)
630 {
631         struct ucl_parser *parser;
632         ucl_object_t *obj, **pobj;
633         int ret = 1;
634
635         parser = lua_ucl_parser_get (L, 1);
636         obj = ucl_parser_get_object (parser);
637
638         if (obj != NULL) {
639                 pobj = lua_newuserdata (L, sizeof (*pobj));
640                 *pobj = obj;
641                 luaL_getmetatable (L, OBJECT_META);
642                 lua_setmetatable (L, -2);
643         }
644         else {
645                 lua_pushnil (L);
646         }
647
648         return ret;
649 }
650
651 /***
652  * @method parser:validate(schema)
653  * Validates the top object in the parser against schema. Schema might be
654  * another object or a string that represents file to load schema from.
655  *
656  * @param {string/table} schema input schema
657  * @return {result,err} two values: boolean result and the corresponding error
658  *
659  */
660 static int
661 lua_ucl_parser_validate (lua_State *L)
662 {
663         struct ucl_parser *parser, *schema_parser;
664         ucl_object_t *schema;
665         const char *schema_file;
666         struct ucl_schema_error err;
667
668         parser = lua_ucl_parser_get (L, 1);
669
670         if (parser && parser->top_obj) {
671                 if (lua_type (L, 2) == LUA_TTABLE) {
672                         schema = ucl_object_lua_import (L, 2);
673
674                         if (schema == NULL) {
675                                 lua_pushboolean (L, false);
676                                 lua_pushstring (L, "cannot load schema from lua table");
677
678                                 return 2;
679                         }
680                 }
681                 else if (lua_type (L, 2) == LUA_TSTRING) {
682                         schema_parser = ucl_parser_new (0);
683                         schema_file = luaL_checkstring (L, 2);
684
685                         if (!ucl_parser_add_file (schema_parser, schema_file)) {
686                                 lua_pushboolean (L, false);
687                                 lua_pushfstring (L, "cannot parse schema file \"%s\": "
688                                                 "%s", schema_file, ucl_parser_get_error (parser));
689                                 ucl_parser_free (schema_parser);
690
691                                 return 2;
692                         }
693
694                         schema = ucl_parser_get_object (schema_parser);
695                         ucl_parser_free (schema_parser);
696                 }
697                 else {
698                         lua_pushboolean (L, false);
699                         lua_pushstring (L, "invalid schema argument");
700
701                         return 2;
702                 }
703
704                 if (!ucl_object_validate (schema, parser->top_obj, &err)) {
705                         lua_pushboolean (L, false);
706                         lua_pushfstring (L, "validation error: "
707                                         "%s", err.msg);
708                 }
709                 else {
710                         lua_pushboolean (L, true);
711                         lua_pushnil (L);
712                 }
713
714                 ucl_object_unref (schema);
715         }
716         else {
717                 lua_pushboolean (L, false);
718                 lua_pushstring (L, "invalid parser or empty top object");
719         }
720
721         return 2;
722 }
723
724 static int
725 lua_ucl_parser_gc (lua_State *L)
726 {
727         struct ucl_parser *parser;
728
729         parser = lua_ucl_parser_get (L, 1);
730         ucl_parser_free (parser);
731
732         return 0;
733 }
734
735 /***
736  * @method object:unwrap()
737  * Unwraps opaque ucl object to the native lua object (performing copying)
738  * @return {variant} any lua object
739  */
740 static int
741 lua_ucl_object_unwrap (lua_State *L)
742 {
743         ucl_object_t *obj;
744
745         obj = lua_ucl_object_get (L, 1);
746
747         if (obj) {
748                 ucl_object_push_lua (L, obj, true);
749         }
750         else {
751                 lua_pushnil (L);
752         }
753
754         return 1;
755 }
756
757 /***
758  * @method object:tostring(type)
759  * Unwraps opaque ucl object to string (json by default). Optionally you can
760  * specify output format:
761  *
762  * - `json` - fine printed json
763  * - `json-compact` - compacted json
764  * - `config` - fine printed configuration
765  * - `ucl` - same as `config`
766  * - `yaml` - embedded yaml
767  * @param {string} type optional
768  * @return {string} string representation of the opaque ucl object
769  */
770 static int
771 lua_ucl_object_tostring (lua_State *L)
772 {
773         ucl_object_t *obj;
774         enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
775
776         obj = lua_ucl_object_get (L, 1);
777
778         if (obj) {
779                 if (lua_gettop (L) > 1) {
780                         if (lua_type (L, 2) == LUA_TSTRING) {
781                                 const char *strtype = lua_tostring (L, 2);
782
783                                 if (strcasecmp (strtype, "json") == 0) {
784                                         format = UCL_EMIT_JSON;
785                                 }
786                                 else if (strcasecmp (strtype, "json-compact") == 0) {
787                                         format = UCL_EMIT_JSON_COMPACT;
788                                 }
789                                 else if (strcasecmp (strtype, "yaml") == 0) {
790                                         format = UCL_EMIT_YAML;
791                                 }
792                                 else if (strcasecmp (strtype, "config") == 0 ||
793                                                 strcasecmp (strtype, "ucl") == 0) {
794                                         format = UCL_EMIT_CONFIG;
795                                 }
796                         }
797                 }
798
799                 return lua_ucl_to_string (L, obj, format);
800         }
801         else {
802                 lua_pushnil (L);
803         }
804
805         return 1;
806 }
807
808 /***
809  * @method object:validate(schema, path)
810  * Validates the given ucl object using schema object represented as another
811  * opaque ucl object. You can also specify path in the form `#/path/def` to
812  * specify the specific schema element to perform validation.
813  *
814  * @param {ucl.object} schema schema object
815  * @param {string} path optional path for validation procedure
816  * @return {result,err} two values: boolean result and the corresponding error
817  */
818 static int
819 lua_ucl_object_validate (lua_State *L)
820 {
821         ucl_object_t *obj, *schema;
822         const ucl_object_t *schema_elt;
823         bool res = false;
824         struct ucl_schema_error err;
825         const char *path = NULL;
826
827         obj = lua_ucl_object_get (L, 1);
828         schema = lua_ucl_object_get (L, 2);
829
830         if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
831                 if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TSTRING) {
832                         path = lua_tostring (L, 3);
833                         if (path[0] == '#') {
834                                 path ++;
835                         }
836                 }
837
838                 if (path) {
839                         schema_elt = ucl_lookup_path_char (schema, path, '/');
840                 }
841                 else {
842                         /* Use the top object */
843                         schema_elt = schema;
844                 }
845
846                 if (schema_elt) {
847                         res = ucl_object_validate (schema_elt, obj, &err);
848
849                         if (res) {
850                                 lua_pushboolean (L, res);
851                                 lua_pushnil (L);
852                         }
853                         else {
854                                 lua_pushboolean (L, res);
855                                 lua_pushfstring (L, "validation error: %s", err.msg);
856                         }
857                 }
858                 else {
859                         lua_pushboolean (L, res);
860
861                         if (path) {
862                                 lua_pushfstring (L, "cannot find the requested path: %s", path);
863                         }
864                         else {
865                                 /* Should not be reached */
866                                 lua_pushstring (L, "unknown error");
867                         }
868                 }
869         }
870         else {
871                 lua_pushboolean (L, res);
872                 lua_pushstring (L, "invalid object or schema");
873         }
874
875         return 2;
876 }
877
878 static int
879 lua_ucl_object_gc (lua_State *L)
880 {
881         ucl_object_t *obj;
882
883         obj = lua_ucl_object_get (L, 1);
884
885         ucl_object_unref (obj);
886
887         return 0;
888 }
889
890 static void
891 lua_ucl_parser_mt (lua_State *L)
892 {
893         luaL_newmetatable (L, PARSER_META);
894
895         lua_pushvalue(L, -1);
896         lua_setfield(L, -2, "__index");
897
898         lua_pushcfunction (L, lua_ucl_parser_gc);
899         lua_setfield (L, -2, "__gc");
900
901         lua_pushcfunction (L, lua_ucl_parser_parse_file);
902         lua_setfield (L, -2, "parse_file");
903
904         lua_pushcfunction (L, lua_ucl_parser_parse_string);
905         lua_setfield (L, -2, "parse_string");
906
907         lua_pushcfunction (L, lua_ucl_parser_get_object);
908         lua_setfield (L, -2, "get_object");
909
910         lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
911         lua_setfield (L, -2, "get_object_wrapped");
912
913         lua_pushcfunction (L, lua_ucl_parser_validate);
914         lua_setfield (L, -2, "validate");
915
916         lua_pop (L, 1);
917 }
918
919 static void
920 lua_ucl_object_mt (lua_State *L)
921 {
922         luaL_newmetatable (L, OBJECT_META);
923
924         lua_pushvalue(L, -1);
925         lua_setfield(L, -2, "__index");
926
927         lua_pushcfunction (L, lua_ucl_object_gc);
928         lua_setfield (L, -2, "__gc");
929
930         lua_pushcfunction (L, lua_ucl_object_tostring);
931         lua_setfield (L, -2, "__tostring");
932
933         lua_pushcfunction (L, lua_ucl_object_tostring);
934         lua_setfield (L, -2, "tostring");
935
936         lua_pushcfunction (L, lua_ucl_object_unwrap);
937         lua_setfield (L, -2, "unwrap");
938
939         lua_pushcfunction (L, lua_ucl_object_unwrap);
940         lua_setfield (L, -2, "tolua");
941
942         lua_pushcfunction (L, lua_ucl_object_validate);
943         lua_setfield (L, -2, "validate");
944
945         lua_pushstring (L, OBJECT_META);
946         lua_setfield (L, -2, "class");
947
948         lua_pop (L, 1);
949 }
950
951 static int
952 lua_ucl_to_json (lua_State *L)
953 {
954         ucl_object_t *obj;
955         int format = UCL_EMIT_JSON;
956
957         if (lua_gettop (L) > 1) {
958                 if (lua_toboolean (L, 2)) {
959                         format = UCL_EMIT_JSON_COMPACT;
960                 }
961         }
962
963         obj = ucl_object_lua_import (L, 1);
964         if (obj != NULL) {
965                 lua_ucl_to_string (L, obj, format);
966                 ucl_object_unref (obj);
967         }
968         else {
969                 lua_pushnil (L);
970         }
971
972         return 1;
973 }
974
975 static int
976 lua_ucl_to_config (lua_State *L)
977 {
978         ucl_object_t *obj;
979
980         obj = ucl_object_lua_import (L, 1);
981         if (obj != NULL) {
982                 lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
983                 ucl_object_unref (obj);
984         }
985         else {
986                 lua_pushnil (L);
987         }
988
989         return 1;
990 }
991
992 /***
993  * @function ucl.to_format(var, format)
994  * Converts lua variable `var` to the specified `format`. Formats supported are:
995  *
996  * - `json` - fine printed json
997  * - `json-compact` - compacted json
998  * - `config` - fine printed configuration
999  * - `ucl` - same as `config`
1000  * - `yaml` - embedded yaml
1001  *
1002  * If `var` contains function, they are called during output formatting and if
1003  * they return string value, then this value is used for ouptut.
1004  * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
1005  * @param {string} format any available format
1006  * @return {string} string representation of `var` in the specific `format`.
1007  * @example
1008 local table = {
1009   str = 'value',
1010   num = 100500,
1011   null = ucl.null,
1012   func = function ()
1013     return 'huh'
1014   end
1015 }
1016
1017 print(ucl.to_format(table, 'ucl'))
1018 -- Output:
1019 --[[
1020 num = 100500;
1021 str = "value";
1022 null = null;
1023 func = "huh";
1024 --]]
1025  */
1026 static int
1027 lua_ucl_to_format (lua_State *L)
1028 {
1029         ucl_object_t *obj;
1030         int format = UCL_EMIT_JSON;
1031
1032         if (lua_gettop (L) > 1) {
1033                 if (lua_type (L, 2) == LUA_TNUMBER) {
1034                         format = lua_tonumber (L, 2);
1035                         if (format < 0 || format >= UCL_EMIT_YAML) {
1036                                 lua_pushnil (L);
1037                                 return 1;
1038                         }
1039                 }
1040                 else if (lua_type (L, 2) == LUA_TSTRING) {
1041                         const char *strtype = lua_tostring (L, 2);
1042
1043                         if (strcasecmp (strtype, "json") == 0) {
1044                                 format = UCL_EMIT_JSON;
1045                         }
1046                         else if (strcasecmp (strtype, "json-compact") == 0) {
1047                                 format = UCL_EMIT_JSON_COMPACT;
1048                         }
1049                         else if (strcasecmp (strtype, "yaml") == 0) {
1050                                 format = UCL_EMIT_YAML;
1051                         }
1052                         else if (strcasecmp (strtype, "config") == 0 ||
1053                                 strcasecmp (strtype, "ucl") == 0) {
1054                                 format = UCL_EMIT_CONFIG;
1055                         }
1056                 }
1057         }
1058
1059         obj = ucl_object_lua_import (L, 1);
1060         if (obj != NULL) {
1061                 lua_ucl_to_string (L, obj, format);
1062                 ucl_object_unref (obj);
1063         }
1064         else {
1065                 lua_pushnil (L);
1066         }
1067
1068         return 1;
1069 }
1070
1071 static int
1072 lua_ucl_null_tostring (lua_State* L)
1073 {
1074         lua_pushstring (L, "null");
1075         return 1;
1076 }
1077
1078 static void
1079 lua_ucl_null_mt (lua_State *L)
1080 {
1081         luaL_newmetatable (L, NULL_META);
1082
1083         lua_pushcfunction (L, lua_ucl_null_tostring);
1084         lua_setfield (L, -2, "__tostring");
1085
1086         lua_pop (L, 1);
1087 }
1088
1089 int
1090 luaopen_ucl (lua_State *L)
1091 {
1092         lua_ucl_parser_mt (L);
1093         lua_ucl_null_mt (L);
1094         lua_ucl_object_mt (L);
1095
1096         /* Create the refs weak table: */
1097         lua_createtable (L, 0, 2);
1098         lua_pushliteral (L, "v"); /* tbl, "v" */
1099         lua_setfield (L, -2, "__mode");
1100         lua_pushvalue (L, -1); /* tbl, tbl */
1101         lua_setmetatable (L, -2); /* tbl */
1102         lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
1103
1104         lua_newtable (L);
1105
1106         lua_pushcfunction (L, lua_ucl_parser_init);
1107         lua_setfield (L, -2, "parser");
1108
1109         lua_pushcfunction (L, lua_ucl_to_json);
1110         lua_setfield (L, -2, "to_json");
1111
1112         lua_pushcfunction (L, lua_ucl_to_config);
1113         lua_setfield (L, -2, "to_config");
1114
1115         lua_pushcfunction (L, lua_ucl_to_format);
1116         lua_setfield (L, -2, "to_format");
1117
1118         ucl_null = lua_newuserdata (L, 0);
1119         luaL_getmetatable (L, NULL_META);
1120         lua_setmetatable (L, -2);
1121
1122         lua_pushvalue (L, -1);
1123         lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
1124
1125         lua_setfield (L, -2, "null");
1126
1127         return 1;
1128 }
1129
1130 struct ucl_lua_funcdata*
1131 ucl_object_toclosure (const ucl_object_t *obj)
1132 {
1133         if (obj == NULL || obj->type != UCL_USERDATA) {
1134                 return NULL;
1135         }
1136
1137         return (struct ucl_lua_funcdata*)obj->value.ud;
1138 }