xref: /freebsd-src/contrib/libucl/lua/lua_ucl.c (revision 4bf5485791b743cece52e2defa8c8efdf389b57a)
1*4bf54857SBaptiste Daroussin /* Copyright (c) 2014, Vsevolod Stakhov
2*4bf54857SBaptiste Daroussin  * All rights reserved.
3*4bf54857SBaptiste Daroussin  *
4*4bf54857SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
5*4bf54857SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
6*4bf54857SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
7*4bf54857SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
8*4bf54857SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
9*4bf54857SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
10*4bf54857SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
11*4bf54857SBaptiste Daroussin  *
12*4bf54857SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13*4bf54857SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14*4bf54857SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15*4bf54857SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16*4bf54857SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17*4bf54857SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18*4bf54857SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19*4bf54857SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20*4bf54857SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21*4bf54857SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22*4bf54857SBaptiste Daroussin  */
23*4bf54857SBaptiste Daroussin 
24*4bf54857SBaptiste Daroussin /**
25*4bf54857SBaptiste Daroussin  * @file lua ucl bindings
26*4bf54857SBaptiste Daroussin  */
27*4bf54857SBaptiste Daroussin 
28*4bf54857SBaptiste Daroussin #include "ucl.h"
29*4bf54857SBaptiste Daroussin #include "ucl_internal.h"
30*4bf54857SBaptiste Daroussin #include "lua_ucl.h"
31*4bf54857SBaptiste Daroussin #include <strings.h>
32*4bf54857SBaptiste Daroussin 
33*4bf54857SBaptiste Daroussin /***
34*4bf54857SBaptiste Daroussin  * @module ucl
35*4bf54857SBaptiste Daroussin  * This lua module allows to parse objects from strings and to store data into
36*4bf54857SBaptiste Daroussin  * ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
37*4bf54857SBaptiste Daroussin  * @example
38*4bf54857SBaptiste Daroussin local ucl = require("ucl")
39*4bf54857SBaptiste Daroussin 
40*4bf54857SBaptiste Daroussin local parser = ucl.parser()
41*4bf54857SBaptiste Daroussin local res,err = parser:parse_string('{key=value}')
42*4bf54857SBaptiste Daroussin 
43*4bf54857SBaptiste Daroussin if not res then
44*4bf54857SBaptiste Daroussin 	print('parser error: ' .. err)
45*4bf54857SBaptiste Daroussin else
46*4bf54857SBaptiste Daroussin 	local obj = parser:get_object()
47*4bf54857SBaptiste Daroussin 	local got = ucl.to_format(obj, 'json')
48*4bf54857SBaptiste Daroussin endif
49*4bf54857SBaptiste Daroussin 
50*4bf54857SBaptiste Daroussin local table = {
51*4bf54857SBaptiste Daroussin   str = 'value',
52*4bf54857SBaptiste Daroussin   num = 100500,
53*4bf54857SBaptiste Daroussin   null = ucl.null,
54*4bf54857SBaptiste Daroussin   func = function ()
55*4bf54857SBaptiste Daroussin     return 'huh'
56*4bf54857SBaptiste Daroussin   end
57*4bf54857SBaptiste Daroussin }
58*4bf54857SBaptiste Daroussin 
59*4bf54857SBaptiste Daroussin print(ucl.to_format(table, 'ucl'))
60*4bf54857SBaptiste Daroussin -- Output:
61*4bf54857SBaptiste Daroussin --[[
62*4bf54857SBaptiste Daroussin num = 100500;
63*4bf54857SBaptiste Daroussin str = "value";
64*4bf54857SBaptiste Daroussin null = null;
65*4bf54857SBaptiste Daroussin func = "huh";
66*4bf54857SBaptiste Daroussin --]]
67*4bf54857SBaptiste Daroussin  */
68*4bf54857SBaptiste Daroussin 
69*4bf54857SBaptiste Daroussin #define PARSER_META "ucl.parser.meta"
70*4bf54857SBaptiste Daroussin #define EMITTER_META "ucl.emitter.meta"
71*4bf54857SBaptiste Daroussin #define NULL_META "null.emitter.meta"
72*4bf54857SBaptiste Daroussin 
73*4bf54857SBaptiste Daroussin static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
74*4bf54857SBaptiste Daroussin static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
75*4bf54857SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
76*4bf54857SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
77*4bf54857SBaptiste Daroussin 
78*4bf54857SBaptiste Daroussin static void *ucl_null;
79*4bf54857SBaptiste Daroussin 
80*4bf54857SBaptiste Daroussin /**
81*4bf54857SBaptiste Daroussin  * Push a single element of an object to lua
82*4bf54857SBaptiste Daroussin  * @param L
83*4bf54857SBaptiste Daroussin  * @param key
84*4bf54857SBaptiste Daroussin  * @param obj
85*4bf54857SBaptiste Daroussin  */
86*4bf54857SBaptiste Daroussin static void
87*4bf54857SBaptiste Daroussin ucl_object_lua_push_element (lua_State *L, const char *key,
88*4bf54857SBaptiste Daroussin 		const ucl_object_t *obj)
89*4bf54857SBaptiste Daroussin {
90*4bf54857SBaptiste Daroussin 	lua_pushstring (L, key);
91*4bf54857SBaptiste Daroussin 	ucl_object_push_lua (L, obj, true);
92*4bf54857SBaptiste Daroussin 	lua_settable (L, -3);
93*4bf54857SBaptiste Daroussin }
94*4bf54857SBaptiste Daroussin 
95*4bf54857SBaptiste Daroussin static void
96*4bf54857SBaptiste Daroussin lua_ucl_userdata_dtor (void *ud)
97*4bf54857SBaptiste Daroussin {
98*4bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
99*4bf54857SBaptiste Daroussin 
100*4bf54857SBaptiste Daroussin 	luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
101*4bf54857SBaptiste Daroussin 	if (fd->ret != NULL) {
102*4bf54857SBaptiste Daroussin 		free (fd->ret);
103*4bf54857SBaptiste Daroussin 	}
104*4bf54857SBaptiste Daroussin 	free (fd);
105*4bf54857SBaptiste Daroussin }
106*4bf54857SBaptiste Daroussin 
107*4bf54857SBaptiste Daroussin static const char *
108*4bf54857SBaptiste Daroussin lua_ucl_userdata_emitter (void *ud)
109*4bf54857SBaptiste Daroussin {
110*4bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
111*4bf54857SBaptiste Daroussin 	const char *out = "";
112*4bf54857SBaptiste Daroussin 
113*4bf54857SBaptiste Daroussin 	lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
114*4bf54857SBaptiste Daroussin 
115*4bf54857SBaptiste Daroussin 	lua_pcall (fd->L, 0, 1, 0);
116*4bf54857SBaptiste Daroussin 	out = lua_tostring (fd->L, -1);
117*4bf54857SBaptiste Daroussin 
118*4bf54857SBaptiste Daroussin 	if (out != NULL) {
119*4bf54857SBaptiste Daroussin 		/* We need to store temporary string in a more appropriate place */
120*4bf54857SBaptiste Daroussin 		if (fd->ret) {
121*4bf54857SBaptiste Daroussin 			free (fd->ret);
122*4bf54857SBaptiste Daroussin 		}
123*4bf54857SBaptiste Daroussin 		fd->ret = strdup (out);
124*4bf54857SBaptiste Daroussin 	}
125*4bf54857SBaptiste Daroussin 
126*4bf54857SBaptiste Daroussin 	lua_settop (fd->L, 0);
127*4bf54857SBaptiste Daroussin 
128*4bf54857SBaptiste Daroussin 	return fd->ret;
129*4bf54857SBaptiste Daroussin }
130*4bf54857SBaptiste Daroussin 
131*4bf54857SBaptiste Daroussin /**
132*4bf54857SBaptiste Daroussin  * Push a single object to lua
133*4bf54857SBaptiste Daroussin  * @param L
134*4bf54857SBaptiste Daroussin  * @param obj
135*4bf54857SBaptiste Daroussin  * @return
136*4bf54857SBaptiste Daroussin  */
137*4bf54857SBaptiste Daroussin static int
138*4bf54857SBaptiste Daroussin ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
139*4bf54857SBaptiste Daroussin 		bool allow_array)
140*4bf54857SBaptiste Daroussin {
141*4bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
142*4bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
143*4bf54857SBaptiste Daroussin 	int nelt = 0;
144*4bf54857SBaptiste Daroussin 
145*4bf54857SBaptiste Daroussin 	if (allow_array && obj->next != NULL) {
146*4bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
147*4bf54857SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj);
148*4bf54857SBaptiste Daroussin 	}
149*4bf54857SBaptiste Daroussin 
150*4bf54857SBaptiste Daroussin 	/* Optimize allocation by preallocation of table */
151*4bf54857SBaptiste Daroussin 	while (ucl_iterate_object (obj, &it, true) != NULL) {
152*4bf54857SBaptiste Daroussin 		nelt ++;
153*4bf54857SBaptiste Daroussin 	}
154*4bf54857SBaptiste Daroussin 
155*4bf54857SBaptiste Daroussin 	lua_createtable (L, 0, nelt);
156*4bf54857SBaptiste Daroussin 	it = NULL;
157*4bf54857SBaptiste Daroussin 
158*4bf54857SBaptiste Daroussin 	while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
159*4bf54857SBaptiste Daroussin 		ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
160*4bf54857SBaptiste Daroussin 	}
161*4bf54857SBaptiste Daroussin 
162*4bf54857SBaptiste Daroussin 	return 1;
163*4bf54857SBaptiste Daroussin }
164*4bf54857SBaptiste Daroussin 
165*4bf54857SBaptiste Daroussin /**
166*4bf54857SBaptiste Daroussin  * Push an array to lua as table indexed by integers
167*4bf54857SBaptiste Daroussin  * @param L
168*4bf54857SBaptiste Daroussin  * @param obj
169*4bf54857SBaptiste Daroussin  * @return
170*4bf54857SBaptiste Daroussin  */
171*4bf54857SBaptiste Daroussin static int
172*4bf54857SBaptiste Daroussin ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
173*4bf54857SBaptiste Daroussin {
174*4bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
175*4bf54857SBaptiste Daroussin 	int i = 1, nelt = 0;
176*4bf54857SBaptiste Daroussin 
177*4bf54857SBaptiste Daroussin 	/* Optimize allocation by preallocation of table */
178*4bf54857SBaptiste Daroussin 	LL_FOREACH (obj, cur) {
179*4bf54857SBaptiste Daroussin 		nelt ++;
180*4bf54857SBaptiste Daroussin 	}
181*4bf54857SBaptiste Daroussin 
182*4bf54857SBaptiste Daroussin 	lua_createtable (L, nelt, 0);
183*4bf54857SBaptiste Daroussin 
184*4bf54857SBaptiste Daroussin 	LL_FOREACH (obj, cur) {
185*4bf54857SBaptiste Daroussin 		ucl_object_push_lua (L, cur, false);
186*4bf54857SBaptiste Daroussin 		lua_rawseti (L, -2, i);
187*4bf54857SBaptiste Daroussin 		i ++;
188*4bf54857SBaptiste Daroussin 	}
189*4bf54857SBaptiste Daroussin 
190*4bf54857SBaptiste Daroussin 	return 1;
191*4bf54857SBaptiste Daroussin }
192*4bf54857SBaptiste Daroussin 
193*4bf54857SBaptiste Daroussin /**
194*4bf54857SBaptiste Daroussin  * Push a simple object to lua depending on its actual type
195*4bf54857SBaptiste Daroussin  */
196*4bf54857SBaptiste Daroussin static int
197*4bf54857SBaptiste Daroussin ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
198*4bf54857SBaptiste Daroussin 		bool allow_array)
199*4bf54857SBaptiste Daroussin {
200*4bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
201*4bf54857SBaptiste Daroussin 
202*4bf54857SBaptiste Daroussin 	if (allow_array && obj->next != NULL) {
203*4bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
204*4bf54857SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj);
205*4bf54857SBaptiste Daroussin 	}
206*4bf54857SBaptiste Daroussin 
207*4bf54857SBaptiste Daroussin 	switch (obj->type) {
208*4bf54857SBaptiste Daroussin 	case UCL_BOOLEAN:
209*4bf54857SBaptiste Daroussin 		lua_pushboolean (L, ucl_obj_toboolean (obj));
210*4bf54857SBaptiste Daroussin 		break;
211*4bf54857SBaptiste Daroussin 	case UCL_STRING:
212*4bf54857SBaptiste Daroussin 		lua_pushstring (L, ucl_obj_tostring (obj));
213*4bf54857SBaptiste Daroussin 		break;
214*4bf54857SBaptiste Daroussin 	case UCL_INT:
215*4bf54857SBaptiste Daroussin #if LUA_VERSION_NUM >= 501
216*4bf54857SBaptiste Daroussin 		lua_pushinteger (L, ucl_obj_toint (obj));
217*4bf54857SBaptiste Daroussin #else
218*4bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_toint (obj));
219*4bf54857SBaptiste Daroussin #endif
220*4bf54857SBaptiste Daroussin 		break;
221*4bf54857SBaptiste Daroussin 	case UCL_FLOAT:
222*4bf54857SBaptiste Daroussin 	case UCL_TIME:
223*4bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_todouble (obj));
224*4bf54857SBaptiste Daroussin 		break;
225*4bf54857SBaptiste Daroussin 	case UCL_NULL:
226*4bf54857SBaptiste Daroussin 		lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
227*4bf54857SBaptiste Daroussin 		break;
228*4bf54857SBaptiste Daroussin 	case UCL_USERDATA:
229*4bf54857SBaptiste Daroussin 		fd = (struct ucl_lua_funcdata *)obj->value.ud;
230*4bf54857SBaptiste Daroussin 		lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
231*4bf54857SBaptiste Daroussin 		break;
232*4bf54857SBaptiste Daroussin 	default:
233*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
234*4bf54857SBaptiste Daroussin 		break;
235*4bf54857SBaptiste Daroussin 	}
236*4bf54857SBaptiste Daroussin 
237*4bf54857SBaptiste Daroussin 	return 1;
238*4bf54857SBaptiste Daroussin }
239*4bf54857SBaptiste Daroussin 
240*4bf54857SBaptiste Daroussin /***
241*4bf54857SBaptiste Daroussin  * @function ucl_object_push_lua(L, obj, allow_array)
242*4bf54857SBaptiste Daroussin  * This is a `C` function to push `UCL` object as lua variable. This function
243*4bf54857SBaptiste Daroussin  * converts `obj` to lua representation using the following conversions:
244*4bf54857SBaptiste Daroussin  *
245*4bf54857SBaptiste Daroussin  * - *scalar* values are directly presented by lua objects
246*4bf54857SBaptiste Daroussin  * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
247*4bf54857SBaptiste Daroussin  * this can be used to pass functions from lua to c and vice-versa
248*4bf54857SBaptiste Daroussin  * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
249*4bf54857SBaptiste Daroussin  * - *objects* are converted to lua tables with string indicies
250*4bf54857SBaptiste Daroussin  * @param {lua_State} L lua state pointer
251*4bf54857SBaptiste Daroussin  * @param {ucl_object_t} obj object to push
252*4bf54857SBaptiste Daroussin  * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
253*4bf54857SBaptiste Daroussin  * @return {int} `1` if an object is pushed to lua
254*4bf54857SBaptiste Daroussin  */
255*4bf54857SBaptiste Daroussin int
256*4bf54857SBaptiste Daroussin ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
257*4bf54857SBaptiste Daroussin {
258*4bf54857SBaptiste Daroussin 	switch (obj->type) {
259*4bf54857SBaptiste Daroussin 	case UCL_OBJECT:
260*4bf54857SBaptiste Daroussin 		return ucl_object_lua_push_object (L, obj, allow_array);
261*4bf54857SBaptiste Daroussin 	case UCL_ARRAY:
262*4bf54857SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj->value.av);
263*4bf54857SBaptiste Daroussin 	default:
264*4bf54857SBaptiste Daroussin 		return ucl_object_lua_push_scalar (L, obj, allow_array);
265*4bf54857SBaptiste Daroussin 	}
266*4bf54857SBaptiste Daroussin }
267*4bf54857SBaptiste Daroussin 
268*4bf54857SBaptiste Daroussin /**
269*4bf54857SBaptiste Daroussin  * Parse lua table into object top
270*4bf54857SBaptiste Daroussin  * @param L
271*4bf54857SBaptiste Daroussin  * @param top
272*4bf54857SBaptiste Daroussin  * @param idx
273*4bf54857SBaptiste Daroussin  */
274*4bf54857SBaptiste Daroussin static ucl_object_t *
275*4bf54857SBaptiste Daroussin ucl_object_lua_fromtable (lua_State *L, int idx)
276*4bf54857SBaptiste Daroussin {
277*4bf54857SBaptiste Daroussin 	ucl_object_t *obj, *top = NULL;
278*4bf54857SBaptiste Daroussin 	size_t keylen;
279*4bf54857SBaptiste Daroussin 	const char *k;
280*4bf54857SBaptiste Daroussin 	bool is_array = true;
281*4bf54857SBaptiste Daroussin 	int max = INT_MIN;
282*4bf54857SBaptiste Daroussin 
283*4bf54857SBaptiste Daroussin 	if (idx < 0) {
284*4bf54857SBaptiste Daroussin 		/* For negative indicies we want to invert them */
285*4bf54857SBaptiste Daroussin 		idx = lua_gettop (L) + idx + 1;
286*4bf54857SBaptiste Daroussin 	}
287*4bf54857SBaptiste Daroussin 	/* Check for array */
288*4bf54857SBaptiste Daroussin 	lua_pushnil (L);
289*4bf54857SBaptiste Daroussin 	while (lua_next (L, idx) != 0) {
290*4bf54857SBaptiste Daroussin 		if (lua_type (L, -2) == LUA_TNUMBER) {
291*4bf54857SBaptiste Daroussin 			double num = lua_tonumber (L, -2);
292*4bf54857SBaptiste Daroussin 			if (num == (int)num) {
293*4bf54857SBaptiste Daroussin 				if (num > max) {
294*4bf54857SBaptiste Daroussin 					max = num;
295*4bf54857SBaptiste Daroussin 				}
296*4bf54857SBaptiste Daroussin 			}
297*4bf54857SBaptiste Daroussin 			else {
298*4bf54857SBaptiste Daroussin 				/* Keys are not integer */
299*4bf54857SBaptiste Daroussin 				lua_pop (L, 2);
300*4bf54857SBaptiste Daroussin 				is_array = false;
301*4bf54857SBaptiste Daroussin 				break;
302*4bf54857SBaptiste Daroussin 			}
303*4bf54857SBaptiste Daroussin 		}
304*4bf54857SBaptiste Daroussin 		else {
305*4bf54857SBaptiste Daroussin 			/* Keys are not numeric */
306*4bf54857SBaptiste Daroussin 			lua_pop (L, 2);
307*4bf54857SBaptiste Daroussin 			is_array = false;
308*4bf54857SBaptiste Daroussin 			break;
309*4bf54857SBaptiste Daroussin 		}
310*4bf54857SBaptiste Daroussin 		lua_pop (L, 1);
311*4bf54857SBaptiste Daroussin 	}
312*4bf54857SBaptiste Daroussin 
313*4bf54857SBaptiste Daroussin 	/* Table iterate */
314*4bf54857SBaptiste Daroussin 	if (is_array) {
315*4bf54857SBaptiste Daroussin 		int i;
316*4bf54857SBaptiste Daroussin 
317*4bf54857SBaptiste Daroussin 		top = ucl_object_typed_new (UCL_ARRAY);
318*4bf54857SBaptiste Daroussin 		for (i = 1; i <= max; i ++) {
319*4bf54857SBaptiste Daroussin 			lua_pushinteger (L, i);
320*4bf54857SBaptiste Daroussin 			lua_gettable (L, idx);
321*4bf54857SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
322*4bf54857SBaptiste Daroussin 			if (obj != NULL) {
323*4bf54857SBaptiste Daroussin 				ucl_array_append (top, obj);
324*4bf54857SBaptiste Daroussin 			}
325*4bf54857SBaptiste Daroussin 		}
326*4bf54857SBaptiste Daroussin 	}
327*4bf54857SBaptiste Daroussin 	else {
328*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
329*4bf54857SBaptiste Daroussin 		top = ucl_object_typed_new (UCL_OBJECT);
330*4bf54857SBaptiste Daroussin 		while (lua_next (L, idx) != 0) {
331*4bf54857SBaptiste Daroussin 			/* copy key to avoid modifications */
332*4bf54857SBaptiste Daroussin 			k = lua_tolstring (L, -2, &keylen);
333*4bf54857SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
334*4bf54857SBaptiste Daroussin 
335*4bf54857SBaptiste Daroussin 			if (obj != NULL) {
336*4bf54857SBaptiste Daroussin 				ucl_object_insert_key (top, obj, k, keylen, true);
337*4bf54857SBaptiste Daroussin 			}
338*4bf54857SBaptiste Daroussin 			lua_pop (L, 1);
339*4bf54857SBaptiste Daroussin 		}
340*4bf54857SBaptiste Daroussin 	}
341*4bf54857SBaptiste Daroussin 
342*4bf54857SBaptiste Daroussin 	return top;
343*4bf54857SBaptiste Daroussin }
344*4bf54857SBaptiste Daroussin 
345*4bf54857SBaptiste Daroussin /**
346*4bf54857SBaptiste Daroussin  * Get a single element from lua to object obj
347*4bf54857SBaptiste Daroussin  * @param L
348*4bf54857SBaptiste Daroussin  * @param obj
349*4bf54857SBaptiste Daroussin  * @param idx
350*4bf54857SBaptiste Daroussin  */
351*4bf54857SBaptiste Daroussin static ucl_object_t *
352*4bf54857SBaptiste Daroussin ucl_object_lua_fromelt (lua_State *L, int idx)
353*4bf54857SBaptiste Daroussin {
354*4bf54857SBaptiste Daroussin 	int type;
355*4bf54857SBaptiste Daroussin 	double num;
356*4bf54857SBaptiste Daroussin 	ucl_object_t *obj = NULL;
357*4bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
358*4bf54857SBaptiste Daroussin 
359*4bf54857SBaptiste Daroussin 	type = lua_type (L, idx);
360*4bf54857SBaptiste Daroussin 
361*4bf54857SBaptiste Daroussin 	switch (type) {
362*4bf54857SBaptiste Daroussin 	case LUA_TSTRING:
363*4bf54857SBaptiste Daroussin 		obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
364*4bf54857SBaptiste Daroussin 		break;
365*4bf54857SBaptiste Daroussin 	case LUA_TNUMBER:
366*4bf54857SBaptiste Daroussin 		num = lua_tonumber (L, idx);
367*4bf54857SBaptiste Daroussin 		if (num == (int64_t)num) {
368*4bf54857SBaptiste Daroussin 			obj = ucl_object_fromint (num);
369*4bf54857SBaptiste Daroussin 		}
370*4bf54857SBaptiste Daroussin 		else {
371*4bf54857SBaptiste Daroussin 			obj = ucl_object_fromdouble (num);
372*4bf54857SBaptiste Daroussin 		}
373*4bf54857SBaptiste Daroussin 		break;
374*4bf54857SBaptiste Daroussin 	case LUA_TBOOLEAN:
375*4bf54857SBaptiste Daroussin 		obj = ucl_object_frombool (lua_toboolean (L, idx));
376*4bf54857SBaptiste Daroussin 		break;
377*4bf54857SBaptiste Daroussin 	case LUA_TUSERDATA:
378*4bf54857SBaptiste Daroussin 		if (lua_topointer (L, idx) == ucl_null) {
379*4bf54857SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_NULL);
380*4bf54857SBaptiste Daroussin 		}
381*4bf54857SBaptiste Daroussin 		break;
382*4bf54857SBaptiste Daroussin 	case LUA_TTABLE:
383*4bf54857SBaptiste Daroussin 	case LUA_TFUNCTION:
384*4bf54857SBaptiste Daroussin 	case LUA_TTHREAD:
385*4bf54857SBaptiste Daroussin 		if (luaL_getmetafield (L, idx, "__gen_ucl")) {
386*4bf54857SBaptiste Daroussin 			if (lua_isfunction (L, -1)) {
387*4bf54857SBaptiste Daroussin 				lua_settop (L, 3); /* gen, obj, func */
388*4bf54857SBaptiste Daroussin 				lua_insert (L, 1); /* func, gen, obj */
389*4bf54857SBaptiste Daroussin 				lua_insert (L, 2); /* func, obj, gen */
390*4bf54857SBaptiste Daroussin 				lua_call(L, 2, 1);
391*4bf54857SBaptiste Daroussin 				obj = ucl_object_lua_fromelt (L, 1);
392*4bf54857SBaptiste Daroussin 			}
393*4bf54857SBaptiste Daroussin 			lua_pop (L, 2);
394*4bf54857SBaptiste Daroussin 		}
395*4bf54857SBaptiste Daroussin 		else {
396*4bf54857SBaptiste Daroussin 			if (type == LUA_TTABLE) {
397*4bf54857SBaptiste Daroussin 				obj = ucl_object_lua_fromtable (L, idx);
398*4bf54857SBaptiste Daroussin 			}
399*4bf54857SBaptiste Daroussin 			else if (type == LUA_TFUNCTION) {
400*4bf54857SBaptiste Daroussin 				fd = malloc (sizeof (*fd));
401*4bf54857SBaptiste Daroussin 				if (fd != NULL) {
402*4bf54857SBaptiste Daroussin 					lua_pushvalue (L, idx);
403*4bf54857SBaptiste Daroussin 					fd->L = L;
404*4bf54857SBaptiste Daroussin 					fd->ret = NULL;
405*4bf54857SBaptiste Daroussin 					fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
406*4bf54857SBaptiste Daroussin 
407*4bf54857SBaptiste Daroussin 					obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
408*4bf54857SBaptiste Daroussin 							lua_ucl_userdata_emitter);
409*4bf54857SBaptiste Daroussin 					obj->type = UCL_USERDATA;
410*4bf54857SBaptiste Daroussin 					obj->value.ud = (void *)fd;
411*4bf54857SBaptiste Daroussin 				}
412*4bf54857SBaptiste Daroussin 			}
413*4bf54857SBaptiste Daroussin 		}
414*4bf54857SBaptiste Daroussin 		break;
415*4bf54857SBaptiste Daroussin 	}
416*4bf54857SBaptiste Daroussin 
417*4bf54857SBaptiste Daroussin 	return obj;
418*4bf54857SBaptiste Daroussin }
419*4bf54857SBaptiste Daroussin 
420*4bf54857SBaptiste Daroussin /**
421*4bf54857SBaptiste Daroussin  * @function ucl_object_lua_import(L, idx)
422*4bf54857SBaptiste Daroussin  * Extracts ucl object from lua variable at `idx` position,
423*4bf54857SBaptiste Daroussin  * @see ucl_object_push_lua for conversion definitions
424*4bf54857SBaptiste Daroussin  * @param {lua_state} L lua state machine pointer
425*4bf54857SBaptiste Daroussin  * @param {int} idx index where the source variable is placed
426*4bf54857SBaptiste Daroussin  * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
427*4bf54857SBaptiste Daroussin  * this object thus needs to be unref'ed after usage.
428*4bf54857SBaptiste Daroussin  */
429*4bf54857SBaptiste Daroussin ucl_object_t *
430*4bf54857SBaptiste Daroussin ucl_object_lua_import (lua_State *L, int idx)
431*4bf54857SBaptiste Daroussin {
432*4bf54857SBaptiste Daroussin 	ucl_object_t *obj;
433*4bf54857SBaptiste Daroussin 	int t;
434*4bf54857SBaptiste Daroussin 
435*4bf54857SBaptiste Daroussin 	t = lua_type (L, idx);
436*4bf54857SBaptiste Daroussin 	switch (t) {
437*4bf54857SBaptiste Daroussin 	case LUA_TTABLE:
438*4bf54857SBaptiste Daroussin 		obj = ucl_object_lua_fromtable (L, idx);
439*4bf54857SBaptiste Daroussin 		break;
440*4bf54857SBaptiste Daroussin 	default:
441*4bf54857SBaptiste Daroussin 		obj = ucl_object_lua_fromelt (L, idx);
442*4bf54857SBaptiste Daroussin 		break;
443*4bf54857SBaptiste Daroussin 	}
444*4bf54857SBaptiste Daroussin 
445*4bf54857SBaptiste Daroussin 	return obj;
446*4bf54857SBaptiste Daroussin }
447*4bf54857SBaptiste Daroussin 
448*4bf54857SBaptiste Daroussin static int
449*4bf54857SBaptiste Daroussin lua_ucl_parser_init (lua_State *L)
450*4bf54857SBaptiste Daroussin {
451*4bf54857SBaptiste Daroussin 	struct ucl_parser *parser, **pparser;
452*4bf54857SBaptiste Daroussin 	int flags = 0;
453*4bf54857SBaptiste Daroussin 
454*4bf54857SBaptiste Daroussin 	if (lua_gettop (L) >= 1) {
455*4bf54857SBaptiste Daroussin 		flags = lua_tonumber (L, 1);
456*4bf54857SBaptiste Daroussin 	}
457*4bf54857SBaptiste Daroussin 
458*4bf54857SBaptiste Daroussin 	parser = ucl_parser_new (flags);
459*4bf54857SBaptiste Daroussin 	if (parser == NULL) {
460*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
461*4bf54857SBaptiste Daroussin 	}
462*4bf54857SBaptiste Daroussin 
463*4bf54857SBaptiste Daroussin 	pparser = lua_newuserdata (L, sizeof (parser));
464*4bf54857SBaptiste Daroussin 	*pparser = parser;
465*4bf54857SBaptiste Daroussin 	luaL_getmetatable (L, PARSER_META);
466*4bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
467*4bf54857SBaptiste Daroussin 
468*4bf54857SBaptiste Daroussin 	return 1;
469*4bf54857SBaptiste Daroussin }
470*4bf54857SBaptiste Daroussin 
471*4bf54857SBaptiste Daroussin static struct ucl_parser *
472*4bf54857SBaptiste Daroussin lua_ucl_parser_get (lua_State *L, int index)
473*4bf54857SBaptiste Daroussin {
474*4bf54857SBaptiste Daroussin 	return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
475*4bf54857SBaptiste Daroussin }
476*4bf54857SBaptiste Daroussin 
477*4bf54857SBaptiste Daroussin /***
478*4bf54857SBaptiste Daroussin  * @method parser:parse_file(name)
479*4bf54857SBaptiste Daroussin  * Parse UCL object from file.
480*4bf54857SBaptiste Daroussin  * @param {string} name filename to parse
481*4bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
482*4bf54857SBaptiste Daroussin @example
483*4bf54857SBaptiste Daroussin local parser = ucl.parser()
484*4bf54857SBaptiste Daroussin local res,err = parser:parse_file('/some/file.conf')
485*4bf54857SBaptiste Daroussin 
486*4bf54857SBaptiste Daroussin if not res then
487*4bf54857SBaptiste Daroussin 	print('parser error: ' .. err)
488*4bf54857SBaptiste Daroussin else
489*4bf54857SBaptiste Daroussin 	-- Do something with object
490*4bf54857SBaptiste Daroussin end
491*4bf54857SBaptiste Daroussin  */
492*4bf54857SBaptiste Daroussin static int
493*4bf54857SBaptiste Daroussin lua_ucl_parser_parse_file (lua_State *L)
494*4bf54857SBaptiste Daroussin {
495*4bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
496*4bf54857SBaptiste Daroussin 	const char *file;
497*4bf54857SBaptiste Daroussin 	int ret = 2;
498*4bf54857SBaptiste Daroussin 
499*4bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
500*4bf54857SBaptiste Daroussin 	file = luaL_checkstring (L, 2);
501*4bf54857SBaptiste Daroussin 
502*4bf54857SBaptiste Daroussin 	if (parser != NULL && file != NULL) {
503*4bf54857SBaptiste Daroussin 		if (ucl_parser_add_file (parser, file)) {
504*4bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
505*4bf54857SBaptiste Daroussin 			ret = 1;
506*4bf54857SBaptiste Daroussin 		}
507*4bf54857SBaptiste Daroussin 		else {
508*4bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
509*4bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
510*4bf54857SBaptiste Daroussin 		}
511*4bf54857SBaptiste Daroussin 	}
512*4bf54857SBaptiste Daroussin 	else {
513*4bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
514*4bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
515*4bf54857SBaptiste Daroussin 	}
516*4bf54857SBaptiste Daroussin 
517*4bf54857SBaptiste Daroussin 	return ret;
518*4bf54857SBaptiste Daroussin }
519*4bf54857SBaptiste Daroussin 
520*4bf54857SBaptiste Daroussin /***
521*4bf54857SBaptiste Daroussin  * @method parser:parse_string(input)
522*4bf54857SBaptiste Daroussin  * Parse UCL object from file.
523*4bf54857SBaptiste Daroussin  * @param {string} input string to parse
524*4bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
525*4bf54857SBaptiste Daroussin  */
526*4bf54857SBaptiste Daroussin static int
527*4bf54857SBaptiste Daroussin lua_ucl_parser_parse_string (lua_State *L)
528*4bf54857SBaptiste Daroussin {
529*4bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
530*4bf54857SBaptiste Daroussin 	const char *string;
531*4bf54857SBaptiste Daroussin 	size_t llen;
532*4bf54857SBaptiste Daroussin 	int ret = 2;
533*4bf54857SBaptiste Daroussin 
534*4bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
535*4bf54857SBaptiste Daroussin 	string = luaL_checklstring (L, 2, &llen);
536*4bf54857SBaptiste Daroussin 
537*4bf54857SBaptiste Daroussin 	if (parser != NULL && string != NULL) {
538*4bf54857SBaptiste Daroussin 		if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) {
539*4bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
540*4bf54857SBaptiste Daroussin 			ret = 1;
541*4bf54857SBaptiste Daroussin 		}
542*4bf54857SBaptiste Daroussin 		else {
543*4bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
544*4bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
545*4bf54857SBaptiste Daroussin 		}
546*4bf54857SBaptiste Daroussin 	}
547*4bf54857SBaptiste Daroussin 	else {
548*4bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
549*4bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
550*4bf54857SBaptiste Daroussin 	}
551*4bf54857SBaptiste Daroussin 
552*4bf54857SBaptiste Daroussin 	return ret;
553*4bf54857SBaptiste Daroussin }
554*4bf54857SBaptiste Daroussin 
555*4bf54857SBaptiste Daroussin /***
556*4bf54857SBaptiste Daroussin  * @method parser:get_object()
557*4bf54857SBaptiste Daroussin  * Get top object from parser and export it to lua representation.
558*4bf54857SBaptiste Daroussin  * @return {variant or nil} ucl object as lua native variable
559*4bf54857SBaptiste Daroussin  */
560*4bf54857SBaptiste Daroussin static int
561*4bf54857SBaptiste Daroussin lua_ucl_parser_get_object (lua_State *L)
562*4bf54857SBaptiste Daroussin {
563*4bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
564*4bf54857SBaptiste Daroussin 	ucl_object_t *obj;
565*4bf54857SBaptiste Daroussin 	int ret = 1;
566*4bf54857SBaptiste Daroussin 
567*4bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
568*4bf54857SBaptiste Daroussin 	obj = ucl_parser_get_object (parser);
569*4bf54857SBaptiste Daroussin 
570*4bf54857SBaptiste Daroussin 	if (obj != NULL) {
571*4bf54857SBaptiste Daroussin 		ret = ucl_object_push_lua (L, obj, false);
572*4bf54857SBaptiste Daroussin 		/* no need to keep reference */
573*4bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
574*4bf54857SBaptiste Daroussin 	}
575*4bf54857SBaptiste Daroussin 	else {
576*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
577*4bf54857SBaptiste Daroussin 	}
578*4bf54857SBaptiste Daroussin 
579*4bf54857SBaptiste Daroussin 	return ret;
580*4bf54857SBaptiste Daroussin }
581*4bf54857SBaptiste Daroussin 
582*4bf54857SBaptiste Daroussin static int
583*4bf54857SBaptiste Daroussin lua_ucl_parser_gc (lua_State *L)
584*4bf54857SBaptiste Daroussin {
585*4bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
586*4bf54857SBaptiste Daroussin 
587*4bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
588*4bf54857SBaptiste Daroussin 	ucl_parser_free (parser);
589*4bf54857SBaptiste Daroussin 
590*4bf54857SBaptiste Daroussin 	return 0;
591*4bf54857SBaptiste Daroussin }
592*4bf54857SBaptiste Daroussin 
593*4bf54857SBaptiste Daroussin static void
594*4bf54857SBaptiste Daroussin lua_ucl_parser_mt (lua_State *L)
595*4bf54857SBaptiste Daroussin {
596*4bf54857SBaptiste Daroussin 	luaL_newmetatable (L, PARSER_META);
597*4bf54857SBaptiste Daroussin 
598*4bf54857SBaptiste Daroussin 	lua_pushvalue(L, -1);
599*4bf54857SBaptiste Daroussin 	lua_setfield(L, -2, "__index");
600*4bf54857SBaptiste Daroussin 
601*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_gc);
602*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__gc");
603*4bf54857SBaptiste Daroussin 
604*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_file);
605*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_file");
606*4bf54857SBaptiste Daroussin 
607*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_string);
608*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_string");
609*4bf54857SBaptiste Daroussin 
610*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_get_object);
611*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "get_object");
612*4bf54857SBaptiste Daroussin 
613*4bf54857SBaptiste Daroussin 	lua_pop (L, 1);
614*4bf54857SBaptiste Daroussin }
615*4bf54857SBaptiste Daroussin 
616*4bf54857SBaptiste Daroussin static int
617*4bf54857SBaptiste Daroussin lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
618*4bf54857SBaptiste Daroussin {
619*4bf54857SBaptiste Daroussin 	unsigned char *result;
620*4bf54857SBaptiste Daroussin 
621*4bf54857SBaptiste Daroussin 	result = ucl_object_emit (obj, type);
622*4bf54857SBaptiste Daroussin 
623*4bf54857SBaptiste Daroussin 	if (result != NULL) {
624*4bf54857SBaptiste Daroussin 		lua_pushstring (L, (const char *)result);
625*4bf54857SBaptiste Daroussin 		free (result);
626*4bf54857SBaptiste Daroussin 	}
627*4bf54857SBaptiste Daroussin 	else {
628*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
629*4bf54857SBaptiste Daroussin 	}
630*4bf54857SBaptiste Daroussin 
631*4bf54857SBaptiste Daroussin 	return 1;
632*4bf54857SBaptiste Daroussin }
633*4bf54857SBaptiste Daroussin 
634*4bf54857SBaptiste Daroussin static int
635*4bf54857SBaptiste Daroussin lua_ucl_to_json (lua_State *L)
636*4bf54857SBaptiste Daroussin {
637*4bf54857SBaptiste Daroussin 	ucl_object_t *obj;
638*4bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
639*4bf54857SBaptiste Daroussin 
640*4bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
641*4bf54857SBaptiste Daroussin 		if (lua_toboolean (L, 2)) {
642*4bf54857SBaptiste Daroussin 			format = UCL_EMIT_JSON_COMPACT;
643*4bf54857SBaptiste Daroussin 		}
644*4bf54857SBaptiste Daroussin 	}
645*4bf54857SBaptiste Daroussin 
646*4bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
647*4bf54857SBaptiste Daroussin 	if (obj != NULL) {
648*4bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
649*4bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
650*4bf54857SBaptiste Daroussin 	}
651*4bf54857SBaptiste Daroussin 	else {
652*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
653*4bf54857SBaptiste Daroussin 	}
654*4bf54857SBaptiste Daroussin 
655*4bf54857SBaptiste Daroussin 	return 1;
656*4bf54857SBaptiste Daroussin }
657*4bf54857SBaptiste Daroussin 
658*4bf54857SBaptiste Daroussin static int
659*4bf54857SBaptiste Daroussin lua_ucl_to_config (lua_State *L)
660*4bf54857SBaptiste Daroussin {
661*4bf54857SBaptiste Daroussin 	ucl_object_t *obj;
662*4bf54857SBaptiste Daroussin 
663*4bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
664*4bf54857SBaptiste Daroussin 	if (obj != NULL) {
665*4bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
666*4bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
667*4bf54857SBaptiste Daroussin 	}
668*4bf54857SBaptiste Daroussin 	else {
669*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
670*4bf54857SBaptiste Daroussin 	}
671*4bf54857SBaptiste Daroussin 
672*4bf54857SBaptiste Daroussin 	return 1;
673*4bf54857SBaptiste Daroussin }
674*4bf54857SBaptiste Daroussin 
675*4bf54857SBaptiste Daroussin /***
676*4bf54857SBaptiste Daroussin  * @function ucl.to_format(var, format)
677*4bf54857SBaptiste Daroussin  * Converts lua variable `var` to the specified `format`. Formats supported are:
678*4bf54857SBaptiste Daroussin  *
679*4bf54857SBaptiste Daroussin  * - `json` - fine printed json
680*4bf54857SBaptiste Daroussin  * - `json-compact` - compacted json
681*4bf54857SBaptiste Daroussin  * - `config` - fine printed configuration
682*4bf54857SBaptiste Daroussin  * - `ucl` - same as `config`
683*4bf54857SBaptiste Daroussin  * - `yaml` - embedded yaml
684*4bf54857SBaptiste Daroussin  *
685*4bf54857SBaptiste Daroussin  * If `var` contains function, they are called during output formatting and if
686*4bf54857SBaptiste Daroussin  * they return string value, then this value is used for ouptut.
687*4bf54857SBaptiste Daroussin  * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
688*4bf54857SBaptiste Daroussin  * @param {string} format any available format
689*4bf54857SBaptiste Daroussin  * @return {string} string representation of `var` in the specific `format`.
690*4bf54857SBaptiste Daroussin  * @example
691*4bf54857SBaptiste Daroussin local table = {
692*4bf54857SBaptiste Daroussin   str = 'value',
693*4bf54857SBaptiste Daroussin   num = 100500,
694*4bf54857SBaptiste Daroussin   null = ucl.null,
695*4bf54857SBaptiste Daroussin   func = function ()
696*4bf54857SBaptiste Daroussin     return 'huh'
697*4bf54857SBaptiste Daroussin   end
698*4bf54857SBaptiste Daroussin }
699*4bf54857SBaptiste Daroussin 
700*4bf54857SBaptiste Daroussin print(ucl.to_format(table, 'ucl'))
701*4bf54857SBaptiste Daroussin -- Output:
702*4bf54857SBaptiste Daroussin --[[
703*4bf54857SBaptiste Daroussin num = 100500;
704*4bf54857SBaptiste Daroussin str = "value";
705*4bf54857SBaptiste Daroussin null = null;
706*4bf54857SBaptiste Daroussin func = "huh";
707*4bf54857SBaptiste Daroussin --]]
708*4bf54857SBaptiste Daroussin  */
709*4bf54857SBaptiste Daroussin static int
710*4bf54857SBaptiste Daroussin lua_ucl_to_format (lua_State *L)
711*4bf54857SBaptiste Daroussin {
712*4bf54857SBaptiste Daroussin 	ucl_object_t *obj;
713*4bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
714*4bf54857SBaptiste Daroussin 
715*4bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
716*4bf54857SBaptiste Daroussin 		if (lua_type (L, 2) == LUA_TNUMBER) {
717*4bf54857SBaptiste Daroussin 			format = lua_tonumber (L, 2);
718*4bf54857SBaptiste Daroussin 			if (format < 0 || format >= UCL_EMIT_YAML) {
719*4bf54857SBaptiste Daroussin 				lua_pushnil (L);
720*4bf54857SBaptiste Daroussin 				return 1;
721*4bf54857SBaptiste Daroussin 			}
722*4bf54857SBaptiste Daroussin 		}
723*4bf54857SBaptiste Daroussin 		else if (lua_type (L, 2) == LUA_TSTRING) {
724*4bf54857SBaptiste Daroussin 			const char *strtype = lua_tostring (L, 2);
725*4bf54857SBaptiste Daroussin 
726*4bf54857SBaptiste Daroussin 			if (strcasecmp (strtype, "json") == 0) {
727*4bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON;
728*4bf54857SBaptiste Daroussin 			}
729*4bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "json-compact") == 0) {
730*4bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON_COMPACT;
731*4bf54857SBaptiste Daroussin 			}
732*4bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "yaml") == 0) {
733*4bf54857SBaptiste Daroussin 				format = UCL_EMIT_YAML;
734*4bf54857SBaptiste Daroussin 			}
735*4bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "config") == 0 ||
736*4bf54857SBaptiste Daroussin 				strcasecmp (strtype, "ucl") == 0) {
737*4bf54857SBaptiste Daroussin 				format = UCL_EMIT_CONFIG;
738*4bf54857SBaptiste Daroussin 			}
739*4bf54857SBaptiste Daroussin 		}
740*4bf54857SBaptiste Daroussin 	}
741*4bf54857SBaptiste Daroussin 
742*4bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
743*4bf54857SBaptiste Daroussin 	if (obj != NULL) {
744*4bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
745*4bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
746*4bf54857SBaptiste Daroussin 	}
747*4bf54857SBaptiste Daroussin 	else {
748*4bf54857SBaptiste Daroussin 		lua_pushnil (L);
749*4bf54857SBaptiste Daroussin 	}
750*4bf54857SBaptiste Daroussin 
751*4bf54857SBaptiste Daroussin 	return 1;
752*4bf54857SBaptiste Daroussin }
753*4bf54857SBaptiste Daroussin 
754*4bf54857SBaptiste Daroussin static int
755*4bf54857SBaptiste Daroussin lua_ucl_null_tostring (lua_State* L)
756*4bf54857SBaptiste Daroussin {
757*4bf54857SBaptiste Daroussin 	lua_pushstring (L, "null");
758*4bf54857SBaptiste Daroussin 	return 1;
759*4bf54857SBaptiste Daroussin }
760*4bf54857SBaptiste Daroussin 
761*4bf54857SBaptiste Daroussin static void
762*4bf54857SBaptiste Daroussin lua_ucl_null_mt (lua_State *L)
763*4bf54857SBaptiste Daroussin {
764*4bf54857SBaptiste Daroussin 	luaL_newmetatable (L, NULL_META);
765*4bf54857SBaptiste Daroussin 
766*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_null_tostring);
767*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
768*4bf54857SBaptiste Daroussin 
769*4bf54857SBaptiste Daroussin 	lua_pop (L, 1);
770*4bf54857SBaptiste Daroussin }
771*4bf54857SBaptiste Daroussin 
772*4bf54857SBaptiste Daroussin int
773*4bf54857SBaptiste Daroussin luaopen_ucl (lua_State *L)
774*4bf54857SBaptiste Daroussin {
775*4bf54857SBaptiste Daroussin 	lua_ucl_parser_mt (L);
776*4bf54857SBaptiste Daroussin 	lua_ucl_null_mt (L);
777*4bf54857SBaptiste Daroussin 
778*4bf54857SBaptiste Daroussin 	/* Create the refs weak table: */
779*4bf54857SBaptiste Daroussin 	lua_createtable (L, 0, 2);
780*4bf54857SBaptiste Daroussin 	lua_pushliteral (L, "v"); /* tbl, "v" */
781*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__mode");
782*4bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1); /* tbl, tbl */
783*4bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2); /* tbl */
784*4bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
785*4bf54857SBaptiste Daroussin 
786*4bf54857SBaptiste Daroussin 	lua_newtable (L);
787*4bf54857SBaptiste Daroussin 
788*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_init);
789*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parser");
790*4bf54857SBaptiste Daroussin 
791*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_json);
792*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_json");
793*4bf54857SBaptiste Daroussin 
794*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_config);
795*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_config");
796*4bf54857SBaptiste Daroussin 
797*4bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_format);
798*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_format");
799*4bf54857SBaptiste Daroussin 
800*4bf54857SBaptiste Daroussin 	ucl_null = lua_newuserdata (L, 0);
801*4bf54857SBaptiste Daroussin 	luaL_getmetatable (L, NULL_META);
802*4bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
803*4bf54857SBaptiste Daroussin 
804*4bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1);
805*4bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
806*4bf54857SBaptiste Daroussin 
807*4bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "null");
808*4bf54857SBaptiste Daroussin 
809*4bf54857SBaptiste Daroussin 	return 1;
810*4bf54857SBaptiste Daroussin }
811*4bf54857SBaptiste Daroussin 
812*4bf54857SBaptiste Daroussin struct ucl_lua_funcdata*
813*4bf54857SBaptiste Daroussin ucl_object_toclosure (const ucl_object_t *obj)
814*4bf54857SBaptiste Daroussin {
815*4bf54857SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_USERDATA) {
816*4bf54857SBaptiste Daroussin 		return NULL;
817*4bf54857SBaptiste Daroussin 	}
818*4bf54857SBaptiste Daroussin 
819*4bf54857SBaptiste Daroussin 	return (struct ucl_lua_funcdata*)obj->value.ud;
820*4bf54857SBaptiste Daroussin }
821