xref: /freebsd/contrib/libucl/lua/lua_ucl.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
14bf54857SBaptiste Daroussin /* Copyright (c) 2014, Vsevolod Stakhov
24bf54857SBaptiste Daroussin  * All rights reserved.
34bf54857SBaptiste Daroussin  *
44bf54857SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
54bf54857SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
64bf54857SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
74bf54857SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
84bf54857SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
94bf54857SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
104bf54857SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
114bf54857SBaptiste Daroussin  *
124bf54857SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
134bf54857SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
144bf54857SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
154bf54857SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
164bf54857SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
174bf54857SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
184bf54857SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
194bf54857SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
204bf54857SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
214bf54857SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
224bf54857SBaptiste Daroussin  */
234bf54857SBaptiste Daroussin 
244bf54857SBaptiste Daroussin /**
254bf54857SBaptiste Daroussin  * @file lua ucl bindings
264bf54857SBaptiste Daroussin  */
274bf54857SBaptiste Daroussin 
284bf54857SBaptiste Daroussin #include "ucl.h"
294bf54857SBaptiste Daroussin #include "ucl_internal.h"
304bf54857SBaptiste Daroussin #include "lua_ucl.h"
314bf54857SBaptiste Daroussin #include <strings.h>
324bf54857SBaptiste Daroussin 
334bf54857SBaptiste Daroussin /***
344bf54857SBaptiste Daroussin  * @module ucl
354bf54857SBaptiste Daroussin  * This lua module allows to parse objects from strings and to store data into
364bf54857SBaptiste Daroussin  * ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
374bf54857SBaptiste Daroussin  * @example
384bf54857SBaptiste Daroussin local ucl = require("ucl")
394bf54857SBaptiste Daroussin 
404bf54857SBaptiste Daroussin local parser = ucl.parser()
414bf54857SBaptiste Daroussin local res,err = parser:parse_string('{key=value}')
424bf54857SBaptiste Daroussin 
434bf54857SBaptiste Daroussin if not res then
444bf54857SBaptiste Daroussin 	print('parser error: ' .. err)
454bf54857SBaptiste Daroussin else
464bf54857SBaptiste Daroussin 	local obj = parser:get_object()
474bf54857SBaptiste Daroussin 	local got = ucl.to_format(obj, 'json')
484bf54857SBaptiste Daroussin endif
494bf54857SBaptiste Daroussin 
504bf54857SBaptiste Daroussin local table = {
514bf54857SBaptiste Daroussin   str = 'value',
524bf54857SBaptiste Daroussin   num = 100500,
534bf54857SBaptiste Daroussin   null = ucl.null,
544bf54857SBaptiste Daroussin   func = function ()
554bf54857SBaptiste Daroussin     return 'huh'
564bf54857SBaptiste Daroussin   end
574bf54857SBaptiste Daroussin }
584bf54857SBaptiste Daroussin 
594bf54857SBaptiste Daroussin print(ucl.to_format(table, 'ucl'))
604bf54857SBaptiste Daroussin -- Output:
614bf54857SBaptiste Daroussin --[[
624bf54857SBaptiste Daroussin num = 100500;
634bf54857SBaptiste Daroussin str = "value";
644bf54857SBaptiste Daroussin null = null;
654bf54857SBaptiste Daroussin func = "huh";
664bf54857SBaptiste Daroussin --]]
674bf54857SBaptiste Daroussin  */
684bf54857SBaptiste Daroussin 
694bf54857SBaptiste Daroussin #define PARSER_META "ucl.parser.meta"
704bf54857SBaptiste Daroussin #define EMITTER_META "ucl.emitter.meta"
714bf54857SBaptiste Daroussin #define NULL_META "null.emitter.meta"
72*39ee7a7aSBaptiste Daroussin #define OBJECT_META "ucl.object.meta"
734bf54857SBaptiste Daroussin 
744bf54857SBaptiste Daroussin static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
754bf54857SBaptiste Daroussin static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
764bf54857SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
774bf54857SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
784bf54857SBaptiste Daroussin 
794bf54857SBaptiste Daroussin static void *ucl_null;
804bf54857SBaptiste Daroussin 
814bf54857SBaptiste Daroussin /**
824bf54857SBaptiste Daroussin  * Push a single element of an object to lua
834bf54857SBaptiste Daroussin  * @param L
844bf54857SBaptiste Daroussin  * @param key
854bf54857SBaptiste Daroussin  * @param obj
864bf54857SBaptiste Daroussin  */
874bf54857SBaptiste Daroussin static void
884bf54857SBaptiste Daroussin ucl_object_lua_push_element (lua_State *L, const char *key,
894bf54857SBaptiste Daroussin 		const ucl_object_t *obj)
904bf54857SBaptiste Daroussin {
914bf54857SBaptiste Daroussin 	lua_pushstring (L, key);
924bf54857SBaptiste Daroussin 	ucl_object_push_lua (L, obj, true);
934bf54857SBaptiste Daroussin 	lua_settable (L, -3);
944bf54857SBaptiste Daroussin }
954bf54857SBaptiste Daroussin 
964bf54857SBaptiste Daroussin static void
974bf54857SBaptiste Daroussin lua_ucl_userdata_dtor (void *ud)
984bf54857SBaptiste Daroussin {
994bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
1004bf54857SBaptiste Daroussin 
1014bf54857SBaptiste Daroussin 	luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
1024bf54857SBaptiste Daroussin 	if (fd->ret != NULL) {
1034bf54857SBaptiste Daroussin 		free (fd->ret);
1044bf54857SBaptiste Daroussin 	}
1054bf54857SBaptiste Daroussin 	free (fd);
1064bf54857SBaptiste Daroussin }
1074bf54857SBaptiste Daroussin 
1084bf54857SBaptiste Daroussin static const char *
1094bf54857SBaptiste Daroussin lua_ucl_userdata_emitter (void *ud)
1104bf54857SBaptiste Daroussin {
1114bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
1124bf54857SBaptiste Daroussin 	const char *out = "";
1134bf54857SBaptiste Daroussin 
1144bf54857SBaptiste Daroussin 	lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
1154bf54857SBaptiste Daroussin 
1164bf54857SBaptiste Daroussin 	lua_pcall (fd->L, 0, 1, 0);
1174bf54857SBaptiste Daroussin 	out = lua_tostring (fd->L, -1);
1184bf54857SBaptiste Daroussin 
1194bf54857SBaptiste Daroussin 	if (out != NULL) {
1204bf54857SBaptiste Daroussin 		/* We need to store temporary string in a more appropriate place */
1214bf54857SBaptiste Daroussin 		if (fd->ret) {
1224bf54857SBaptiste Daroussin 			free (fd->ret);
1234bf54857SBaptiste Daroussin 		}
1244bf54857SBaptiste Daroussin 		fd->ret = strdup (out);
1254bf54857SBaptiste Daroussin 	}
1264bf54857SBaptiste Daroussin 
1274bf54857SBaptiste Daroussin 	lua_settop (fd->L, 0);
1284bf54857SBaptiste Daroussin 
1294bf54857SBaptiste Daroussin 	return fd->ret;
1304bf54857SBaptiste Daroussin }
1314bf54857SBaptiste Daroussin 
1324bf54857SBaptiste Daroussin /**
1334bf54857SBaptiste Daroussin  * Push a single object to lua
1344bf54857SBaptiste Daroussin  * @param L
1354bf54857SBaptiste Daroussin  * @param obj
1364bf54857SBaptiste Daroussin  * @return
1374bf54857SBaptiste Daroussin  */
1384bf54857SBaptiste Daroussin static int
1394bf54857SBaptiste Daroussin ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
1404bf54857SBaptiste Daroussin 		bool allow_array)
1414bf54857SBaptiste Daroussin {
1424bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
1434bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
1444bf54857SBaptiste Daroussin 	int nelt = 0;
1454bf54857SBaptiste Daroussin 
1464bf54857SBaptiste Daroussin 	if (allow_array && obj->next != NULL) {
1474bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
1484bf54857SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj);
1494bf54857SBaptiste Daroussin 	}
1504bf54857SBaptiste Daroussin 
1514bf54857SBaptiste Daroussin 	/* Optimize allocation by preallocation of table */
1524bf54857SBaptiste Daroussin 	while (ucl_iterate_object (obj, &it, true) != NULL) {
1534bf54857SBaptiste Daroussin 		nelt ++;
1544bf54857SBaptiste Daroussin 	}
1554bf54857SBaptiste Daroussin 
1564bf54857SBaptiste Daroussin 	lua_createtable (L, 0, nelt);
1574bf54857SBaptiste Daroussin 	it = NULL;
1584bf54857SBaptiste Daroussin 
1594bf54857SBaptiste Daroussin 	while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
1604bf54857SBaptiste Daroussin 		ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
1614bf54857SBaptiste Daroussin 	}
1624bf54857SBaptiste Daroussin 
1634bf54857SBaptiste Daroussin 	return 1;
1644bf54857SBaptiste Daroussin }
1654bf54857SBaptiste Daroussin 
1664bf54857SBaptiste Daroussin /**
1674bf54857SBaptiste Daroussin  * Push an array to lua as table indexed by integers
1684bf54857SBaptiste Daroussin  * @param L
1694bf54857SBaptiste Daroussin  * @param obj
1704bf54857SBaptiste Daroussin  * @return
1714bf54857SBaptiste Daroussin  */
1724bf54857SBaptiste Daroussin static int
1734bf54857SBaptiste Daroussin ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
1744bf54857SBaptiste Daroussin {
1754bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
176*39ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it;
1774bf54857SBaptiste Daroussin 	int i = 1, nelt = 0;
1784bf54857SBaptiste Daroussin 
179*39ee7a7aSBaptiste Daroussin 	if (obj->type == UCL_ARRAY) {
180*39ee7a7aSBaptiste Daroussin 		nelt = obj->len;
181*39ee7a7aSBaptiste Daroussin 		it = ucl_object_iterate_new (obj);
182*39ee7a7aSBaptiste Daroussin 		lua_createtable (L, nelt, 0);
183*39ee7a7aSBaptiste Daroussin 
184*39ee7a7aSBaptiste Daroussin 		while ((cur = ucl_object_iterate_safe (it, true))) {
185*39ee7a7aSBaptiste Daroussin 			ucl_object_push_lua (L, cur, false);
186*39ee7a7aSBaptiste Daroussin 			lua_rawseti (L, -2, i);
187*39ee7a7aSBaptiste Daroussin 			i ++;
188*39ee7a7aSBaptiste Daroussin 		}
189*39ee7a7aSBaptiste Daroussin 	}
190*39ee7a7aSBaptiste Daroussin 	else {
1914bf54857SBaptiste Daroussin 		/* Optimize allocation by preallocation of table */
1924bf54857SBaptiste Daroussin 		LL_FOREACH (obj, cur) {
1934bf54857SBaptiste Daroussin 			nelt ++;
1944bf54857SBaptiste Daroussin 		}
1954bf54857SBaptiste Daroussin 
1964bf54857SBaptiste Daroussin 		lua_createtable (L, nelt, 0);
1974bf54857SBaptiste Daroussin 
1984bf54857SBaptiste Daroussin 		LL_FOREACH (obj, cur) {
1994bf54857SBaptiste Daroussin 			ucl_object_push_lua (L, cur, false);
2004bf54857SBaptiste Daroussin 			lua_rawseti (L, -2, i);
2014bf54857SBaptiste Daroussin 			i ++;
2024bf54857SBaptiste Daroussin 		}
203*39ee7a7aSBaptiste Daroussin 	}
2044bf54857SBaptiste Daroussin 
2054bf54857SBaptiste Daroussin 	return 1;
2064bf54857SBaptiste Daroussin }
2074bf54857SBaptiste Daroussin 
2084bf54857SBaptiste Daroussin /**
2094bf54857SBaptiste Daroussin  * Push a simple object to lua depending on its actual type
2104bf54857SBaptiste Daroussin  */
2114bf54857SBaptiste Daroussin static int
2124bf54857SBaptiste Daroussin ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
2134bf54857SBaptiste Daroussin 		bool allow_array)
2144bf54857SBaptiste Daroussin {
2154bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
2164bf54857SBaptiste Daroussin 
2174bf54857SBaptiste Daroussin 	if (allow_array && obj->next != NULL) {
2184bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
2194bf54857SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj);
2204bf54857SBaptiste Daroussin 	}
2214bf54857SBaptiste Daroussin 
2224bf54857SBaptiste Daroussin 	switch (obj->type) {
2234bf54857SBaptiste Daroussin 	case UCL_BOOLEAN:
2244bf54857SBaptiste Daroussin 		lua_pushboolean (L, ucl_obj_toboolean (obj));
2254bf54857SBaptiste Daroussin 		break;
2264bf54857SBaptiste Daroussin 	case UCL_STRING:
2274bf54857SBaptiste Daroussin 		lua_pushstring (L, ucl_obj_tostring (obj));
2284bf54857SBaptiste Daroussin 		break;
2294bf54857SBaptiste Daroussin 	case UCL_INT:
2304bf54857SBaptiste Daroussin #if LUA_VERSION_NUM >= 501
2314bf54857SBaptiste Daroussin 		lua_pushinteger (L, ucl_obj_toint (obj));
2324bf54857SBaptiste Daroussin #else
2334bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_toint (obj));
2344bf54857SBaptiste Daroussin #endif
2354bf54857SBaptiste Daroussin 		break;
2364bf54857SBaptiste Daroussin 	case UCL_FLOAT:
2374bf54857SBaptiste Daroussin 	case UCL_TIME:
2384bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_todouble (obj));
2394bf54857SBaptiste Daroussin 		break;
2404bf54857SBaptiste Daroussin 	case UCL_NULL:
2414bf54857SBaptiste Daroussin 		lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
2424bf54857SBaptiste Daroussin 		break;
2434bf54857SBaptiste Daroussin 	case UCL_USERDATA:
2444bf54857SBaptiste Daroussin 		fd = (struct ucl_lua_funcdata *)obj->value.ud;
2454bf54857SBaptiste Daroussin 		lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
2464bf54857SBaptiste Daroussin 		break;
2474bf54857SBaptiste Daroussin 	default:
2484bf54857SBaptiste Daroussin 		lua_pushnil (L);
2494bf54857SBaptiste Daroussin 		break;
2504bf54857SBaptiste Daroussin 	}
2514bf54857SBaptiste Daroussin 
2524bf54857SBaptiste Daroussin 	return 1;
2534bf54857SBaptiste Daroussin }
2544bf54857SBaptiste Daroussin 
2554bf54857SBaptiste Daroussin /***
2564bf54857SBaptiste Daroussin  * @function ucl_object_push_lua(L, obj, allow_array)
2574bf54857SBaptiste Daroussin  * This is a `C` function to push `UCL` object as lua variable. This function
2584bf54857SBaptiste Daroussin  * converts `obj` to lua representation using the following conversions:
2594bf54857SBaptiste Daroussin  *
2604bf54857SBaptiste Daroussin  * - *scalar* values are directly presented by lua objects
2614bf54857SBaptiste Daroussin  * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
2624bf54857SBaptiste Daroussin  * this can be used to pass functions from lua to c and vice-versa
2634bf54857SBaptiste Daroussin  * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
2644bf54857SBaptiste Daroussin  * - *objects* are converted to lua tables with string indicies
2654bf54857SBaptiste Daroussin  * @param {lua_State} L lua state pointer
2664bf54857SBaptiste Daroussin  * @param {ucl_object_t} obj object to push
2674bf54857SBaptiste Daroussin  * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
2684bf54857SBaptiste Daroussin  * @return {int} `1` if an object is pushed to lua
2694bf54857SBaptiste Daroussin  */
2704bf54857SBaptiste Daroussin int
2714bf54857SBaptiste Daroussin ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
2724bf54857SBaptiste Daroussin {
2734bf54857SBaptiste Daroussin 	switch (obj->type) {
2744bf54857SBaptiste Daroussin 	case UCL_OBJECT:
2754bf54857SBaptiste Daroussin 		return ucl_object_lua_push_object (L, obj, allow_array);
2764bf54857SBaptiste Daroussin 	case UCL_ARRAY:
277*39ee7a7aSBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj);
2784bf54857SBaptiste Daroussin 	default:
2794bf54857SBaptiste Daroussin 		return ucl_object_lua_push_scalar (L, obj, allow_array);
2804bf54857SBaptiste Daroussin 	}
2814bf54857SBaptiste Daroussin }
2824bf54857SBaptiste Daroussin 
2834bf54857SBaptiste Daroussin /**
2844bf54857SBaptiste Daroussin  * Parse lua table into object top
2854bf54857SBaptiste Daroussin  * @param L
2864bf54857SBaptiste Daroussin  * @param top
2874bf54857SBaptiste Daroussin  * @param idx
2884bf54857SBaptiste Daroussin  */
2894bf54857SBaptiste Daroussin static ucl_object_t *
2904bf54857SBaptiste Daroussin ucl_object_lua_fromtable (lua_State *L, int idx)
2914bf54857SBaptiste Daroussin {
2924bf54857SBaptiste Daroussin 	ucl_object_t *obj, *top = NULL;
2934bf54857SBaptiste Daroussin 	size_t keylen;
2944bf54857SBaptiste Daroussin 	const char *k;
2954bf54857SBaptiste Daroussin 	bool is_array = true;
2964bf54857SBaptiste Daroussin 	int max = INT_MIN;
2974bf54857SBaptiste Daroussin 
2984bf54857SBaptiste Daroussin 	if (idx < 0) {
2994bf54857SBaptiste Daroussin 		/* For negative indicies we want to invert them */
3004bf54857SBaptiste Daroussin 		idx = lua_gettop (L) + idx + 1;
3014bf54857SBaptiste Daroussin 	}
3024bf54857SBaptiste Daroussin 	/* Check for array */
3034bf54857SBaptiste Daroussin 	lua_pushnil (L);
3044bf54857SBaptiste Daroussin 	while (lua_next (L, idx) != 0) {
3054bf54857SBaptiste Daroussin 		if (lua_type (L, -2) == LUA_TNUMBER) {
3064bf54857SBaptiste Daroussin 			double num = lua_tonumber (L, -2);
3074bf54857SBaptiste Daroussin 			if (num == (int)num) {
3084bf54857SBaptiste Daroussin 				if (num > max) {
3094bf54857SBaptiste Daroussin 					max = num;
3104bf54857SBaptiste Daroussin 				}
3114bf54857SBaptiste Daroussin 			}
3124bf54857SBaptiste Daroussin 			else {
3134bf54857SBaptiste Daroussin 				/* Keys are not integer */
3144bf54857SBaptiste Daroussin 				lua_pop (L, 2);
3154bf54857SBaptiste Daroussin 				is_array = false;
3164bf54857SBaptiste Daroussin 				break;
3174bf54857SBaptiste Daroussin 			}
3184bf54857SBaptiste Daroussin 		}
3194bf54857SBaptiste Daroussin 		else {
3204bf54857SBaptiste Daroussin 			/* Keys are not numeric */
3214bf54857SBaptiste Daroussin 			lua_pop (L, 2);
3224bf54857SBaptiste Daroussin 			is_array = false;
3234bf54857SBaptiste Daroussin 			break;
3244bf54857SBaptiste Daroussin 		}
3254bf54857SBaptiste Daroussin 		lua_pop (L, 1);
3264bf54857SBaptiste Daroussin 	}
3274bf54857SBaptiste Daroussin 
3284bf54857SBaptiste Daroussin 	/* Table iterate */
3294bf54857SBaptiste Daroussin 	if (is_array) {
3304bf54857SBaptiste Daroussin 		int i;
3314bf54857SBaptiste Daroussin 
3324bf54857SBaptiste Daroussin 		top = ucl_object_typed_new (UCL_ARRAY);
3334bf54857SBaptiste Daroussin 		for (i = 1; i <= max; i ++) {
3344bf54857SBaptiste Daroussin 			lua_pushinteger (L, i);
3354bf54857SBaptiste Daroussin 			lua_gettable (L, idx);
3364bf54857SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
3374bf54857SBaptiste Daroussin 			if (obj != NULL) {
3384bf54857SBaptiste Daroussin 				ucl_array_append (top, obj);
3394bf54857SBaptiste Daroussin 			}
340*39ee7a7aSBaptiste Daroussin 			lua_pop (L, 1);
3414bf54857SBaptiste Daroussin 		}
3424bf54857SBaptiste Daroussin 	}
3434bf54857SBaptiste Daroussin 	else {
3444bf54857SBaptiste Daroussin 		lua_pushnil (L);
3454bf54857SBaptiste Daroussin 		top = ucl_object_typed_new (UCL_OBJECT);
3464bf54857SBaptiste Daroussin 		while (lua_next (L, idx) != 0) {
3474bf54857SBaptiste Daroussin 			/* copy key to avoid modifications */
3484bf54857SBaptiste Daroussin 			k = lua_tolstring (L, -2, &keylen);
3494bf54857SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
3504bf54857SBaptiste Daroussin 
3514bf54857SBaptiste Daroussin 			if (obj != NULL) {
3524bf54857SBaptiste Daroussin 				ucl_object_insert_key (top, obj, k, keylen, true);
3534bf54857SBaptiste Daroussin 			}
3544bf54857SBaptiste Daroussin 			lua_pop (L, 1);
3554bf54857SBaptiste Daroussin 		}
3564bf54857SBaptiste Daroussin 	}
3574bf54857SBaptiste Daroussin 
3584bf54857SBaptiste Daroussin 	return top;
3594bf54857SBaptiste Daroussin }
3604bf54857SBaptiste Daroussin 
3614bf54857SBaptiste Daroussin /**
3624bf54857SBaptiste Daroussin  * Get a single element from lua to object obj
3634bf54857SBaptiste Daroussin  * @param L
3644bf54857SBaptiste Daroussin  * @param obj
3654bf54857SBaptiste Daroussin  * @param idx
3664bf54857SBaptiste Daroussin  */
3674bf54857SBaptiste Daroussin static ucl_object_t *
3684bf54857SBaptiste Daroussin ucl_object_lua_fromelt (lua_State *L, int idx)
3694bf54857SBaptiste Daroussin {
3704bf54857SBaptiste Daroussin 	int type;
3714bf54857SBaptiste Daroussin 	double num;
3724bf54857SBaptiste Daroussin 	ucl_object_t *obj = NULL;
3734bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
3744bf54857SBaptiste Daroussin 
3754bf54857SBaptiste Daroussin 	type = lua_type (L, idx);
3764bf54857SBaptiste Daroussin 
3774bf54857SBaptiste Daroussin 	switch (type) {
3784bf54857SBaptiste Daroussin 	case LUA_TSTRING:
3794bf54857SBaptiste Daroussin 		obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
3804bf54857SBaptiste Daroussin 		break;
3814bf54857SBaptiste Daroussin 	case LUA_TNUMBER:
3824bf54857SBaptiste Daroussin 		num = lua_tonumber (L, idx);
3834bf54857SBaptiste Daroussin 		if (num == (int64_t)num) {
3844bf54857SBaptiste Daroussin 			obj = ucl_object_fromint (num);
3854bf54857SBaptiste Daroussin 		}
3864bf54857SBaptiste Daroussin 		else {
3874bf54857SBaptiste Daroussin 			obj = ucl_object_fromdouble (num);
3884bf54857SBaptiste Daroussin 		}
3894bf54857SBaptiste Daroussin 		break;
3904bf54857SBaptiste Daroussin 	case LUA_TBOOLEAN:
3914bf54857SBaptiste Daroussin 		obj = ucl_object_frombool (lua_toboolean (L, idx));
3924bf54857SBaptiste Daroussin 		break;
3934bf54857SBaptiste Daroussin 	case LUA_TUSERDATA:
3944bf54857SBaptiste Daroussin 		if (lua_topointer (L, idx) == ucl_null) {
3954bf54857SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_NULL);
3964bf54857SBaptiste Daroussin 		}
3974bf54857SBaptiste Daroussin 		break;
3984bf54857SBaptiste Daroussin 	case LUA_TTABLE:
3994bf54857SBaptiste Daroussin 	case LUA_TFUNCTION:
4004bf54857SBaptiste Daroussin 	case LUA_TTHREAD:
4014bf54857SBaptiste Daroussin 		if (luaL_getmetafield (L, idx, "__gen_ucl")) {
4024bf54857SBaptiste Daroussin 			if (lua_isfunction (L, -1)) {
4034bf54857SBaptiste Daroussin 				lua_settop (L, 3); /* gen, obj, func */
4044bf54857SBaptiste Daroussin 				lua_insert (L, 1); /* func, gen, obj */
4054bf54857SBaptiste Daroussin 				lua_insert (L, 2); /* func, obj, gen */
4064bf54857SBaptiste Daroussin 				lua_call(L, 2, 1);
4074bf54857SBaptiste Daroussin 				obj = ucl_object_lua_fromelt (L, 1);
4084bf54857SBaptiste Daroussin 			}
4094bf54857SBaptiste Daroussin 			lua_pop (L, 2);
4104bf54857SBaptiste Daroussin 		}
4114bf54857SBaptiste Daroussin 		else {
4124bf54857SBaptiste Daroussin 			if (type == LUA_TTABLE) {
4134bf54857SBaptiste Daroussin 				obj = ucl_object_lua_fromtable (L, idx);
4144bf54857SBaptiste Daroussin 			}
4154bf54857SBaptiste Daroussin 			else if (type == LUA_TFUNCTION) {
4164bf54857SBaptiste Daroussin 				fd = malloc (sizeof (*fd));
4174bf54857SBaptiste Daroussin 				if (fd != NULL) {
4184bf54857SBaptiste Daroussin 					lua_pushvalue (L, idx);
4194bf54857SBaptiste Daroussin 					fd->L = L;
4204bf54857SBaptiste Daroussin 					fd->ret = NULL;
4214bf54857SBaptiste Daroussin 					fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
4224bf54857SBaptiste Daroussin 
4234bf54857SBaptiste Daroussin 					obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
4244bf54857SBaptiste Daroussin 							lua_ucl_userdata_emitter);
4254bf54857SBaptiste Daroussin 					obj->type = UCL_USERDATA;
4264bf54857SBaptiste Daroussin 					obj->value.ud = (void *)fd;
4274bf54857SBaptiste Daroussin 				}
4284bf54857SBaptiste Daroussin 			}
4294bf54857SBaptiste Daroussin 		}
4304bf54857SBaptiste Daroussin 		break;
4314bf54857SBaptiste Daroussin 	}
4324bf54857SBaptiste Daroussin 
4334bf54857SBaptiste Daroussin 	return obj;
4344bf54857SBaptiste Daroussin }
4354bf54857SBaptiste Daroussin 
4364bf54857SBaptiste Daroussin /**
4374bf54857SBaptiste Daroussin  * @function ucl_object_lua_import(L, idx)
4384bf54857SBaptiste Daroussin  * Extracts ucl object from lua variable at `idx` position,
4394bf54857SBaptiste Daroussin  * @see ucl_object_push_lua for conversion definitions
4404bf54857SBaptiste Daroussin  * @param {lua_state} L lua state machine pointer
4414bf54857SBaptiste Daroussin  * @param {int} idx index where the source variable is placed
4424bf54857SBaptiste Daroussin  * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
4434bf54857SBaptiste Daroussin  * this object thus needs to be unref'ed after usage.
4444bf54857SBaptiste Daroussin  */
4454bf54857SBaptiste Daroussin ucl_object_t *
4464bf54857SBaptiste Daroussin ucl_object_lua_import (lua_State *L, int idx)
4474bf54857SBaptiste Daroussin {
4484bf54857SBaptiste Daroussin 	ucl_object_t *obj;
4494bf54857SBaptiste Daroussin 	int t;
4504bf54857SBaptiste Daroussin 
4514bf54857SBaptiste Daroussin 	t = lua_type (L, idx);
4524bf54857SBaptiste Daroussin 	switch (t) {
4534bf54857SBaptiste Daroussin 	case LUA_TTABLE:
4544bf54857SBaptiste Daroussin 		obj = ucl_object_lua_fromtable (L, idx);
4554bf54857SBaptiste Daroussin 		break;
4564bf54857SBaptiste Daroussin 	default:
4574bf54857SBaptiste Daroussin 		obj = ucl_object_lua_fromelt (L, idx);
4584bf54857SBaptiste Daroussin 		break;
4594bf54857SBaptiste Daroussin 	}
4604bf54857SBaptiste Daroussin 
4614bf54857SBaptiste Daroussin 	return obj;
4624bf54857SBaptiste Daroussin }
4634bf54857SBaptiste Daroussin 
4644bf54857SBaptiste Daroussin static int
465*39ee7a7aSBaptiste Daroussin lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
466*39ee7a7aSBaptiste Daroussin {
467*39ee7a7aSBaptiste Daroussin 	unsigned char *result;
468*39ee7a7aSBaptiste Daroussin 
469*39ee7a7aSBaptiste Daroussin 	result = ucl_object_emit (obj, type);
470*39ee7a7aSBaptiste Daroussin 
471*39ee7a7aSBaptiste Daroussin 	if (result != NULL) {
472*39ee7a7aSBaptiste Daroussin 		lua_pushstring (L, (const char *)result);
473*39ee7a7aSBaptiste Daroussin 		free (result);
474*39ee7a7aSBaptiste Daroussin 	}
475*39ee7a7aSBaptiste Daroussin 	else {
476*39ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
477*39ee7a7aSBaptiste Daroussin 	}
478*39ee7a7aSBaptiste Daroussin 
479*39ee7a7aSBaptiste Daroussin 	return 1;
480*39ee7a7aSBaptiste Daroussin }
481*39ee7a7aSBaptiste Daroussin 
482*39ee7a7aSBaptiste Daroussin static int
4834bf54857SBaptiste Daroussin lua_ucl_parser_init (lua_State *L)
4844bf54857SBaptiste Daroussin {
4854bf54857SBaptiste Daroussin 	struct ucl_parser *parser, **pparser;
4864bf54857SBaptiste Daroussin 	int flags = 0;
4874bf54857SBaptiste Daroussin 
4884bf54857SBaptiste Daroussin 	if (lua_gettop (L) >= 1) {
4894bf54857SBaptiste Daroussin 		flags = lua_tonumber (L, 1);
4904bf54857SBaptiste Daroussin 	}
4914bf54857SBaptiste Daroussin 
4924bf54857SBaptiste Daroussin 	parser = ucl_parser_new (flags);
4934bf54857SBaptiste Daroussin 	if (parser == NULL) {
4944bf54857SBaptiste Daroussin 		lua_pushnil (L);
4954bf54857SBaptiste Daroussin 	}
4964bf54857SBaptiste Daroussin 
4974bf54857SBaptiste Daroussin 	pparser = lua_newuserdata (L, sizeof (parser));
4984bf54857SBaptiste Daroussin 	*pparser = parser;
4994bf54857SBaptiste Daroussin 	luaL_getmetatable (L, PARSER_META);
5004bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
5014bf54857SBaptiste Daroussin 
5024bf54857SBaptiste Daroussin 	return 1;
5034bf54857SBaptiste Daroussin }
5044bf54857SBaptiste Daroussin 
5054bf54857SBaptiste Daroussin static struct ucl_parser *
5064bf54857SBaptiste Daroussin lua_ucl_parser_get (lua_State *L, int index)
5074bf54857SBaptiste Daroussin {
5084bf54857SBaptiste Daroussin 	return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
5094bf54857SBaptiste Daroussin }
5104bf54857SBaptiste Daroussin 
511*39ee7a7aSBaptiste Daroussin static ucl_object_t *
512*39ee7a7aSBaptiste Daroussin lua_ucl_object_get (lua_State *L, int index)
513*39ee7a7aSBaptiste Daroussin {
514*39ee7a7aSBaptiste Daroussin 	return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
515*39ee7a7aSBaptiste Daroussin }
516*39ee7a7aSBaptiste Daroussin 
5174bf54857SBaptiste Daroussin /***
5184bf54857SBaptiste Daroussin  * @method parser:parse_file(name)
5194bf54857SBaptiste Daroussin  * Parse UCL object from file.
5204bf54857SBaptiste Daroussin  * @param {string} name filename to parse
5214bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
5224bf54857SBaptiste Daroussin @example
5234bf54857SBaptiste Daroussin local parser = ucl.parser()
5244bf54857SBaptiste Daroussin local res,err = parser:parse_file('/some/file.conf')
5254bf54857SBaptiste Daroussin 
5264bf54857SBaptiste Daroussin if not res then
5274bf54857SBaptiste Daroussin 	print('parser error: ' .. err)
5284bf54857SBaptiste Daroussin else
5294bf54857SBaptiste Daroussin 	-- Do something with object
5304bf54857SBaptiste Daroussin end
5314bf54857SBaptiste Daroussin  */
5324bf54857SBaptiste Daroussin static int
5334bf54857SBaptiste Daroussin lua_ucl_parser_parse_file (lua_State *L)
5344bf54857SBaptiste Daroussin {
5354bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
5364bf54857SBaptiste Daroussin 	const char *file;
5374bf54857SBaptiste Daroussin 	int ret = 2;
5384bf54857SBaptiste Daroussin 
5394bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
5404bf54857SBaptiste Daroussin 	file = luaL_checkstring (L, 2);
5414bf54857SBaptiste Daroussin 
5424bf54857SBaptiste Daroussin 	if (parser != NULL && file != NULL) {
5434bf54857SBaptiste Daroussin 		if (ucl_parser_add_file (parser, file)) {
5444bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
5454bf54857SBaptiste Daroussin 			ret = 1;
5464bf54857SBaptiste Daroussin 		}
5474bf54857SBaptiste Daroussin 		else {
5484bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
5494bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
5504bf54857SBaptiste Daroussin 		}
5514bf54857SBaptiste Daroussin 	}
5524bf54857SBaptiste Daroussin 	else {
5534bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
5544bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
5554bf54857SBaptiste Daroussin 	}
5564bf54857SBaptiste Daroussin 
5574bf54857SBaptiste Daroussin 	return ret;
5584bf54857SBaptiste Daroussin }
5594bf54857SBaptiste Daroussin 
5604bf54857SBaptiste Daroussin /***
5614bf54857SBaptiste Daroussin  * @method parser:parse_string(input)
5624bf54857SBaptiste Daroussin  * Parse UCL object from file.
5634bf54857SBaptiste Daroussin  * @param {string} input string to parse
5644bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
5654bf54857SBaptiste Daroussin  */
5664bf54857SBaptiste Daroussin static int
5674bf54857SBaptiste Daroussin lua_ucl_parser_parse_string (lua_State *L)
5684bf54857SBaptiste Daroussin {
5694bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
5704bf54857SBaptiste Daroussin 	const char *string;
5714bf54857SBaptiste Daroussin 	size_t llen;
5724bf54857SBaptiste Daroussin 	int ret = 2;
5734bf54857SBaptiste Daroussin 
5744bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
5754bf54857SBaptiste Daroussin 	string = luaL_checklstring (L, 2, &llen);
5764bf54857SBaptiste Daroussin 
5774bf54857SBaptiste Daroussin 	if (parser != NULL && string != NULL) {
5784bf54857SBaptiste Daroussin 		if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) {
5794bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
5804bf54857SBaptiste Daroussin 			ret = 1;
5814bf54857SBaptiste Daroussin 		}
5824bf54857SBaptiste Daroussin 		else {
5834bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
5844bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
5854bf54857SBaptiste Daroussin 		}
5864bf54857SBaptiste Daroussin 	}
5874bf54857SBaptiste Daroussin 	else {
5884bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
5894bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
5904bf54857SBaptiste Daroussin 	}
5914bf54857SBaptiste Daroussin 
5924bf54857SBaptiste Daroussin 	return ret;
5934bf54857SBaptiste Daroussin }
5944bf54857SBaptiste Daroussin 
5954bf54857SBaptiste Daroussin /***
5964bf54857SBaptiste Daroussin  * @method parser:get_object()
5974bf54857SBaptiste Daroussin  * Get top object from parser and export it to lua representation.
5984bf54857SBaptiste Daroussin  * @return {variant or nil} ucl object as lua native variable
5994bf54857SBaptiste Daroussin  */
6004bf54857SBaptiste Daroussin static int
6014bf54857SBaptiste Daroussin lua_ucl_parser_get_object (lua_State *L)
6024bf54857SBaptiste Daroussin {
6034bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
6044bf54857SBaptiste Daroussin 	ucl_object_t *obj;
6054bf54857SBaptiste Daroussin 	int ret = 1;
6064bf54857SBaptiste Daroussin 
6074bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
6084bf54857SBaptiste Daroussin 	obj = ucl_parser_get_object (parser);
6094bf54857SBaptiste Daroussin 
6104bf54857SBaptiste Daroussin 	if (obj != NULL) {
6114bf54857SBaptiste Daroussin 		ret = ucl_object_push_lua (L, obj, false);
6124bf54857SBaptiste Daroussin 		/* no need to keep reference */
6134bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
6144bf54857SBaptiste Daroussin 	}
6154bf54857SBaptiste Daroussin 	else {
6164bf54857SBaptiste Daroussin 		lua_pushnil (L);
6174bf54857SBaptiste Daroussin 	}
6184bf54857SBaptiste Daroussin 
6194bf54857SBaptiste Daroussin 	return ret;
6204bf54857SBaptiste Daroussin }
6214bf54857SBaptiste Daroussin 
622*39ee7a7aSBaptiste Daroussin /***
623*39ee7a7aSBaptiste Daroussin  * @method parser:get_object_wrapped()
624*39ee7a7aSBaptiste Daroussin  * Get top object from parser and export it to userdata object without
625*39ee7a7aSBaptiste Daroussin  * unwrapping to lua.
626*39ee7a7aSBaptiste Daroussin  * @return {ucl.object or nil} ucl object wrapped variable
627*39ee7a7aSBaptiste Daroussin  */
628*39ee7a7aSBaptiste Daroussin static int
629*39ee7a7aSBaptiste Daroussin lua_ucl_parser_get_object_wrapped (lua_State *L)
630*39ee7a7aSBaptiste Daroussin {
631*39ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser;
632*39ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, **pobj;
633*39ee7a7aSBaptiste Daroussin 	int ret = 1;
634*39ee7a7aSBaptiste Daroussin 
635*39ee7a7aSBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
636*39ee7a7aSBaptiste Daroussin 	obj = ucl_parser_get_object (parser);
637*39ee7a7aSBaptiste Daroussin 
638*39ee7a7aSBaptiste Daroussin 	if (obj != NULL) {
639*39ee7a7aSBaptiste Daroussin 		pobj = lua_newuserdata (L, sizeof (*pobj));
640*39ee7a7aSBaptiste Daroussin 		*pobj = obj;
641*39ee7a7aSBaptiste Daroussin 		luaL_getmetatable (L, OBJECT_META);
642*39ee7a7aSBaptiste Daroussin 		lua_setmetatable (L, -2);
643*39ee7a7aSBaptiste Daroussin 	}
644*39ee7a7aSBaptiste Daroussin 	else {
645*39ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
646*39ee7a7aSBaptiste Daroussin 	}
647*39ee7a7aSBaptiste Daroussin 
648*39ee7a7aSBaptiste Daroussin 	return ret;
649*39ee7a7aSBaptiste Daroussin }
650*39ee7a7aSBaptiste Daroussin 
651*39ee7a7aSBaptiste Daroussin /***
652*39ee7a7aSBaptiste Daroussin  * @method parser:validate(schema)
653*39ee7a7aSBaptiste Daroussin  * Validates the top object in the parser against schema. Schema might be
654*39ee7a7aSBaptiste Daroussin  * another object or a string that represents file to load schema from.
655*39ee7a7aSBaptiste Daroussin  *
656*39ee7a7aSBaptiste Daroussin  * @param {string/table} schema input schema
657*39ee7a7aSBaptiste Daroussin  * @return {result,err} two values: boolean result and the corresponding error
658*39ee7a7aSBaptiste Daroussin  *
659*39ee7a7aSBaptiste Daroussin  */
660*39ee7a7aSBaptiste Daroussin static int
661*39ee7a7aSBaptiste Daroussin lua_ucl_parser_validate (lua_State *L)
662*39ee7a7aSBaptiste Daroussin {
663*39ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser, *schema_parser;
664*39ee7a7aSBaptiste Daroussin 	ucl_object_t *schema;
665*39ee7a7aSBaptiste Daroussin 	const char *schema_file;
666*39ee7a7aSBaptiste Daroussin 	struct ucl_schema_error err;
667*39ee7a7aSBaptiste Daroussin 
668*39ee7a7aSBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
669*39ee7a7aSBaptiste Daroussin 
670*39ee7a7aSBaptiste Daroussin 	if (parser && parser->top_obj) {
671*39ee7a7aSBaptiste Daroussin 		if (lua_type (L, 2) == LUA_TTABLE) {
672*39ee7a7aSBaptiste Daroussin 			schema = ucl_object_lua_import (L, 2);
673*39ee7a7aSBaptiste Daroussin 
674*39ee7a7aSBaptiste Daroussin 			if (schema == NULL) {
675*39ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, false);
676*39ee7a7aSBaptiste Daroussin 				lua_pushstring (L, "cannot load schema from lua table");
677*39ee7a7aSBaptiste Daroussin 
678*39ee7a7aSBaptiste Daroussin 				return 2;
679*39ee7a7aSBaptiste Daroussin 			}
680*39ee7a7aSBaptiste Daroussin 		}
681*39ee7a7aSBaptiste Daroussin 		else if (lua_type (L, 2) == LUA_TSTRING) {
682*39ee7a7aSBaptiste Daroussin 			schema_parser = ucl_parser_new (0);
683*39ee7a7aSBaptiste Daroussin 			schema_file = luaL_checkstring (L, 2);
684*39ee7a7aSBaptiste Daroussin 
685*39ee7a7aSBaptiste Daroussin 			if (!ucl_parser_add_file (schema_parser, schema_file)) {
686*39ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, false);
687*39ee7a7aSBaptiste Daroussin 				lua_pushfstring (L, "cannot parse schema file \"%s\": "
688*39ee7a7aSBaptiste Daroussin 						"%s", schema_file, ucl_parser_get_error (parser));
689*39ee7a7aSBaptiste Daroussin 				ucl_parser_free (schema_parser);
690*39ee7a7aSBaptiste Daroussin 
691*39ee7a7aSBaptiste Daroussin 				return 2;
692*39ee7a7aSBaptiste Daroussin 			}
693*39ee7a7aSBaptiste Daroussin 
694*39ee7a7aSBaptiste Daroussin 			schema = ucl_parser_get_object (schema_parser);
695*39ee7a7aSBaptiste Daroussin 			ucl_parser_free (schema_parser);
696*39ee7a7aSBaptiste Daroussin 		}
697*39ee7a7aSBaptiste Daroussin 		else {
698*39ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, false);
699*39ee7a7aSBaptiste Daroussin 			lua_pushstring (L, "invalid schema argument");
700*39ee7a7aSBaptiste Daroussin 
701*39ee7a7aSBaptiste Daroussin 			return 2;
702*39ee7a7aSBaptiste Daroussin 		}
703*39ee7a7aSBaptiste Daroussin 
704*39ee7a7aSBaptiste Daroussin 		if (!ucl_object_validate (schema, parser->top_obj, &err)) {
705*39ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, false);
706*39ee7a7aSBaptiste Daroussin 			lua_pushfstring (L, "validation error: "
707*39ee7a7aSBaptiste Daroussin 					"%s", err.msg);
708*39ee7a7aSBaptiste Daroussin 		}
709*39ee7a7aSBaptiste Daroussin 		else {
710*39ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, true);
711*39ee7a7aSBaptiste Daroussin 			lua_pushnil (L);
712*39ee7a7aSBaptiste Daroussin 		}
713*39ee7a7aSBaptiste Daroussin 
714*39ee7a7aSBaptiste Daroussin 		ucl_object_unref (schema);
715*39ee7a7aSBaptiste Daroussin 	}
716*39ee7a7aSBaptiste Daroussin 	else {
717*39ee7a7aSBaptiste Daroussin 		lua_pushboolean (L, false);
718*39ee7a7aSBaptiste Daroussin 		lua_pushstring (L, "invalid parser or empty top object");
719*39ee7a7aSBaptiste Daroussin 	}
720*39ee7a7aSBaptiste Daroussin 
721*39ee7a7aSBaptiste Daroussin 	return 2;
722*39ee7a7aSBaptiste Daroussin }
723*39ee7a7aSBaptiste Daroussin 
7244bf54857SBaptiste Daroussin static int
7254bf54857SBaptiste Daroussin lua_ucl_parser_gc (lua_State *L)
7264bf54857SBaptiste Daroussin {
7274bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
7284bf54857SBaptiste Daroussin 
7294bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
7304bf54857SBaptiste Daroussin 	ucl_parser_free (parser);
7314bf54857SBaptiste Daroussin 
7324bf54857SBaptiste Daroussin 	return 0;
7334bf54857SBaptiste Daroussin }
7344bf54857SBaptiste Daroussin 
735*39ee7a7aSBaptiste Daroussin /***
736*39ee7a7aSBaptiste Daroussin  * @method object:unwrap()
737*39ee7a7aSBaptiste Daroussin  * Unwraps opaque ucl object to the native lua object (performing copying)
738*39ee7a7aSBaptiste Daroussin  * @return {variant} any lua object
739*39ee7a7aSBaptiste Daroussin  */
740*39ee7a7aSBaptiste Daroussin static int
741*39ee7a7aSBaptiste Daroussin lua_ucl_object_unwrap (lua_State *L)
742*39ee7a7aSBaptiste Daroussin {
743*39ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
744*39ee7a7aSBaptiste Daroussin 
745*39ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
746*39ee7a7aSBaptiste Daroussin 
747*39ee7a7aSBaptiste Daroussin 	if (obj) {
748*39ee7a7aSBaptiste Daroussin 		ucl_object_push_lua (L, obj, true);
749*39ee7a7aSBaptiste Daroussin 	}
750*39ee7a7aSBaptiste Daroussin 	else {
751*39ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
752*39ee7a7aSBaptiste Daroussin 	}
753*39ee7a7aSBaptiste Daroussin 
754*39ee7a7aSBaptiste Daroussin 	return 1;
755*39ee7a7aSBaptiste Daroussin }
756*39ee7a7aSBaptiste Daroussin 
757*39ee7a7aSBaptiste Daroussin /***
758*39ee7a7aSBaptiste Daroussin  * @method object:tostring(type)
759*39ee7a7aSBaptiste Daroussin  * Unwraps opaque ucl object to string (json by default). Optionally you can
760*39ee7a7aSBaptiste Daroussin  * specify output format:
761*39ee7a7aSBaptiste Daroussin  *
762*39ee7a7aSBaptiste Daroussin  * - `json` - fine printed json
763*39ee7a7aSBaptiste Daroussin  * - `json-compact` - compacted json
764*39ee7a7aSBaptiste Daroussin  * - `config` - fine printed configuration
765*39ee7a7aSBaptiste Daroussin  * - `ucl` - same as `config`
766*39ee7a7aSBaptiste Daroussin  * - `yaml` - embedded yaml
767*39ee7a7aSBaptiste Daroussin  * @param {string} type optional
768*39ee7a7aSBaptiste Daroussin  * @return {string} string representation of the opaque ucl object
769*39ee7a7aSBaptiste Daroussin  */
770*39ee7a7aSBaptiste Daroussin static int
771*39ee7a7aSBaptiste Daroussin lua_ucl_object_tostring (lua_State *L)
772*39ee7a7aSBaptiste Daroussin {
773*39ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
774*39ee7a7aSBaptiste Daroussin 	enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
775*39ee7a7aSBaptiste Daroussin 
776*39ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
777*39ee7a7aSBaptiste Daroussin 
778*39ee7a7aSBaptiste Daroussin 	if (obj) {
779*39ee7a7aSBaptiste Daroussin 		if (lua_gettop (L) > 1) {
780*39ee7a7aSBaptiste Daroussin 			if (lua_type (L, 2) == LUA_TSTRING) {
781*39ee7a7aSBaptiste Daroussin 				const char *strtype = lua_tostring (L, 2);
782*39ee7a7aSBaptiste Daroussin 
783*39ee7a7aSBaptiste Daroussin 				if (strcasecmp (strtype, "json") == 0) {
784*39ee7a7aSBaptiste Daroussin 					format = UCL_EMIT_JSON;
785*39ee7a7aSBaptiste Daroussin 				}
786*39ee7a7aSBaptiste Daroussin 				else if (strcasecmp (strtype, "json-compact") == 0) {
787*39ee7a7aSBaptiste Daroussin 					format = UCL_EMIT_JSON_COMPACT;
788*39ee7a7aSBaptiste Daroussin 				}
789*39ee7a7aSBaptiste Daroussin 				else if (strcasecmp (strtype, "yaml") == 0) {
790*39ee7a7aSBaptiste Daroussin 					format = UCL_EMIT_YAML;
791*39ee7a7aSBaptiste Daroussin 				}
792*39ee7a7aSBaptiste Daroussin 				else if (strcasecmp (strtype, "config") == 0 ||
793*39ee7a7aSBaptiste Daroussin 						strcasecmp (strtype, "ucl") == 0) {
794*39ee7a7aSBaptiste Daroussin 					format = UCL_EMIT_CONFIG;
795*39ee7a7aSBaptiste Daroussin 				}
796*39ee7a7aSBaptiste Daroussin 			}
797*39ee7a7aSBaptiste Daroussin 		}
798*39ee7a7aSBaptiste Daroussin 
799*39ee7a7aSBaptiste Daroussin 		return lua_ucl_to_string (L, obj, format);
800*39ee7a7aSBaptiste Daroussin 	}
801*39ee7a7aSBaptiste Daroussin 	else {
802*39ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
803*39ee7a7aSBaptiste Daroussin 	}
804*39ee7a7aSBaptiste Daroussin 
805*39ee7a7aSBaptiste Daroussin 	return 1;
806*39ee7a7aSBaptiste Daroussin }
807*39ee7a7aSBaptiste Daroussin 
808*39ee7a7aSBaptiste Daroussin /***
809*39ee7a7aSBaptiste Daroussin  * @method object:validate(schema, path)
810*39ee7a7aSBaptiste Daroussin  * Validates the given ucl object using schema object represented as another
811*39ee7a7aSBaptiste Daroussin  * opaque ucl object. You can also specify path in the form `#/path/def` to
812*39ee7a7aSBaptiste Daroussin  * specify the specific schema element to perform validation.
813*39ee7a7aSBaptiste Daroussin  *
814*39ee7a7aSBaptiste Daroussin  * @param {ucl.object} schema schema object
815*39ee7a7aSBaptiste Daroussin  * @param {string} path optional path for validation procedure
816*39ee7a7aSBaptiste Daroussin  * @return {result,err} two values: boolean result and the corresponding error
817*39ee7a7aSBaptiste Daroussin  */
818*39ee7a7aSBaptiste Daroussin static int
819*39ee7a7aSBaptiste Daroussin lua_ucl_object_validate (lua_State *L)
820*39ee7a7aSBaptiste Daroussin {
821*39ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, *schema;
822*39ee7a7aSBaptiste Daroussin 	const ucl_object_t *schema_elt;
823*39ee7a7aSBaptiste Daroussin 	bool res = false;
824*39ee7a7aSBaptiste Daroussin 	struct ucl_schema_error err;
825*39ee7a7aSBaptiste Daroussin 	const char *path = NULL;
826*39ee7a7aSBaptiste Daroussin 
827*39ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
828*39ee7a7aSBaptiste Daroussin 	schema = lua_ucl_object_get (L, 2);
829*39ee7a7aSBaptiste Daroussin 
830*39ee7a7aSBaptiste Daroussin 	if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
831*39ee7a7aSBaptiste Daroussin 		if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TSTRING) {
832*39ee7a7aSBaptiste Daroussin 			path = lua_tostring (L, 3);
833*39ee7a7aSBaptiste Daroussin 			if (path[0] == '#') {
834*39ee7a7aSBaptiste Daroussin 				path ++;
835*39ee7a7aSBaptiste Daroussin 			}
836*39ee7a7aSBaptiste Daroussin 		}
837*39ee7a7aSBaptiste Daroussin 
838*39ee7a7aSBaptiste Daroussin 		if (path) {
839*39ee7a7aSBaptiste Daroussin 			schema_elt = ucl_lookup_path_char (schema, path, '/');
840*39ee7a7aSBaptiste Daroussin 		}
841*39ee7a7aSBaptiste Daroussin 		else {
842*39ee7a7aSBaptiste Daroussin 			/* Use the top object */
843*39ee7a7aSBaptiste Daroussin 			schema_elt = schema;
844*39ee7a7aSBaptiste Daroussin 		}
845*39ee7a7aSBaptiste Daroussin 
846*39ee7a7aSBaptiste Daroussin 		if (schema_elt) {
847*39ee7a7aSBaptiste Daroussin 			res = ucl_object_validate (schema_elt, obj, &err);
848*39ee7a7aSBaptiste Daroussin 
849*39ee7a7aSBaptiste Daroussin 			if (res) {
850*39ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, res);
851*39ee7a7aSBaptiste Daroussin 				lua_pushnil (L);
852*39ee7a7aSBaptiste Daroussin 			}
853*39ee7a7aSBaptiste Daroussin 			else {
854*39ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, res);
855*39ee7a7aSBaptiste Daroussin 				lua_pushfstring (L, "validation error: %s", err.msg);
856*39ee7a7aSBaptiste Daroussin 			}
857*39ee7a7aSBaptiste Daroussin 		}
858*39ee7a7aSBaptiste Daroussin 		else {
859*39ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, res);
860*39ee7a7aSBaptiste Daroussin 
861*39ee7a7aSBaptiste Daroussin 			if (path) {
862*39ee7a7aSBaptiste Daroussin 				lua_pushfstring (L, "cannot find the requested path: %s", path);
863*39ee7a7aSBaptiste Daroussin 			}
864*39ee7a7aSBaptiste Daroussin 			else {
865*39ee7a7aSBaptiste Daroussin 				/* Should not be reached */
866*39ee7a7aSBaptiste Daroussin 				lua_pushstring (L, "unknown error");
867*39ee7a7aSBaptiste Daroussin 			}
868*39ee7a7aSBaptiste Daroussin 		}
869*39ee7a7aSBaptiste Daroussin 	}
870*39ee7a7aSBaptiste Daroussin 	else {
871*39ee7a7aSBaptiste Daroussin 		lua_pushboolean (L, res);
872*39ee7a7aSBaptiste Daroussin 		lua_pushstring (L, "invalid object or schema");
873*39ee7a7aSBaptiste Daroussin 	}
874*39ee7a7aSBaptiste Daroussin 
875*39ee7a7aSBaptiste Daroussin 	return 2;
876*39ee7a7aSBaptiste Daroussin }
877*39ee7a7aSBaptiste Daroussin 
878*39ee7a7aSBaptiste Daroussin static int
879*39ee7a7aSBaptiste Daroussin lua_ucl_object_gc (lua_State *L)
880*39ee7a7aSBaptiste Daroussin {
881*39ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
882*39ee7a7aSBaptiste Daroussin 
883*39ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
884*39ee7a7aSBaptiste Daroussin 
885*39ee7a7aSBaptiste Daroussin 	ucl_object_unref (obj);
886*39ee7a7aSBaptiste Daroussin 
887*39ee7a7aSBaptiste Daroussin 	return 0;
888*39ee7a7aSBaptiste Daroussin }
889*39ee7a7aSBaptiste Daroussin 
8904bf54857SBaptiste Daroussin static void
8914bf54857SBaptiste Daroussin lua_ucl_parser_mt (lua_State *L)
8924bf54857SBaptiste Daroussin {
8934bf54857SBaptiste Daroussin 	luaL_newmetatable (L, PARSER_META);
8944bf54857SBaptiste Daroussin 
8954bf54857SBaptiste Daroussin 	lua_pushvalue(L, -1);
8964bf54857SBaptiste Daroussin 	lua_setfield(L, -2, "__index");
8974bf54857SBaptiste Daroussin 
8984bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_gc);
8994bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__gc");
9004bf54857SBaptiste Daroussin 
9014bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_file);
9024bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_file");
9034bf54857SBaptiste Daroussin 
9044bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_string);
9054bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_string");
9064bf54857SBaptiste Daroussin 
9074bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_get_object);
9084bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "get_object");
9094bf54857SBaptiste Daroussin 
910*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
911*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "get_object_wrapped");
912*39ee7a7aSBaptiste Daroussin 
913*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_validate);
914*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "validate");
915*39ee7a7aSBaptiste Daroussin 
9164bf54857SBaptiste Daroussin 	lua_pop (L, 1);
9174bf54857SBaptiste Daroussin }
9184bf54857SBaptiste Daroussin 
919*39ee7a7aSBaptiste Daroussin static void
920*39ee7a7aSBaptiste Daroussin lua_ucl_object_mt (lua_State *L)
9214bf54857SBaptiste Daroussin {
922*39ee7a7aSBaptiste Daroussin 	luaL_newmetatable (L, OBJECT_META);
9234bf54857SBaptiste Daroussin 
924*39ee7a7aSBaptiste Daroussin 	lua_pushvalue(L, -1);
925*39ee7a7aSBaptiste Daroussin 	lua_setfield(L, -2, "__index");
9264bf54857SBaptiste Daroussin 
927*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_gc);
928*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "__gc");
9294bf54857SBaptiste Daroussin 
930*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
931*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
932*39ee7a7aSBaptiste Daroussin 
933*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
934*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "tostring");
935*39ee7a7aSBaptiste Daroussin 
936*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_unwrap);
937*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "unwrap");
938*39ee7a7aSBaptiste Daroussin 
939*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_unwrap);
940*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "tolua");
941*39ee7a7aSBaptiste Daroussin 
942*39ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_validate);
943*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "validate");
944*39ee7a7aSBaptiste Daroussin 
945*39ee7a7aSBaptiste Daroussin 	lua_pushstring (L, OBJECT_META);
946*39ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "class");
947*39ee7a7aSBaptiste Daroussin 
948*39ee7a7aSBaptiste Daroussin 	lua_pop (L, 1);
9494bf54857SBaptiste Daroussin }
9504bf54857SBaptiste Daroussin 
9514bf54857SBaptiste Daroussin static int
9524bf54857SBaptiste Daroussin lua_ucl_to_json (lua_State *L)
9534bf54857SBaptiste Daroussin {
9544bf54857SBaptiste Daroussin 	ucl_object_t *obj;
9554bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
9564bf54857SBaptiste Daroussin 
9574bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
9584bf54857SBaptiste Daroussin 		if (lua_toboolean (L, 2)) {
9594bf54857SBaptiste Daroussin 			format = UCL_EMIT_JSON_COMPACT;
9604bf54857SBaptiste Daroussin 		}
9614bf54857SBaptiste Daroussin 	}
9624bf54857SBaptiste Daroussin 
9634bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
9644bf54857SBaptiste Daroussin 	if (obj != NULL) {
9654bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
9664bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
9674bf54857SBaptiste Daroussin 	}
9684bf54857SBaptiste Daroussin 	else {
9694bf54857SBaptiste Daroussin 		lua_pushnil (L);
9704bf54857SBaptiste Daroussin 	}
9714bf54857SBaptiste Daroussin 
9724bf54857SBaptiste Daroussin 	return 1;
9734bf54857SBaptiste Daroussin }
9744bf54857SBaptiste Daroussin 
9754bf54857SBaptiste Daroussin static int
9764bf54857SBaptiste Daroussin lua_ucl_to_config (lua_State *L)
9774bf54857SBaptiste Daroussin {
9784bf54857SBaptiste Daroussin 	ucl_object_t *obj;
9794bf54857SBaptiste Daroussin 
9804bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
9814bf54857SBaptiste Daroussin 	if (obj != NULL) {
9824bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
9834bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
9844bf54857SBaptiste Daroussin 	}
9854bf54857SBaptiste Daroussin 	else {
9864bf54857SBaptiste Daroussin 		lua_pushnil (L);
9874bf54857SBaptiste Daroussin 	}
9884bf54857SBaptiste Daroussin 
9894bf54857SBaptiste Daroussin 	return 1;
9904bf54857SBaptiste Daroussin }
9914bf54857SBaptiste Daroussin 
9924bf54857SBaptiste Daroussin /***
9934bf54857SBaptiste Daroussin  * @function ucl.to_format(var, format)
9944bf54857SBaptiste Daroussin  * Converts lua variable `var` to the specified `format`. Formats supported are:
9954bf54857SBaptiste Daroussin  *
9964bf54857SBaptiste Daroussin  * - `json` - fine printed json
9974bf54857SBaptiste Daroussin  * - `json-compact` - compacted json
9984bf54857SBaptiste Daroussin  * - `config` - fine printed configuration
9994bf54857SBaptiste Daroussin  * - `ucl` - same as `config`
10004bf54857SBaptiste Daroussin  * - `yaml` - embedded yaml
10014bf54857SBaptiste Daroussin  *
10024bf54857SBaptiste Daroussin  * If `var` contains function, they are called during output formatting and if
10034bf54857SBaptiste Daroussin  * they return string value, then this value is used for ouptut.
10044bf54857SBaptiste Daroussin  * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
10054bf54857SBaptiste Daroussin  * @param {string} format any available format
10064bf54857SBaptiste Daroussin  * @return {string} string representation of `var` in the specific `format`.
10074bf54857SBaptiste Daroussin  * @example
10084bf54857SBaptiste Daroussin local table = {
10094bf54857SBaptiste Daroussin   str = 'value',
10104bf54857SBaptiste Daroussin   num = 100500,
10114bf54857SBaptiste Daroussin   null = ucl.null,
10124bf54857SBaptiste Daroussin   func = function ()
10134bf54857SBaptiste Daroussin     return 'huh'
10144bf54857SBaptiste Daroussin   end
10154bf54857SBaptiste Daroussin }
10164bf54857SBaptiste Daroussin 
10174bf54857SBaptiste Daroussin print(ucl.to_format(table, 'ucl'))
10184bf54857SBaptiste Daroussin -- Output:
10194bf54857SBaptiste Daroussin --[[
10204bf54857SBaptiste Daroussin num = 100500;
10214bf54857SBaptiste Daroussin str = "value";
10224bf54857SBaptiste Daroussin null = null;
10234bf54857SBaptiste Daroussin func = "huh";
10244bf54857SBaptiste Daroussin --]]
10254bf54857SBaptiste Daroussin  */
10264bf54857SBaptiste Daroussin static int
10274bf54857SBaptiste Daroussin lua_ucl_to_format (lua_State *L)
10284bf54857SBaptiste Daroussin {
10294bf54857SBaptiste Daroussin 	ucl_object_t *obj;
10304bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
10314bf54857SBaptiste Daroussin 
10324bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
10334bf54857SBaptiste Daroussin 		if (lua_type (L, 2) == LUA_TNUMBER) {
10344bf54857SBaptiste Daroussin 			format = lua_tonumber (L, 2);
10354bf54857SBaptiste Daroussin 			if (format < 0 || format >= UCL_EMIT_YAML) {
10364bf54857SBaptiste Daroussin 				lua_pushnil (L);
10374bf54857SBaptiste Daroussin 				return 1;
10384bf54857SBaptiste Daroussin 			}
10394bf54857SBaptiste Daroussin 		}
10404bf54857SBaptiste Daroussin 		else if (lua_type (L, 2) == LUA_TSTRING) {
10414bf54857SBaptiste Daroussin 			const char *strtype = lua_tostring (L, 2);
10424bf54857SBaptiste Daroussin 
10434bf54857SBaptiste Daroussin 			if (strcasecmp (strtype, "json") == 0) {
10444bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON;
10454bf54857SBaptiste Daroussin 			}
10464bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "json-compact") == 0) {
10474bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON_COMPACT;
10484bf54857SBaptiste Daroussin 			}
10494bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "yaml") == 0) {
10504bf54857SBaptiste Daroussin 				format = UCL_EMIT_YAML;
10514bf54857SBaptiste Daroussin 			}
10524bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "config") == 0 ||
10534bf54857SBaptiste Daroussin 				strcasecmp (strtype, "ucl") == 0) {
10544bf54857SBaptiste Daroussin 				format = UCL_EMIT_CONFIG;
10554bf54857SBaptiste Daroussin 			}
10564bf54857SBaptiste Daroussin 		}
10574bf54857SBaptiste Daroussin 	}
10584bf54857SBaptiste Daroussin 
10594bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
10604bf54857SBaptiste Daroussin 	if (obj != NULL) {
10614bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
10624bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
10634bf54857SBaptiste Daroussin 	}
10644bf54857SBaptiste Daroussin 	else {
10654bf54857SBaptiste Daroussin 		lua_pushnil (L);
10664bf54857SBaptiste Daroussin 	}
10674bf54857SBaptiste Daroussin 
10684bf54857SBaptiste Daroussin 	return 1;
10694bf54857SBaptiste Daroussin }
10704bf54857SBaptiste Daroussin 
10714bf54857SBaptiste Daroussin static int
10724bf54857SBaptiste Daroussin lua_ucl_null_tostring (lua_State* L)
10734bf54857SBaptiste Daroussin {
10744bf54857SBaptiste Daroussin 	lua_pushstring (L, "null");
10754bf54857SBaptiste Daroussin 	return 1;
10764bf54857SBaptiste Daroussin }
10774bf54857SBaptiste Daroussin 
10784bf54857SBaptiste Daroussin static void
10794bf54857SBaptiste Daroussin lua_ucl_null_mt (lua_State *L)
10804bf54857SBaptiste Daroussin {
10814bf54857SBaptiste Daroussin 	luaL_newmetatable (L, NULL_META);
10824bf54857SBaptiste Daroussin 
10834bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_null_tostring);
10844bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
10854bf54857SBaptiste Daroussin 
10864bf54857SBaptiste Daroussin 	lua_pop (L, 1);
10874bf54857SBaptiste Daroussin }
10884bf54857SBaptiste Daroussin 
10894bf54857SBaptiste Daroussin int
10904bf54857SBaptiste Daroussin luaopen_ucl (lua_State *L)
10914bf54857SBaptiste Daroussin {
10924bf54857SBaptiste Daroussin 	lua_ucl_parser_mt (L);
10934bf54857SBaptiste Daroussin 	lua_ucl_null_mt (L);
1094*39ee7a7aSBaptiste Daroussin 	lua_ucl_object_mt (L);
10954bf54857SBaptiste Daroussin 
10964bf54857SBaptiste Daroussin 	/* Create the refs weak table: */
10974bf54857SBaptiste Daroussin 	lua_createtable (L, 0, 2);
10984bf54857SBaptiste Daroussin 	lua_pushliteral (L, "v"); /* tbl, "v" */
10994bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__mode");
11004bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1); /* tbl, tbl */
11014bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2); /* tbl */
11024bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
11034bf54857SBaptiste Daroussin 
11044bf54857SBaptiste Daroussin 	lua_newtable (L);
11054bf54857SBaptiste Daroussin 
11064bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_init);
11074bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parser");
11084bf54857SBaptiste Daroussin 
11094bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_json);
11104bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_json");
11114bf54857SBaptiste Daroussin 
11124bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_config);
11134bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_config");
11144bf54857SBaptiste Daroussin 
11154bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_format);
11164bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_format");
11174bf54857SBaptiste Daroussin 
11184bf54857SBaptiste Daroussin 	ucl_null = lua_newuserdata (L, 0);
11194bf54857SBaptiste Daroussin 	luaL_getmetatable (L, NULL_META);
11204bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
11214bf54857SBaptiste Daroussin 
11224bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1);
11234bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
11244bf54857SBaptiste Daroussin 
11254bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "null");
11264bf54857SBaptiste Daroussin 
11274bf54857SBaptiste Daroussin 	return 1;
11284bf54857SBaptiste Daroussin }
11294bf54857SBaptiste Daroussin 
11304bf54857SBaptiste Daroussin struct ucl_lua_funcdata*
11314bf54857SBaptiste Daroussin ucl_object_toclosure (const ucl_object_t *obj)
11324bf54857SBaptiste Daroussin {
11334bf54857SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_USERDATA) {
11344bf54857SBaptiste Daroussin 		return NULL;
11354bf54857SBaptiste Daroussin 	}
11364bf54857SBaptiste Daroussin 
11374bf54857SBaptiste Daroussin 	return (struct ucl_lua_funcdata*)obj->value.ud;
11384bf54857SBaptiste Daroussin }
1139