xref: /freebsd/contrib/libucl/lua/lua_ucl.c (revision a0409676120c1e558d0ade943019934e0f15118d)
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"
71*a0409676SBaptiste Daroussin #define NULL_META "ucl.null.meta"
7239ee7a7aSBaptiste Daroussin #define OBJECT_META "ucl.object.meta"
73*a0409676SBaptiste Daroussin #define UCL_OBJECT_TYPE_META "ucl.type.object"
74*a0409676SBaptiste Daroussin #define UCL_ARRAY_TYPE_META "ucl.type.array"
75*a0409676SBaptiste Daroussin #define UCL_IMPL_ARRAY_TYPE_META "ucl.type.impl_array"
764bf54857SBaptiste Daroussin 
77*a0409676SBaptiste Daroussin static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags);
78*a0409676SBaptiste Daroussin static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, int flags);
79*a0409676SBaptiste Daroussin static int ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags);
80*a0409676SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags);
81*a0409676SBaptiste Daroussin static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags);
824bf54857SBaptiste Daroussin 
834bf54857SBaptiste Daroussin static void *ucl_null;
844bf54857SBaptiste Daroussin 
85*a0409676SBaptiste Daroussin 
86*a0409676SBaptiste Daroussin enum lua_ucl_push_flags {
87*a0409676SBaptiste Daroussin 	LUA_UCL_DEFAULT_FLAGS = 0,
88*a0409676SBaptiste Daroussin 	LUA_UCL_ALLOW_ARRAY = (1u << 0u),
89*a0409676SBaptiste Daroussin 	LUA_UCL_CONVERT_NIL = (1u << 1u),
90*a0409676SBaptiste Daroussin };
91*a0409676SBaptiste Daroussin 
924bf54857SBaptiste Daroussin /**
934bf54857SBaptiste Daroussin  * Push a single element of an object to lua
944bf54857SBaptiste Daroussin  * @param L
954bf54857SBaptiste Daroussin  * @param key
964bf54857SBaptiste Daroussin  * @param obj
974bf54857SBaptiste Daroussin  */
984bf54857SBaptiste Daroussin static void
ucl_object_lua_push_element(lua_State * L,const char * key,const ucl_object_t * obj,int flags)994bf54857SBaptiste Daroussin ucl_object_lua_push_element (lua_State *L, const char *key,
100*a0409676SBaptiste Daroussin 		const ucl_object_t *obj, int flags)
1014bf54857SBaptiste Daroussin {
1024bf54857SBaptiste Daroussin 	lua_pushstring (L, key);
103*a0409676SBaptiste Daroussin 	ucl_object_push_lua_common (L, obj, flags|LUA_UCL_ALLOW_ARRAY);
1044bf54857SBaptiste Daroussin 	lua_settable (L, -3);
1054bf54857SBaptiste Daroussin }
1064bf54857SBaptiste Daroussin 
1074bf54857SBaptiste Daroussin static void
lua_ucl_userdata_dtor(void * ud)1084bf54857SBaptiste Daroussin lua_ucl_userdata_dtor (void *ud)
1094bf54857SBaptiste Daroussin {
1104bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
1114bf54857SBaptiste Daroussin 
1124bf54857SBaptiste Daroussin 	luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
1134bf54857SBaptiste Daroussin 	if (fd->ret != NULL) {
1144bf54857SBaptiste Daroussin 		free (fd->ret);
1154bf54857SBaptiste Daroussin 	}
1164bf54857SBaptiste Daroussin 	free (fd);
1174bf54857SBaptiste Daroussin }
1184bf54857SBaptiste Daroussin 
1194bf54857SBaptiste Daroussin static const char *
lua_ucl_userdata_emitter(void * ud)1204bf54857SBaptiste Daroussin lua_ucl_userdata_emitter (void *ud)
1214bf54857SBaptiste Daroussin {
1224bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
1234bf54857SBaptiste Daroussin 	const char *out = "";
1244bf54857SBaptiste Daroussin 
1254bf54857SBaptiste Daroussin 	lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
1264bf54857SBaptiste Daroussin 
1274bf54857SBaptiste Daroussin 	lua_pcall (fd->L, 0, 1, 0);
1284bf54857SBaptiste Daroussin 	out = lua_tostring (fd->L, -1);
1294bf54857SBaptiste Daroussin 
1304bf54857SBaptiste Daroussin 	if (out != NULL) {
1314bf54857SBaptiste Daroussin 		/* We need to store temporary string in a more appropriate place */
1324bf54857SBaptiste Daroussin 		if (fd->ret) {
1334bf54857SBaptiste Daroussin 			free (fd->ret);
1344bf54857SBaptiste Daroussin 		}
1354bf54857SBaptiste Daroussin 		fd->ret = strdup (out);
1364bf54857SBaptiste Daroussin 	}
1374bf54857SBaptiste Daroussin 
1384bf54857SBaptiste Daroussin 	lua_settop (fd->L, 0);
1394bf54857SBaptiste Daroussin 
1404bf54857SBaptiste Daroussin 	return fd->ret;
1414bf54857SBaptiste Daroussin }
1424bf54857SBaptiste Daroussin 
1434bf54857SBaptiste Daroussin /**
1444bf54857SBaptiste Daroussin  * Push a single object to lua
1454bf54857SBaptiste Daroussin  * @param L
1464bf54857SBaptiste Daroussin  * @param obj
1474bf54857SBaptiste Daroussin  * @return
1484bf54857SBaptiste Daroussin  */
1494bf54857SBaptiste Daroussin static int
ucl_object_lua_push_object(lua_State * L,const ucl_object_t * obj,int flags)1504bf54857SBaptiste Daroussin ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
151*a0409676SBaptiste Daroussin 		int flags)
1524bf54857SBaptiste Daroussin {
1534bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
1544bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
1554bf54857SBaptiste Daroussin 
156*a0409676SBaptiste Daroussin 	if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
1574bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
158*a0409676SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj, flags);
1594bf54857SBaptiste Daroussin 	}
1604bf54857SBaptiste Daroussin 
161*a0409676SBaptiste Daroussin 	lua_createtable (L, 0, obj->len);
1624bf54857SBaptiste Daroussin 	it = NULL;
1634bf54857SBaptiste Daroussin 
164d9f0ce31SBaptiste Daroussin 	while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
165*a0409676SBaptiste Daroussin 		ucl_object_lua_push_element (L, ucl_object_key (cur), cur, flags);
1664bf54857SBaptiste Daroussin 	}
1674bf54857SBaptiste Daroussin 
168*a0409676SBaptiste Daroussin 	luaL_getmetatable (L, UCL_OBJECT_TYPE_META);
169*a0409676SBaptiste Daroussin 	lua_setmetatable (L, -2);
170*a0409676SBaptiste Daroussin 
1714bf54857SBaptiste Daroussin 	return 1;
1724bf54857SBaptiste Daroussin }
1734bf54857SBaptiste Daroussin 
1744bf54857SBaptiste Daroussin /**
1754bf54857SBaptiste Daroussin  * Push an array to lua as table indexed by integers
1764bf54857SBaptiste Daroussin  * @param L
1774bf54857SBaptiste Daroussin  * @param obj
1784bf54857SBaptiste Daroussin  * @return
1794bf54857SBaptiste Daroussin  */
1804bf54857SBaptiste Daroussin static int
ucl_object_lua_push_array(lua_State * L,const ucl_object_t * obj,int flags)181*a0409676SBaptiste Daroussin ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags)
1824bf54857SBaptiste Daroussin {
1834bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
18439ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it;
1854bf54857SBaptiste Daroussin 	int i = 1, nelt = 0;
1864bf54857SBaptiste Daroussin 
18739ee7a7aSBaptiste Daroussin 	if (obj->type == UCL_ARRAY) {
18839ee7a7aSBaptiste Daroussin 		nelt = obj->len;
18939ee7a7aSBaptiste Daroussin 		it = ucl_object_iterate_new (obj);
19039ee7a7aSBaptiste Daroussin 		lua_createtable (L, nelt, 0);
19139ee7a7aSBaptiste Daroussin 
19239ee7a7aSBaptiste Daroussin 		while ((cur = ucl_object_iterate_safe (it, true))) {
193*a0409676SBaptiste Daroussin 			ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
19439ee7a7aSBaptiste Daroussin 			lua_rawseti (L, -2, i);
19539ee7a7aSBaptiste Daroussin 			i ++;
19639ee7a7aSBaptiste Daroussin 		}
19711dd9ed6SBaptiste Daroussin 
198*a0409676SBaptiste Daroussin 		luaL_getmetatable (L, UCL_ARRAY_TYPE_META);
199*a0409676SBaptiste Daroussin 		lua_setmetatable (L, -2);
200*a0409676SBaptiste Daroussin 
20111dd9ed6SBaptiste Daroussin 		ucl_object_iterate_free (it);
20239ee7a7aSBaptiste Daroussin 	}
20339ee7a7aSBaptiste Daroussin 	else {
2044bf54857SBaptiste Daroussin 		/* Optimize allocation by preallocation of table */
2054bf54857SBaptiste Daroussin 		LL_FOREACH (obj, cur) {
2064bf54857SBaptiste Daroussin 			nelt ++;
2074bf54857SBaptiste Daroussin 		}
2084bf54857SBaptiste Daroussin 
2094bf54857SBaptiste Daroussin 		lua_createtable (L, nelt, 0);
2104bf54857SBaptiste Daroussin 
2114bf54857SBaptiste Daroussin 		LL_FOREACH (obj, cur) {
212*a0409676SBaptiste Daroussin 			ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
2134bf54857SBaptiste Daroussin 			lua_rawseti (L, -2, i);
2144bf54857SBaptiste Daroussin 			i ++;
2154bf54857SBaptiste Daroussin 		}
216*a0409676SBaptiste Daroussin 
217*a0409676SBaptiste Daroussin 		luaL_getmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
218*a0409676SBaptiste Daroussin 		lua_setmetatable (L, -2);
21939ee7a7aSBaptiste Daroussin 	}
2204bf54857SBaptiste Daroussin 
2214bf54857SBaptiste Daroussin 	return 1;
2224bf54857SBaptiste Daroussin }
2234bf54857SBaptiste Daroussin 
2244bf54857SBaptiste Daroussin /**
2254bf54857SBaptiste Daroussin  * Push a simple object to lua depending on its actual type
2264bf54857SBaptiste Daroussin  */
2274bf54857SBaptiste Daroussin static int
ucl_object_lua_push_scalar(lua_State * L,const ucl_object_t * obj,int flags)2284bf54857SBaptiste Daroussin ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
229*a0409676SBaptiste Daroussin 		int flags)
2304bf54857SBaptiste Daroussin {
2314bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
2324bf54857SBaptiste Daroussin 
233*a0409676SBaptiste Daroussin 	if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
2344bf54857SBaptiste Daroussin 		/* Actually we need to push this as an array */
235*a0409676SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj, flags);
2364bf54857SBaptiste Daroussin 	}
2374bf54857SBaptiste Daroussin 
2384bf54857SBaptiste Daroussin 	switch (obj->type) {
2394bf54857SBaptiste Daroussin 	case UCL_BOOLEAN:
2404bf54857SBaptiste Daroussin 		lua_pushboolean (L, ucl_obj_toboolean (obj));
2414bf54857SBaptiste Daroussin 		break;
2424bf54857SBaptiste Daroussin 	case UCL_STRING:
2434bf54857SBaptiste Daroussin 		lua_pushstring (L, ucl_obj_tostring (obj));
2444bf54857SBaptiste Daroussin 		break;
2454bf54857SBaptiste Daroussin 	case UCL_INT:
2464bf54857SBaptiste Daroussin #if LUA_VERSION_NUM >= 501
2474bf54857SBaptiste Daroussin 		lua_pushinteger (L, ucl_obj_toint (obj));
2484bf54857SBaptiste Daroussin #else
2494bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_toint (obj));
2504bf54857SBaptiste Daroussin #endif
2514bf54857SBaptiste Daroussin 		break;
2524bf54857SBaptiste Daroussin 	case UCL_FLOAT:
2534bf54857SBaptiste Daroussin 	case UCL_TIME:
2544bf54857SBaptiste Daroussin 		lua_pushnumber (L, ucl_obj_todouble (obj));
2554bf54857SBaptiste Daroussin 		break;
2564bf54857SBaptiste Daroussin 	case UCL_NULL:
257*a0409676SBaptiste Daroussin 		if (flags & LUA_UCL_CONVERT_NIL) {
258*a0409676SBaptiste Daroussin 			lua_pushboolean (L, false);
259*a0409676SBaptiste Daroussin 		}
260*a0409676SBaptiste Daroussin 		else {
2614bf54857SBaptiste Daroussin 			lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
262*a0409676SBaptiste Daroussin 		}
2634bf54857SBaptiste Daroussin 		break;
2644bf54857SBaptiste Daroussin 	case UCL_USERDATA:
2654bf54857SBaptiste Daroussin 		fd = (struct ucl_lua_funcdata *)obj->value.ud;
2664bf54857SBaptiste Daroussin 		lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
2674bf54857SBaptiste Daroussin 		break;
2684bf54857SBaptiste Daroussin 	default:
2694bf54857SBaptiste Daroussin 		lua_pushnil (L);
2704bf54857SBaptiste Daroussin 		break;
2714bf54857SBaptiste Daroussin 	}
2724bf54857SBaptiste Daroussin 
2734bf54857SBaptiste Daroussin 	return 1;
2744bf54857SBaptiste Daroussin }
2754bf54857SBaptiste Daroussin 
276*a0409676SBaptiste Daroussin static int
ucl_object_push_lua_common(lua_State * L,const ucl_object_t * obj,int flags)277*a0409676SBaptiste Daroussin ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags)
278*a0409676SBaptiste Daroussin {
279*a0409676SBaptiste Daroussin 	switch (obj->type) {
280*a0409676SBaptiste Daroussin 	case UCL_OBJECT:
281*a0409676SBaptiste Daroussin 		return ucl_object_lua_push_object (L, obj, flags);
282*a0409676SBaptiste Daroussin 	case UCL_ARRAY:
283*a0409676SBaptiste Daroussin 		return ucl_object_lua_push_array (L, obj, flags);
284*a0409676SBaptiste Daroussin 	default:
285*a0409676SBaptiste Daroussin 		return ucl_object_lua_push_scalar (L, obj, flags);
286*a0409676SBaptiste Daroussin 	}
287*a0409676SBaptiste Daroussin }
288*a0409676SBaptiste Daroussin 
2894bf54857SBaptiste Daroussin /***
2904bf54857SBaptiste Daroussin  * @function ucl_object_push_lua(L, obj, allow_array)
2914bf54857SBaptiste Daroussin  * This is a `C` function to push `UCL` object as lua variable. This function
2924bf54857SBaptiste Daroussin  * converts `obj` to lua representation using the following conversions:
2934bf54857SBaptiste Daroussin  *
2944bf54857SBaptiste Daroussin  * - *scalar* values are directly presented by lua objects
2954bf54857SBaptiste Daroussin  * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
2964bf54857SBaptiste Daroussin  * this can be used to pass functions from lua to c and vice-versa
2974bf54857SBaptiste Daroussin  * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
2984bf54857SBaptiste Daroussin  * - *objects* are converted to lua tables with string indicies
2994bf54857SBaptiste Daroussin  * @param {lua_State} L lua state pointer
3004bf54857SBaptiste Daroussin  * @param {ucl_object_t} obj object to push
3014bf54857SBaptiste Daroussin  * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
3024bf54857SBaptiste Daroussin  * @return {int} `1` if an object is pushed to lua
3034bf54857SBaptiste Daroussin  */
3044bf54857SBaptiste Daroussin int
ucl_object_push_lua(lua_State * L,const ucl_object_t * obj,bool allow_array)3054bf54857SBaptiste Daroussin ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
3064bf54857SBaptiste Daroussin {
307*a0409676SBaptiste Daroussin 	return ucl_object_push_lua_common (L, obj,
308*a0409676SBaptiste Daroussin 			allow_array ? LUA_UCL_ALLOW_ARRAY : LUA_UCL_DEFAULT_FLAGS);
3094bf54857SBaptiste Daroussin }
310*a0409676SBaptiste Daroussin 
311*a0409676SBaptiste Daroussin int
ucl_object_push_lua_filter_nil(lua_State * L,const ucl_object_t * obj,bool allow_array)312*a0409676SBaptiste Daroussin ucl_object_push_lua_filter_nil (lua_State *L, const ucl_object_t *obj, bool allow_array)
313*a0409676SBaptiste Daroussin {
314*a0409676SBaptiste Daroussin 	return ucl_object_push_lua_common (L, obj,
315*a0409676SBaptiste Daroussin 			allow_array ? (LUA_UCL_ALLOW_ARRAY|LUA_UCL_CONVERT_NIL) :
316*a0409676SBaptiste Daroussin 			(LUA_UCL_DEFAULT_FLAGS|LUA_UCL_CONVERT_NIL));
3174bf54857SBaptiste Daroussin }
3184bf54857SBaptiste Daroussin 
3194bf54857SBaptiste Daroussin /**
3204bf54857SBaptiste Daroussin  * Parse lua table into object top
3214bf54857SBaptiste Daroussin  * @param L
3224bf54857SBaptiste Daroussin  * @param top
3234bf54857SBaptiste Daroussin  * @param idx
3244bf54857SBaptiste Daroussin  */
3254bf54857SBaptiste Daroussin static ucl_object_t *
ucl_object_lua_fromtable(lua_State * L,int idx,ucl_string_flags_t flags)326*a0409676SBaptiste Daroussin ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)
3274bf54857SBaptiste Daroussin {
328*a0409676SBaptiste Daroussin 	ucl_object_t *obj, *top = NULL, *cur;
3294bf54857SBaptiste Daroussin 	size_t keylen;
3304bf54857SBaptiste Daroussin 	const char *k;
331*a0409676SBaptiste Daroussin 	bool is_array = true, is_implicit = false, found_mt = false;
332*a0409676SBaptiste Daroussin 	size_t max = 0, nelts = 0;
3334bf54857SBaptiste Daroussin 
3344bf54857SBaptiste Daroussin 	if (idx < 0) {
3354bf54857SBaptiste Daroussin 		/* For negative indicies we want to invert them */
3364bf54857SBaptiste Daroussin 		idx = lua_gettop (L) + idx + 1;
3374bf54857SBaptiste Daroussin 	}
338*a0409676SBaptiste Daroussin 
339*a0409676SBaptiste Daroussin 	/* First, we check from metatable */
340*a0409676SBaptiste Daroussin 	if (luaL_getmetafield (L, idx, "class") != 0) {
341*a0409676SBaptiste Daroussin 
342*a0409676SBaptiste Daroussin 		if (lua_type (L, -1) == LUA_TSTRING) {
343*a0409676SBaptiste Daroussin 			const char *classname = lua_tostring (L, -1);
344*a0409676SBaptiste Daroussin 
345*a0409676SBaptiste Daroussin 			if (strcmp (classname, UCL_OBJECT_TYPE_META) == 0) {
346*a0409676SBaptiste Daroussin 				is_array = false;
347*a0409676SBaptiste Daroussin 				found_mt = true;
348*a0409676SBaptiste Daroussin 			} else if (strcmp (classname, UCL_ARRAY_TYPE_META) == 0) {
349*a0409676SBaptiste Daroussin 				is_array = true;
350*a0409676SBaptiste Daroussin 				found_mt = true;
351*a0409676SBaptiste Daroussin #if LUA_VERSION_NUM >= 502
352*a0409676SBaptiste Daroussin 				max = lua_rawlen (L, idx);
353*a0409676SBaptiste Daroussin #else
354*a0409676SBaptiste Daroussin 				max = lua_objlen (L, idx);
355*a0409676SBaptiste Daroussin #endif
356*a0409676SBaptiste Daroussin 				nelts = max;
357*a0409676SBaptiste Daroussin 			} else if (strcmp (classname, UCL_IMPL_ARRAY_TYPE_META) == 0) {
358*a0409676SBaptiste Daroussin 				is_array = true;
359*a0409676SBaptiste Daroussin 				is_implicit = true;
360*a0409676SBaptiste Daroussin 				found_mt = true;
361*a0409676SBaptiste Daroussin #if LUA_VERSION_NUM >= 502
362*a0409676SBaptiste Daroussin 				max = lua_rawlen (L, idx);
363*a0409676SBaptiste Daroussin #else
364*a0409676SBaptiste Daroussin 				max = lua_objlen (L, idx);
365*a0409676SBaptiste Daroussin #endif
366*a0409676SBaptiste Daroussin 				nelts = max;
367*a0409676SBaptiste Daroussin 			}
368*a0409676SBaptiste Daroussin 		}
369*a0409676SBaptiste Daroussin 
370*a0409676SBaptiste Daroussin 		lua_pop (L, 1);
371*a0409676SBaptiste Daroussin 	}
372*a0409676SBaptiste Daroussin 
373*a0409676SBaptiste Daroussin 	if (!found_mt) {
374*a0409676SBaptiste Daroussin 		/* Check for array (it is all inefficient) */
3754bf54857SBaptiste Daroussin 		lua_pushnil (L);
376*a0409676SBaptiste Daroussin 
3774bf54857SBaptiste Daroussin 		while (lua_next (L, idx) != 0) {
378*a0409676SBaptiste Daroussin 			lua_pushvalue (L, -2);
379*a0409676SBaptiste Daroussin 
380*a0409676SBaptiste Daroussin 			if (lua_type (L, -1) == LUA_TNUMBER) {
381*a0409676SBaptiste Daroussin 				double num = lua_tonumber (L, -1);
3824bf54857SBaptiste Daroussin 				if (num == (int) num) {
3834bf54857SBaptiste Daroussin 					if (num > max) {
3844bf54857SBaptiste Daroussin 						max = num;
3854bf54857SBaptiste Daroussin 					}
3864bf54857SBaptiste Daroussin 				}
3874bf54857SBaptiste Daroussin 				else {
3884bf54857SBaptiste Daroussin 					/* Keys are not integer */
3894bf54857SBaptiste Daroussin 					is_array = false;
3904bf54857SBaptiste Daroussin 				}
3914bf54857SBaptiste Daroussin 			}
3924bf54857SBaptiste Daroussin 			else {
3934bf54857SBaptiste Daroussin 				/* Keys are not numeric */
3944bf54857SBaptiste Daroussin 				is_array = false;
3954bf54857SBaptiste Daroussin 			}
396*a0409676SBaptiste Daroussin 
397*a0409676SBaptiste Daroussin 			lua_pop (L, 2);
398*a0409676SBaptiste Daroussin 			nelts ++;
399*a0409676SBaptiste Daroussin 		}
4004bf54857SBaptiste Daroussin 	}
4014bf54857SBaptiste Daroussin 
4024bf54857SBaptiste Daroussin 	/* Table iterate */
4034bf54857SBaptiste Daroussin 	if (is_array) {
4044bf54857SBaptiste Daroussin 		int i;
4054bf54857SBaptiste Daroussin 
406*a0409676SBaptiste Daroussin 		if (!is_implicit) {
4074bf54857SBaptiste Daroussin 			top = ucl_object_typed_new (UCL_ARRAY);
408*a0409676SBaptiste Daroussin 			ucl_object_reserve (top, nelts);
409*a0409676SBaptiste Daroussin 		}
410*a0409676SBaptiste Daroussin 		else {
411*a0409676SBaptiste Daroussin 			top = NULL;
412*a0409676SBaptiste Daroussin 		}
413*a0409676SBaptiste Daroussin 
4144bf54857SBaptiste Daroussin 		for (i = 1; i <= max; i ++) {
4154bf54857SBaptiste Daroussin 			lua_pushinteger (L, i);
4164bf54857SBaptiste Daroussin 			lua_gettable (L, idx);
417*a0409676SBaptiste Daroussin 
418*a0409676SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags);
419*a0409676SBaptiste Daroussin 
4204bf54857SBaptiste Daroussin 			if (obj != NULL) {
421*a0409676SBaptiste Daroussin 				if (is_implicit) {
422*a0409676SBaptiste Daroussin 					DL_APPEND (top, obj);
423*a0409676SBaptiste Daroussin 				}
424*a0409676SBaptiste Daroussin 				else {
4254bf54857SBaptiste Daroussin 					ucl_array_append (top, obj);
4264bf54857SBaptiste Daroussin 				}
427*a0409676SBaptiste Daroussin 			}
42839ee7a7aSBaptiste Daroussin 			lua_pop (L, 1);
4294bf54857SBaptiste Daroussin 		}
4304bf54857SBaptiste Daroussin 	}
4314bf54857SBaptiste Daroussin 	else {
4324bf54857SBaptiste Daroussin 		lua_pushnil (L);
4334bf54857SBaptiste Daroussin 		top = ucl_object_typed_new (UCL_OBJECT);
434*a0409676SBaptiste Daroussin 		ucl_object_reserve (top, nelts);
435*a0409676SBaptiste Daroussin 
4364bf54857SBaptiste Daroussin 		while (lua_next (L, idx) != 0) {
4374bf54857SBaptiste Daroussin 			/* copy key to avoid modifications */
438*a0409676SBaptiste Daroussin 			lua_pushvalue (L, -2);
439*a0409676SBaptiste Daroussin 			k = lua_tolstring (L, -1, &keylen);
440*a0409676SBaptiste Daroussin 			obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags);
4414bf54857SBaptiste Daroussin 
4424bf54857SBaptiste Daroussin 			if (obj != NULL) {
4434bf54857SBaptiste Daroussin 				ucl_object_insert_key (top, obj, k, keylen, true);
444*a0409676SBaptiste Daroussin 
445*a0409676SBaptiste Daroussin 				DL_FOREACH (obj, cur) {
446*a0409676SBaptiste Daroussin 					if (cur->keylen == 0) {
447*a0409676SBaptiste Daroussin 						cur->keylen = obj->keylen;
448*a0409676SBaptiste Daroussin 						cur->key = obj->key;
4494bf54857SBaptiste Daroussin 					}
450*a0409676SBaptiste Daroussin 				}
451*a0409676SBaptiste Daroussin 			}
452*a0409676SBaptiste Daroussin 			lua_pop (L, 2);
4534bf54857SBaptiste Daroussin 		}
4544bf54857SBaptiste Daroussin 	}
4554bf54857SBaptiste Daroussin 
4564bf54857SBaptiste Daroussin 	return top;
4574bf54857SBaptiste Daroussin }
4584bf54857SBaptiste Daroussin 
4594bf54857SBaptiste Daroussin /**
4604bf54857SBaptiste Daroussin  * Get a single element from lua to object obj
4614bf54857SBaptiste Daroussin  * @param L
4624bf54857SBaptiste Daroussin  * @param obj
4634bf54857SBaptiste Daroussin  * @param idx
4644bf54857SBaptiste Daroussin  */
4654bf54857SBaptiste Daroussin static ucl_object_t *
ucl_object_lua_fromelt(lua_State * L,int idx,ucl_string_flags_t flags)466*a0409676SBaptiste Daroussin ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)
4674bf54857SBaptiste Daroussin {
4684bf54857SBaptiste Daroussin 	int type;
4694bf54857SBaptiste Daroussin 	double num;
4704bf54857SBaptiste Daroussin 	ucl_object_t *obj = NULL;
4714bf54857SBaptiste Daroussin 	struct ucl_lua_funcdata *fd;
472*a0409676SBaptiste Daroussin 	const char *str;
473*a0409676SBaptiste Daroussin 	size_t sz;
4744bf54857SBaptiste Daroussin 
4754bf54857SBaptiste Daroussin 	type = lua_type (L, idx);
4764bf54857SBaptiste Daroussin 
4774bf54857SBaptiste Daroussin 	switch (type) {
4784bf54857SBaptiste Daroussin 	case LUA_TSTRING:
479*a0409676SBaptiste Daroussin 		str = lua_tolstring (L, idx, &sz);
480*a0409676SBaptiste Daroussin 
481*a0409676SBaptiste Daroussin 		if (str) {
482*a0409676SBaptiste Daroussin 			obj = ucl_object_fromstring_common (str, sz, flags);
483*a0409676SBaptiste Daroussin 		}
484*a0409676SBaptiste Daroussin 		else {
485*a0409676SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_NULL);
486*a0409676SBaptiste Daroussin 		}
4874bf54857SBaptiste Daroussin 		break;
4884bf54857SBaptiste Daroussin 	case LUA_TNUMBER:
4894bf54857SBaptiste Daroussin 		num = lua_tonumber (L, idx);
4904bf54857SBaptiste Daroussin 		if (num == (int64_t)num) {
4914bf54857SBaptiste Daroussin 			obj = ucl_object_fromint (num);
4924bf54857SBaptiste Daroussin 		}
4934bf54857SBaptiste Daroussin 		else {
4944bf54857SBaptiste Daroussin 			obj = ucl_object_fromdouble (num);
4954bf54857SBaptiste Daroussin 		}
4964bf54857SBaptiste Daroussin 		break;
4974bf54857SBaptiste Daroussin 	case LUA_TBOOLEAN:
4984bf54857SBaptiste Daroussin 		obj = ucl_object_frombool (lua_toboolean (L, idx));
4994bf54857SBaptiste Daroussin 		break;
5004bf54857SBaptiste Daroussin 	case LUA_TUSERDATA:
5014bf54857SBaptiste Daroussin 		if (lua_topointer (L, idx) == ucl_null) {
5024bf54857SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_NULL);
5034bf54857SBaptiste Daroussin 		}
5044bf54857SBaptiste Daroussin 		break;
5054bf54857SBaptiste Daroussin 	case LUA_TTABLE:
5064bf54857SBaptiste Daroussin 	case LUA_TFUNCTION:
5074bf54857SBaptiste Daroussin 	case LUA_TTHREAD:
5084bf54857SBaptiste Daroussin 		if (luaL_getmetafield (L, idx, "__gen_ucl")) {
5094bf54857SBaptiste Daroussin 			if (lua_isfunction (L, -1)) {
5104bf54857SBaptiste Daroussin 				lua_settop (L, 3); /* gen, obj, func */
5114bf54857SBaptiste Daroussin 				lua_insert (L, 1); /* func, gen, obj */
5124bf54857SBaptiste Daroussin 				lua_insert (L, 2); /* func, obj, gen */
5134bf54857SBaptiste Daroussin 				lua_call(L, 2, 1);
514*a0409676SBaptiste Daroussin 				obj = ucl_object_lua_fromelt (L, 1, flags);
5154bf54857SBaptiste Daroussin 			}
5164bf54857SBaptiste Daroussin 			lua_pop (L, 2);
5174bf54857SBaptiste Daroussin 		}
5184bf54857SBaptiste Daroussin 		else {
5194bf54857SBaptiste Daroussin 			if (type == LUA_TTABLE) {
520*a0409676SBaptiste Daroussin 				obj = ucl_object_lua_fromtable (L, idx, flags);
5214bf54857SBaptiste Daroussin 			}
5224bf54857SBaptiste Daroussin 			else if (type == LUA_TFUNCTION) {
5234bf54857SBaptiste Daroussin 				fd = malloc (sizeof (*fd));
5244bf54857SBaptiste Daroussin 				if (fd != NULL) {
5254bf54857SBaptiste Daroussin 					lua_pushvalue (L, idx);
5264bf54857SBaptiste Daroussin 					fd->L = L;
5274bf54857SBaptiste Daroussin 					fd->ret = NULL;
5284bf54857SBaptiste Daroussin 					fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
5294bf54857SBaptiste Daroussin 
5304bf54857SBaptiste Daroussin 					obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
531d9f0ce31SBaptiste Daroussin 							lua_ucl_userdata_emitter, (void *)fd);
5324bf54857SBaptiste Daroussin 				}
5334bf54857SBaptiste Daroussin 			}
5344bf54857SBaptiste Daroussin 		}
5354bf54857SBaptiste Daroussin 		break;
5364bf54857SBaptiste Daroussin 	}
5374bf54857SBaptiste Daroussin 
5384bf54857SBaptiste Daroussin 	return obj;
5394bf54857SBaptiste Daroussin }
5404bf54857SBaptiste Daroussin 
5414bf54857SBaptiste Daroussin /**
5424bf54857SBaptiste Daroussin  * @function ucl_object_lua_import(L, idx)
5434bf54857SBaptiste Daroussin  * Extracts ucl object from lua variable at `idx` position,
5444bf54857SBaptiste Daroussin  * @see ucl_object_push_lua for conversion definitions
5454bf54857SBaptiste Daroussin  * @param {lua_state} L lua state machine pointer
5464bf54857SBaptiste Daroussin  * @param {int} idx index where the source variable is placed
5474bf54857SBaptiste Daroussin  * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
5484bf54857SBaptiste Daroussin  * this object thus needs to be unref'ed after usage.
5494bf54857SBaptiste Daroussin  */
5504bf54857SBaptiste Daroussin ucl_object_t *
ucl_object_lua_import(lua_State * L,int idx)5514bf54857SBaptiste Daroussin ucl_object_lua_import (lua_State *L, int idx)
5524bf54857SBaptiste Daroussin {
5534bf54857SBaptiste Daroussin 	ucl_object_t *obj;
5544bf54857SBaptiste Daroussin 	int t;
5554bf54857SBaptiste Daroussin 
5564bf54857SBaptiste Daroussin 	t = lua_type (L, idx);
5574bf54857SBaptiste Daroussin 	switch (t) {
5584bf54857SBaptiste Daroussin 	case LUA_TTABLE:
559*a0409676SBaptiste Daroussin 		obj = ucl_object_lua_fromtable (L, idx, 0);
5604bf54857SBaptiste Daroussin 		break;
5614bf54857SBaptiste Daroussin 	default:
562*a0409676SBaptiste Daroussin 		obj = ucl_object_lua_fromelt (L, idx, 0);
563*a0409676SBaptiste Daroussin 		break;
564*a0409676SBaptiste Daroussin 	}
565*a0409676SBaptiste Daroussin 
566*a0409676SBaptiste Daroussin 	return obj;
567*a0409676SBaptiste Daroussin }
568*a0409676SBaptiste Daroussin 
569*a0409676SBaptiste Daroussin /**
570*a0409676SBaptiste Daroussin  * @function ucl_object_lua_import_escape(L, idx)
571*a0409676SBaptiste Daroussin  * Extracts ucl object from lua variable at `idx` position escaping JSON strings
572*a0409676SBaptiste Daroussin  * @see ucl_object_push_lua for conversion definitions
573*a0409676SBaptiste Daroussin  * @param {lua_state} L lua state machine pointer
574*a0409676SBaptiste Daroussin  * @param {int} idx index where the source variable is placed
575*a0409676SBaptiste Daroussin  * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
576*a0409676SBaptiste Daroussin  * this object thus needs to be unref'ed after usage.
577*a0409676SBaptiste Daroussin  */
578*a0409676SBaptiste Daroussin ucl_object_t *
ucl_object_lua_import_escape(lua_State * L,int idx)579*a0409676SBaptiste Daroussin ucl_object_lua_import_escape (lua_State *L, int idx)
580*a0409676SBaptiste Daroussin {
581*a0409676SBaptiste Daroussin 	ucl_object_t *obj;
582*a0409676SBaptiste Daroussin 	int t;
583*a0409676SBaptiste Daroussin 
584*a0409676SBaptiste Daroussin 	t = lua_type (L, idx);
585*a0409676SBaptiste Daroussin 	switch (t) {
586*a0409676SBaptiste Daroussin 	case LUA_TTABLE:
587*a0409676SBaptiste Daroussin 		obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);
588*a0409676SBaptiste Daroussin 		break;
589*a0409676SBaptiste Daroussin 	default:
590*a0409676SBaptiste Daroussin 		obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);
5914bf54857SBaptiste Daroussin 		break;
5924bf54857SBaptiste Daroussin 	}
5934bf54857SBaptiste Daroussin 
5944bf54857SBaptiste Daroussin 	return obj;
5954bf54857SBaptiste Daroussin }
5964bf54857SBaptiste Daroussin 
5974bf54857SBaptiste Daroussin static int
lua_ucl_to_string(lua_State * L,const ucl_object_t * obj,enum ucl_emitter type)59839ee7a7aSBaptiste Daroussin lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
59939ee7a7aSBaptiste Daroussin {
60039ee7a7aSBaptiste Daroussin 	unsigned char *result;
60139ee7a7aSBaptiste Daroussin 
60239ee7a7aSBaptiste Daroussin 	result = ucl_object_emit (obj, type);
60339ee7a7aSBaptiste Daroussin 
60439ee7a7aSBaptiste Daroussin 	if (result != NULL) {
60539ee7a7aSBaptiste Daroussin 		lua_pushstring (L, (const char *)result);
60639ee7a7aSBaptiste Daroussin 		free (result);
60739ee7a7aSBaptiste Daroussin 	}
60839ee7a7aSBaptiste Daroussin 	else {
60939ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
61039ee7a7aSBaptiste Daroussin 	}
61139ee7a7aSBaptiste Daroussin 
61239ee7a7aSBaptiste Daroussin 	return 1;
61339ee7a7aSBaptiste Daroussin }
61439ee7a7aSBaptiste Daroussin 
61539ee7a7aSBaptiste Daroussin static int
lua_ucl_parser_init(lua_State * L)6164bf54857SBaptiste Daroussin lua_ucl_parser_init (lua_State *L)
6174bf54857SBaptiste Daroussin {
6184bf54857SBaptiste Daroussin 	struct ucl_parser *parser, **pparser;
61911dd9ed6SBaptiste Daroussin 	int flags = UCL_PARSER_NO_FILEVARS;
6204bf54857SBaptiste Daroussin 
6214bf54857SBaptiste Daroussin 	if (lua_gettop (L) >= 1) {
6224bf54857SBaptiste Daroussin 		flags = lua_tonumber (L, 1);
6234bf54857SBaptiste Daroussin 	}
6244bf54857SBaptiste Daroussin 
6254bf54857SBaptiste Daroussin 	parser = ucl_parser_new (flags);
6264bf54857SBaptiste Daroussin 	if (parser == NULL) {
6274bf54857SBaptiste Daroussin 		lua_pushnil (L);
628*a0409676SBaptiste Daroussin 		return 1;
6294bf54857SBaptiste Daroussin 	}
6304bf54857SBaptiste Daroussin 
6314bf54857SBaptiste Daroussin 	pparser = lua_newuserdata (L, sizeof (parser));
6324bf54857SBaptiste Daroussin 	*pparser = parser;
6334bf54857SBaptiste Daroussin 	luaL_getmetatable (L, PARSER_META);
6344bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
6354bf54857SBaptiste Daroussin 
6364bf54857SBaptiste Daroussin 	return 1;
6374bf54857SBaptiste Daroussin }
6384bf54857SBaptiste Daroussin 
6394bf54857SBaptiste Daroussin static struct ucl_parser *
lua_ucl_parser_get(lua_State * L,int index)6404bf54857SBaptiste Daroussin lua_ucl_parser_get (lua_State *L, int index)
6414bf54857SBaptiste Daroussin {
6424bf54857SBaptiste Daroussin 	return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
6434bf54857SBaptiste Daroussin }
6444bf54857SBaptiste Daroussin 
64539ee7a7aSBaptiste Daroussin static ucl_object_t *
lua_ucl_object_get(lua_State * L,int index)64639ee7a7aSBaptiste Daroussin lua_ucl_object_get (lua_State *L, int index)
64739ee7a7aSBaptiste Daroussin {
64839ee7a7aSBaptiste Daroussin 	return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
64939ee7a7aSBaptiste Daroussin }
65039ee7a7aSBaptiste Daroussin 
651d9f0ce31SBaptiste Daroussin static void
lua_ucl_push_opaque(lua_State * L,ucl_object_t * obj)652d9f0ce31SBaptiste Daroussin lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
653d9f0ce31SBaptiste Daroussin {
654d9f0ce31SBaptiste Daroussin 	ucl_object_t **pobj;
655d9f0ce31SBaptiste Daroussin 
656d9f0ce31SBaptiste Daroussin 	pobj = lua_newuserdata (L, sizeof (*pobj));
657d9f0ce31SBaptiste Daroussin 	*pobj = obj;
658d9f0ce31SBaptiste Daroussin 	luaL_getmetatable (L, OBJECT_META);
659d9f0ce31SBaptiste Daroussin 	lua_setmetatable (L, -2);
660d9f0ce31SBaptiste Daroussin }
661d9f0ce31SBaptiste Daroussin 
66211dd9ed6SBaptiste Daroussin static inline enum ucl_parse_type
lua_ucl_str_to_parse_type(const char * str)66311dd9ed6SBaptiste Daroussin lua_ucl_str_to_parse_type (const char *str)
66411dd9ed6SBaptiste Daroussin {
66511dd9ed6SBaptiste Daroussin 	enum ucl_parse_type type = UCL_PARSE_UCL;
66611dd9ed6SBaptiste Daroussin 
66711dd9ed6SBaptiste Daroussin 	if (str != NULL) {
66811dd9ed6SBaptiste Daroussin 		if (strcasecmp (str, "msgpack") == 0) {
66911dd9ed6SBaptiste Daroussin 			type = UCL_PARSE_MSGPACK;
67011dd9ed6SBaptiste Daroussin 		}
67111dd9ed6SBaptiste Daroussin 		else if (strcasecmp (str, "sexp") == 0 ||
67211dd9ed6SBaptiste Daroussin 				strcasecmp (str, "csexp") == 0) {
67311dd9ed6SBaptiste Daroussin 			type = UCL_PARSE_CSEXP;
67411dd9ed6SBaptiste Daroussin 		}
67511dd9ed6SBaptiste Daroussin 		else if (strcasecmp (str, "auto") == 0) {
67611dd9ed6SBaptiste Daroussin 			type = UCL_PARSE_AUTO;
67711dd9ed6SBaptiste Daroussin 		}
67811dd9ed6SBaptiste Daroussin 	}
67911dd9ed6SBaptiste Daroussin 
68011dd9ed6SBaptiste Daroussin 	return type;
68111dd9ed6SBaptiste Daroussin }
68211dd9ed6SBaptiste Daroussin 
6834bf54857SBaptiste Daroussin /***
6844bf54857SBaptiste Daroussin  * @method parser:parse_file(name)
6854bf54857SBaptiste Daroussin  * Parse UCL object from file.
6864bf54857SBaptiste Daroussin  * @param {string} name filename to parse
6874bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
6884bf54857SBaptiste Daroussin @example
6894bf54857SBaptiste Daroussin local parser = ucl.parser()
6904bf54857SBaptiste Daroussin local res,err = parser:parse_file('/some/file.conf')
6914bf54857SBaptiste Daroussin 
6924bf54857SBaptiste Daroussin if not res then
6934bf54857SBaptiste Daroussin 	print('parser error: ' .. err)
6944bf54857SBaptiste Daroussin else
6954bf54857SBaptiste Daroussin 	-- Do something with object
6964bf54857SBaptiste Daroussin end
6974bf54857SBaptiste Daroussin  */
6984bf54857SBaptiste Daroussin static int
lua_ucl_parser_parse_file(lua_State * L)6994bf54857SBaptiste Daroussin lua_ucl_parser_parse_file (lua_State *L)
7004bf54857SBaptiste Daroussin {
7014bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
7024bf54857SBaptiste Daroussin 	const char *file;
7034bf54857SBaptiste Daroussin 	int ret = 2;
7044bf54857SBaptiste Daroussin 
7054bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
7064bf54857SBaptiste Daroussin 	file = luaL_checkstring (L, 2);
7074bf54857SBaptiste Daroussin 
7084bf54857SBaptiste Daroussin 	if (parser != NULL && file != NULL) {
7094bf54857SBaptiste Daroussin 		if (ucl_parser_add_file (parser, file)) {
7104bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
7114bf54857SBaptiste Daroussin 			ret = 1;
7124bf54857SBaptiste Daroussin 		}
7134bf54857SBaptiste Daroussin 		else {
7144bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
7154bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
7164bf54857SBaptiste Daroussin 		}
7174bf54857SBaptiste Daroussin 	}
7184bf54857SBaptiste Daroussin 	else {
7194bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
7204bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
7214bf54857SBaptiste Daroussin 	}
7224bf54857SBaptiste Daroussin 
7234bf54857SBaptiste Daroussin 	return ret;
7244bf54857SBaptiste Daroussin }
7254bf54857SBaptiste Daroussin 
7264bf54857SBaptiste Daroussin /***
727*a0409676SBaptiste Daroussin  * @method parser:register_variable(name, value)
728*a0409676SBaptiste Daroussin  * Register parser variable
729*a0409676SBaptiste Daroussin  * @param {string} name name of variable
730*a0409676SBaptiste Daroussin  * @param {string} value value of variable
731*a0409676SBaptiste Daroussin  * @return {bool} success
732*a0409676SBaptiste Daroussin @example
733*a0409676SBaptiste Daroussin local parser = ucl.parser()
734*a0409676SBaptiste Daroussin local res = parser:register_variable('CONFDIR', '/etc/foo')
735*a0409676SBaptiste Daroussin  */
736*a0409676SBaptiste Daroussin static int
lua_ucl_parser_register_variable(lua_State * L)737*a0409676SBaptiste Daroussin lua_ucl_parser_register_variable (lua_State *L)
738*a0409676SBaptiste Daroussin {
739*a0409676SBaptiste Daroussin 	struct ucl_parser *parser;
740*a0409676SBaptiste Daroussin 	const char *name, *value;
741*a0409676SBaptiste Daroussin 	int ret = 2;
742*a0409676SBaptiste Daroussin 
743*a0409676SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
744*a0409676SBaptiste Daroussin 	name = luaL_checkstring (L, 2);
745*a0409676SBaptiste Daroussin 	value = luaL_checkstring (L, 3);
746*a0409676SBaptiste Daroussin 
747*a0409676SBaptiste Daroussin 	if (parser != NULL && name != NULL && value != NULL) {
748*a0409676SBaptiste Daroussin 		ucl_parser_register_variable (parser, name, value);
749*a0409676SBaptiste Daroussin 		lua_pushboolean (L, true);
750*a0409676SBaptiste Daroussin 		ret = 1;
751*a0409676SBaptiste Daroussin 	}
752*a0409676SBaptiste Daroussin 	else {
753*a0409676SBaptiste Daroussin 		return luaL_error (L, "invalid arguments");
754*a0409676SBaptiste Daroussin 	}
755*a0409676SBaptiste Daroussin 
756*a0409676SBaptiste Daroussin 	return ret;
757*a0409676SBaptiste Daroussin }
758*a0409676SBaptiste Daroussin 
759*a0409676SBaptiste Daroussin /***
760*a0409676SBaptiste Daroussin  * @method parser:register_variables(vars)
761*a0409676SBaptiste Daroussin  * Register parser variables
762*a0409676SBaptiste Daroussin  * @param {table} vars names/values of variables
763*a0409676SBaptiste Daroussin  * @return {bool} success
764*a0409676SBaptiste Daroussin @example
765*a0409676SBaptiste Daroussin local parser = ucl.parser()
766*a0409676SBaptiste Daroussin local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'})
767*a0409676SBaptiste Daroussin  */
768*a0409676SBaptiste Daroussin static int
lua_ucl_parser_register_variables(lua_State * L)769*a0409676SBaptiste Daroussin lua_ucl_parser_register_variables (lua_State *L)
770*a0409676SBaptiste Daroussin {
771*a0409676SBaptiste Daroussin 	struct ucl_parser *parser;
772*a0409676SBaptiste Daroussin 	const char *name, *value;
773*a0409676SBaptiste Daroussin 	int ret = 2;
774*a0409676SBaptiste Daroussin 
775*a0409676SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
776*a0409676SBaptiste Daroussin 
777*a0409676SBaptiste Daroussin 	if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) {
778*a0409676SBaptiste Daroussin 		for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
779*a0409676SBaptiste Daroussin 			lua_pushvalue (L, -2);
780*a0409676SBaptiste Daroussin 			name = luaL_checkstring (L, -1);
781*a0409676SBaptiste Daroussin 			value = luaL_checkstring (L, -2);
782*a0409676SBaptiste Daroussin 			ucl_parser_register_variable (parser, name, value);
783*a0409676SBaptiste Daroussin 			lua_pop (L, 1);
784*a0409676SBaptiste Daroussin 		}
785*a0409676SBaptiste Daroussin 
786*a0409676SBaptiste Daroussin 		lua_pushboolean (L, true);
787*a0409676SBaptiste Daroussin 		ret = 1;
788*a0409676SBaptiste Daroussin 	}
789*a0409676SBaptiste Daroussin 	else {
790*a0409676SBaptiste Daroussin 		return luaL_error (L, "invalid arguments");
791*a0409676SBaptiste Daroussin 	}
792*a0409676SBaptiste Daroussin 
793*a0409676SBaptiste Daroussin 	return ret;
794*a0409676SBaptiste Daroussin }
795*a0409676SBaptiste Daroussin 
796*a0409676SBaptiste Daroussin /***
7974bf54857SBaptiste Daroussin  * @method parser:parse_string(input)
7984bf54857SBaptiste Daroussin  * Parse UCL object from file.
7994bf54857SBaptiste Daroussin  * @param {string} input string to parse
8004bf54857SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
8014bf54857SBaptiste Daroussin  */
8024bf54857SBaptiste Daroussin static int
lua_ucl_parser_parse_string(lua_State * L)8034bf54857SBaptiste Daroussin lua_ucl_parser_parse_string (lua_State *L)
8044bf54857SBaptiste Daroussin {
8054bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
8064bf54857SBaptiste Daroussin 	const char *string;
8074bf54857SBaptiste Daroussin 	size_t llen;
80811dd9ed6SBaptiste Daroussin 	enum ucl_parse_type type = UCL_PARSE_UCL;
8094bf54857SBaptiste Daroussin 	int ret = 2;
8104bf54857SBaptiste Daroussin 
8114bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
8124bf54857SBaptiste Daroussin 	string = luaL_checklstring (L, 2, &llen);
8134bf54857SBaptiste Daroussin 
81411dd9ed6SBaptiste Daroussin 	if (lua_type (L, 3) == LUA_TSTRING) {
81511dd9ed6SBaptiste Daroussin 		type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
81611dd9ed6SBaptiste Daroussin 	}
81711dd9ed6SBaptiste Daroussin 
8184bf54857SBaptiste Daroussin 	if (parser != NULL && string != NULL) {
81911dd9ed6SBaptiste Daroussin 		if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string,
82011dd9ed6SBaptiste Daroussin 				llen, 0, UCL_DUPLICATE_APPEND, type)) {
8214bf54857SBaptiste Daroussin 			lua_pushboolean (L, true);
8224bf54857SBaptiste Daroussin 			ret = 1;
8234bf54857SBaptiste Daroussin 		}
8244bf54857SBaptiste Daroussin 		else {
8254bf54857SBaptiste Daroussin 			lua_pushboolean (L, false);
8264bf54857SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
8274bf54857SBaptiste Daroussin 		}
8284bf54857SBaptiste Daroussin 	}
8294bf54857SBaptiste Daroussin 	else {
8304bf54857SBaptiste Daroussin 		lua_pushboolean (L, false);
8314bf54857SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
8324bf54857SBaptiste Daroussin 	}
8334bf54857SBaptiste Daroussin 
8344bf54857SBaptiste Daroussin 	return ret;
8354bf54857SBaptiste Daroussin }
8364bf54857SBaptiste Daroussin 
837*a0409676SBaptiste Daroussin struct _rspamd_lua_text {
838*a0409676SBaptiste Daroussin 	const char *start;
839*a0409676SBaptiste Daroussin 	unsigned int len;
840*a0409676SBaptiste Daroussin 	unsigned int flags;
841*a0409676SBaptiste Daroussin };
842*a0409676SBaptiste Daroussin 
843*a0409676SBaptiste Daroussin /***
844*a0409676SBaptiste Daroussin  * @method parser:parse_text(input)
845*a0409676SBaptiste Daroussin  * Parse UCL object from text object (Rspamd specific).
846*a0409676SBaptiste Daroussin  * @param {rspamd_text} input text to parse
847*a0409676SBaptiste Daroussin  * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
848*a0409676SBaptiste Daroussin  */
849*a0409676SBaptiste Daroussin static int
lua_ucl_parser_parse_text(lua_State * L)850*a0409676SBaptiste Daroussin lua_ucl_parser_parse_text (lua_State *L)
851*a0409676SBaptiste Daroussin {
852*a0409676SBaptiste Daroussin 	struct ucl_parser *parser;
853*a0409676SBaptiste Daroussin 	struct _rspamd_lua_text *t;
854*a0409676SBaptiste Daroussin 	enum ucl_parse_type type = UCL_PARSE_UCL;
855*a0409676SBaptiste Daroussin 	int ret = 2;
856*a0409676SBaptiste Daroussin 
857*a0409676SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
858*a0409676SBaptiste Daroussin 	t = lua_touserdata (L, 2);
859*a0409676SBaptiste Daroussin 
860*a0409676SBaptiste Daroussin 	if (lua_type (L, 3) == LUA_TSTRING) {
861*a0409676SBaptiste Daroussin 		type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
862*a0409676SBaptiste Daroussin 	}
863*a0409676SBaptiste Daroussin 
864*a0409676SBaptiste Daroussin 	if (parser != NULL && t != NULL) {
865*a0409676SBaptiste Daroussin 		if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start,
866*a0409676SBaptiste Daroussin 				t->len, 0, UCL_DUPLICATE_APPEND, type)) {
867*a0409676SBaptiste Daroussin 			lua_pushboolean (L, true);
868*a0409676SBaptiste Daroussin 			ret = 1;
869*a0409676SBaptiste Daroussin 		}
870*a0409676SBaptiste Daroussin 		else {
871*a0409676SBaptiste Daroussin 			lua_pushboolean (L, false);
872*a0409676SBaptiste Daroussin 			lua_pushstring (L, ucl_parser_get_error (parser));
873*a0409676SBaptiste Daroussin 		}
874*a0409676SBaptiste Daroussin 	}
875*a0409676SBaptiste Daroussin 	else {
876*a0409676SBaptiste Daroussin 		lua_pushboolean (L, false);
877*a0409676SBaptiste Daroussin 		lua_pushstring (L, "invalid arguments");
878*a0409676SBaptiste Daroussin 	}
879*a0409676SBaptiste Daroussin 
880*a0409676SBaptiste Daroussin 	return ret;
881*a0409676SBaptiste Daroussin }
882*a0409676SBaptiste Daroussin 
8834bf54857SBaptiste Daroussin /***
8844bf54857SBaptiste Daroussin  * @method parser:get_object()
8854bf54857SBaptiste Daroussin  * Get top object from parser and export it to lua representation.
8864bf54857SBaptiste Daroussin  * @return {variant or nil} ucl object as lua native variable
8874bf54857SBaptiste Daroussin  */
8884bf54857SBaptiste Daroussin static int
lua_ucl_parser_get_object(lua_State * L)8894bf54857SBaptiste Daroussin lua_ucl_parser_get_object (lua_State *L)
8904bf54857SBaptiste Daroussin {
8914bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
8924bf54857SBaptiste Daroussin 	ucl_object_t *obj;
8934bf54857SBaptiste Daroussin 	int ret = 1;
8944bf54857SBaptiste Daroussin 
8954bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
8964bf54857SBaptiste Daroussin 	obj = ucl_parser_get_object (parser);
8974bf54857SBaptiste Daroussin 
8984bf54857SBaptiste Daroussin 	if (obj != NULL) {
8994bf54857SBaptiste Daroussin 		ret = ucl_object_push_lua (L, obj, false);
9004bf54857SBaptiste Daroussin 		/* no need to keep reference */
9014bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
9024bf54857SBaptiste Daroussin 	}
9034bf54857SBaptiste Daroussin 	else {
9044bf54857SBaptiste Daroussin 		lua_pushnil (L);
9054bf54857SBaptiste Daroussin 	}
9064bf54857SBaptiste Daroussin 
9074bf54857SBaptiste Daroussin 	return ret;
9084bf54857SBaptiste Daroussin }
9094bf54857SBaptiste Daroussin 
91039ee7a7aSBaptiste Daroussin /***
91139ee7a7aSBaptiste Daroussin  * @method parser:get_object_wrapped()
91239ee7a7aSBaptiste Daroussin  * Get top object from parser and export it to userdata object without
91339ee7a7aSBaptiste Daroussin  * unwrapping to lua.
91439ee7a7aSBaptiste Daroussin  * @return {ucl.object or nil} ucl object wrapped variable
91539ee7a7aSBaptiste Daroussin  */
91639ee7a7aSBaptiste Daroussin static int
lua_ucl_parser_get_object_wrapped(lua_State * L)91739ee7a7aSBaptiste Daroussin lua_ucl_parser_get_object_wrapped (lua_State *L)
91839ee7a7aSBaptiste Daroussin {
91939ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser;
920d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj;
92139ee7a7aSBaptiste Daroussin 	int ret = 1;
92239ee7a7aSBaptiste Daroussin 
92339ee7a7aSBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
92439ee7a7aSBaptiste Daroussin 	obj = ucl_parser_get_object (parser);
92539ee7a7aSBaptiste Daroussin 
92639ee7a7aSBaptiste Daroussin 	if (obj != NULL) {
927d9f0ce31SBaptiste Daroussin 		lua_ucl_push_opaque (L, obj);
92839ee7a7aSBaptiste Daroussin 	}
92939ee7a7aSBaptiste Daroussin 	else {
93039ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
93139ee7a7aSBaptiste Daroussin 	}
93239ee7a7aSBaptiste Daroussin 
93339ee7a7aSBaptiste Daroussin 	return ret;
93439ee7a7aSBaptiste Daroussin }
93539ee7a7aSBaptiste Daroussin 
93639ee7a7aSBaptiste Daroussin /***
93739ee7a7aSBaptiste Daroussin  * @method parser:validate(schema)
93839ee7a7aSBaptiste Daroussin  * Validates the top object in the parser against schema. Schema might be
93939ee7a7aSBaptiste Daroussin  * another object or a string that represents file to load schema from.
94039ee7a7aSBaptiste Daroussin  *
94139ee7a7aSBaptiste Daroussin  * @param {string/table} schema input schema
94239ee7a7aSBaptiste Daroussin  * @return {result,err} two values: boolean result and the corresponding error
94339ee7a7aSBaptiste Daroussin  *
94439ee7a7aSBaptiste Daroussin  */
94539ee7a7aSBaptiste Daroussin static int
lua_ucl_parser_validate(lua_State * L)94639ee7a7aSBaptiste Daroussin lua_ucl_parser_validate (lua_State *L)
94739ee7a7aSBaptiste Daroussin {
94839ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser, *schema_parser;
94939ee7a7aSBaptiste Daroussin 	ucl_object_t *schema;
95039ee7a7aSBaptiste Daroussin 	const char *schema_file;
95139ee7a7aSBaptiste Daroussin 	struct ucl_schema_error err;
95239ee7a7aSBaptiste Daroussin 
95339ee7a7aSBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
95439ee7a7aSBaptiste Daroussin 
95539ee7a7aSBaptiste Daroussin 	if (parser && parser->top_obj) {
95639ee7a7aSBaptiste Daroussin 		if (lua_type (L, 2) == LUA_TTABLE) {
95739ee7a7aSBaptiste Daroussin 			schema = ucl_object_lua_import (L, 2);
95839ee7a7aSBaptiste Daroussin 
95939ee7a7aSBaptiste Daroussin 			if (schema == NULL) {
96039ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, false);
96139ee7a7aSBaptiste Daroussin 				lua_pushstring (L, "cannot load schema from lua table");
96239ee7a7aSBaptiste Daroussin 
96339ee7a7aSBaptiste Daroussin 				return 2;
96439ee7a7aSBaptiste Daroussin 			}
96539ee7a7aSBaptiste Daroussin 		}
96639ee7a7aSBaptiste Daroussin 		else if (lua_type (L, 2) == LUA_TSTRING) {
96739ee7a7aSBaptiste Daroussin 			schema_parser = ucl_parser_new (0);
96839ee7a7aSBaptiste Daroussin 			schema_file = luaL_checkstring (L, 2);
96939ee7a7aSBaptiste Daroussin 
97039ee7a7aSBaptiste Daroussin 			if (!ucl_parser_add_file (schema_parser, schema_file)) {
97139ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, false);
97239ee7a7aSBaptiste Daroussin 				lua_pushfstring (L, "cannot parse schema file \"%s\": "
97339ee7a7aSBaptiste Daroussin 						"%s", schema_file, ucl_parser_get_error (parser));
97439ee7a7aSBaptiste Daroussin 				ucl_parser_free (schema_parser);
97539ee7a7aSBaptiste Daroussin 
97639ee7a7aSBaptiste Daroussin 				return 2;
97739ee7a7aSBaptiste Daroussin 			}
97839ee7a7aSBaptiste Daroussin 
97939ee7a7aSBaptiste Daroussin 			schema = ucl_parser_get_object (schema_parser);
98039ee7a7aSBaptiste Daroussin 			ucl_parser_free (schema_parser);
98139ee7a7aSBaptiste Daroussin 		}
98239ee7a7aSBaptiste Daroussin 		else {
98339ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, false);
98439ee7a7aSBaptiste Daroussin 			lua_pushstring (L, "invalid schema argument");
98539ee7a7aSBaptiste Daroussin 
98639ee7a7aSBaptiste Daroussin 			return 2;
98739ee7a7aSBaptiste Daroussin 		}
98839ee7a7aSBaptiste Daroussin 
98939ee7a7aSBaptiste Daroussin 		if (!ucl_object_validate (schema, parser->top_obj, &err)) {
99039ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, false);
99139ee7a7aSBaptiste Daroussin 			lua_pushfstring (L, "validation error: "
99239ee7a7aSBaptiste Daroussin 					"%s", err.msg);
99339ee7a7aSBaptiste Daroussin 		}
99439ee7a7aSBaptiste Daroussin 		else {
99539ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, true);
99639ee7a7aSBaptiste Daroussin 			lua_pushnil (L);
99739ee7a7aSBaptiste Daroussin 		}
99839ee7a7aSBaptiste Daroussin 
99939ee7a7aSBaptiste Daroussin 		ucl_object_unref (schema);
100039ee7a7aSBaptiste Daroussin 	}
100139ee7a7aSBaptiste Daroussin 	else {
100239ee7a7aSBaptiste Daroussin 		lua_pushboolean (L, false);
100339ee7a7aSBaptiste Daroussin 		lua_pushstring (L, "invalid parser or empty top object");
100439ee7a7aSBaptiste Daroussin 	}
100539ee7a7aSBaptiste Daroussin 
100639ee7a7aSBaptiste Daroussin 	return 2;
100739ee7a7aSBaptiste Daroussin }
100839ee7a7aSBaptiste Daroussin 
10094bf54857SBaptiste Daroussin static int
lua_ucl_parser_gc(lua_State * L)10104bf54857SBaptiste Daroussin lua_ucl_parser_gc (lua_State *L)
10114bf54857SBaptiste Daroussin {
10124bf54857SBaptiste Daroussin 	struct ucl_parser *parser;
10134bf54857SBaptiste Daroussin 
10144bf54857SBaptiste Daroussin 	parser = lua_ucl_parser_get (L, 1);
10154bf54857SBaptiste Daroussin 	ucl_parser_free (parser);
10164bf54857SBaptiste Daroussin 
10174bf54857SBaptiste Daroussin 	return 0;
10184bf54857SBaptiste Daroussin }
10194bf54857SBaptiste Daroussin 
102039ee7a7aSBaptiste Daroussin /***
102139ee7a7aSBaptiste Daroussin  * @method object:unwrap()
102239ee7a7aSBaptiste Daroussin  * Unwraps opaque ucl object to the native lua object (performing copying)
102339ee7a7aSBaptiste Daroussin  * @return {variant} any lua object
102439ee7a7aSBaptiste Daroussin  */
102539ee7a7aSBaptiste Daroussin static int
lua_ucl_object_unwrap(lua_State * L)102639ee7a7aSBaptiste Daroussin lua_ucl_object_unwrap (lua_State *L)
102739ee7a7aSBaptiste Daroussin {
102839ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
102939ee7a7aSBaptiste Daroussin 
103039ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
103139ee7a7aSBaptiste Daroussin 
103239ee7a7aSBaptiste Daroussin 	if (obj) {
103339ee7a7aSBaptiste Daroussin 		ucl_object_push_lua (L, obj, true);
103439ee7a7aSBaptiste Daroussin 	}
103539ee7a7aSBaptiste Daroussin 	else {
103639ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
103739ee7a7aSBaptiste Daroussin 	}
103839ee7a7aSBaptiste Daroussin 
103939ee7a7aSBaptiste Daroussin 	return 1;
104039ee7a7aSBaptiste Daroussin }
104139ee7a7aSBaptiste Daroussin 
104211dd9ed6SBaptiste Daroussin static inline enum ucl_emitter
lua_ucl_str_to_emit_type(const char * strtype)104311dd9ed6SBaptiste Daroussin lua_ucl_str_to_emit_type (const char *strtype)
104411dd9ed6SBaptiste Daroussin {
104511dd9ed6SBaptiste Daroussin 	enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
104611dd9ed6SBaptiste Daroussin 
104711dd9ed6SBaptiste Daroussin 	if (strcasecmp (strtype, "json") == 0) {
104811dd9ed6SBaptiste Daroussin 		format = UCL_EMIT_JSON;
104911dd9ed6SBaptiste Daroussin 	}
105011dd9ed6SBaptiste Daroussin 	else if (strcasecmp (strtype, "json-compact") == 0) {
105111dd9ed6SBaptiste Daroussin 		format = UCL_EMIT_JSON_COMPACT;
105211dd9ed6SBaptiste Daroussin 	}
105311dd9ed6SBaptiste Daroussin 	else if (strcasecmp (strtype, "yaml") == 0) {
105411dd9ed6SBaptiste Daroussin 		format = UCL_EMIT_YAML;
105511dd9ed6SBaptiste Daroussin 	}
105611dd9ed6SBaptiste Daroussin 	else if (strcasecmp (strtype, "config") == 0 ||
105711dd9ed6SBaptiste Daroussin 			strcasecmp (strtype, "ucl") == 0) {
105811dd9ed6SBaptiste Daroussin 		format = UCL_EMIT_CONFIG;
105911dd9ed6SBaptiste Daroussin 	}
106011dd9ed6SBaptiste Daroussin 
106111dd9ed6SBaptiste Daroussin 	return format;
106211dd9ed6SBaptiste Daroussin }
106311dd9ed6SBaptiste Daroussin 
106439ee7a7aSBaptiste Daroussin /***
106539ee7a7aSBaptiste Daroussin  * @method object:tostring(type)
106639ee7a7aSBaptiste Daroussin  * Unwraps opaque ucl object to string (json by default). Optionally you can
106739ee7a7aSBaptiste Daroussin  * specify output format:
106839ee7a7aSBaptiste Daroussin  *
106939ee7a7aSBaptiste Daroussin  * - `json` - fine printed json
107039ee7a7aSBaptiste Daroussin  * - `json-compact` - compacted json
107139ee7a7aSBaptiste Daroussin  * - `config` - fine printed configuration
107239ee7a7aSBaptiste Daroussin  * - `ucl` - same as `config`
107339ee7a7aSBaptiste Daroussin  * - `yaml` - embedded yaml
107439ee7a7aSBaptiste Daroussin  * @param {string} type optional
107539ee7a7aSBaptiste Daroussin  * @return {string} string representation of the opaque ucl object
107639ee7a7aSBaptiste Daroussin  */
107739ee7a7aSBaptiste Daroussin static int
lua_ucl_object_tostring(lua_State * L)107839ee7a7aSBaptiste Daroussin lua_ucl_object_tostring (lua_State *L)
107939ee7a7aSBaptiste Daroussin {
108039ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
108139ee7a7aSBaptiste Daroussin 	enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
108239ee7a7aSBaptiste Daroussin 
108339ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
108439ee7a7aSBaptiste Daroussin 
108539ee7a7aSBaptiste Daroussin 	if (obj) {
108639ee7a7aSBaptiste Daroussin 		if (lua_gettop (L) > 1) {
108739ee7a7aSBaptiste Daroussin 			if (lua_type (L, 2) == LUA_TSTRING) {
108839ee7a7aSBaptiste Daroussin 				const char *strtype = lua_tostring (L, 2);
108939ee7a7aSBaptiste Daroussin 
109011dd9ed6SBaptiste Daroussin 				format = lua_ucl_str_to_emit_type (strtype);
109139ee7a7aSBaptiste Daroussin 			}
109239ee7a7aSBaptiste Daroussin 		}
109339ee7a7aSBaptiste Daroussin 
109439ee7a7aSBaptiste Daroussin 		return lua_ucl_to_string (L, obj, format);
109539ee7a7aSBaptiste Daroussin 	}
109639ee7a7aSBaptiste Daroussin 	else {
109739ee7a7aSBaptiste Daroussin 		lua_pushnil (L);
109839ee7a7aSBaptiste Daroussin 	}
109939ee7a7aSBaptiste Daroussin 
110039ee7a7aSBaptiste Daroussin 	return 1;
110139ee7a7aSBaptiste Daroussin }
110239ee7a7aSBaptiste Daroussin 
110339ee7a7aSBaptiste Daroussin /***
1104d9f0ce31SBaptiste Daroussin  * @method object:validate(schema[, path[, ext_refs]])
110539ee7a7aSBaptiste Daroussin  * Validates the given ucl object using schema object represented as another
110639ee7a7aSBaptiste Daroussin  * opaque ucl object. You can also specify path in the form `#/path/def` to
110739ee7a7aSBaptiste Daroussin  * specify the specific schema element to perform validation.
110839ee7a7aSBaptiste Daroussin  *
110939ee7a7aSBaptiste Daroussin  * @param {ucl.object} schema schema object
111039ee7a7aSBaptiste Daroussin  * @param {string} path optional path for validation procedure
1111d9f0ce31SBaptiste Daroussin  * @return {result,err} two values: boolean result and the corresponding
1112d9f0ce31SBaptiste Daroussin  * error, if `ext_refs` are also specified, then they are returned as opaque
1113d9f0ce31SBaptiste Daroussin  * ucl object as {result,err,ext_refs}
111439ee7a7aSBaptiste Daroussin  */
111539ee7a7aSBaptiste Daroussin static int
lua_ucl_object_validate(lua_State * L)111639ee7a7aSBaptiste Daroussin lua_ucl_object_validate (lua_State *L)
111739ee7a7aSBaptiste Daroussin {
1118d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj, *schema, *ext_refs = NULL;
111939ee7a7aSBaptiste Daroussin 	const ucl_object_t *schema_elt;
112039ee7a7aSBaptiste Daroussin 	bool res = false;
112139ee7a7aSBaptiste Daroussin 	struct ucl_schema_error err;
112239ee7a7aSBaptiste Daroussin 	const char *path = NULL;
112339ee7a7aSBaptiste Daroussin 
112439ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
112539ee7a7aSBaptiste Daroussin 	schema = lua_ucl_object_get (L, 2);
112639ee7a7aSBaptiste Daroussin 
112739ee7a7aSBaptiste Daroussin 	if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
1128d9f0ce31SBaptiste Daroussin 		if (lua_gettop (L) > 2) {
1129d9f0ce31SBaptiste Daroussin 			if (lua_type (L, 3) == LUA_TSTRING) {
113039ee7a7aSBaptiste Daroussin 				path = lua_tostring (L, 3);
113139ee7a7aSBaptiste Daroussin 				if (path[0] == '#') {
113239ee7a7aSBaptiste Daroussin 					path++;
113339ee7a7aSBaptiste Daroussin 				}
113439ee7a7aSBaptiste Daroussin 			}
1135d9f0ce31SBaptiste Daroussin 			else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) ==
1136d9f0ce31SBaptiste Daroussin 						LUA_TTABLE) {
1137d9f0ce31SBaptiste Daroussin 				/* External refs */
1138d9f0ce31SBaptiste Daroussin 				ext_refs = lua_ucl_object_get (L, 3);
1139d9f0ce31SBaptiste Daroussin 			}
1140d9f0ce31SBaptiste Daroussin 
1141d9f0ce31SBaptiste Daroussin 			if (lua_gettop (L) > 3) {
1142d9f0ce31SBaptiste Daroussin 				if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) ==
1143d9f0ce31SBaptiste Daroussin 						LUA_TTABLE) {
1144d9f0ce31SBaptiste Daroussin 					/* External refs */
1145d9f0ce31SBaptiste Daroussin 					ext_refs = lua_ucl_object_get (L, 4);
1146d9f0ce31SBaptiste Daroussin 				}
1147d9f0ce31SBaptiste Daroussin 			}
1148d9f0ce31SBaptiste Daroussin 		}
114939ee7a7aSBaptiste Daroussin 
115039ee7a7aSBaptiste Daroussin 		if (path) {
1151d9f0ce31SBaptiste Daroussin 			schema_elt = ucl_object_lookup_path_char (schema, path, '/');
115239ee7a7aSBaptiste Daroussin 		}
115339ee7a7aSBaptiste Daroussin 		else {
115439ee7a7aSBaptiste Daroussin 			/* Use the top object */
115539ee7a7aSBaptiste Daroussin 			schema_elt = schema;
115639ee7a7aSBaptiste Daroussin 		}
115739ee7a7aSBaptiste Daroussin 
115839ee7a7aSBaptiste Daroussin 		if (schema_elt) {
1159d9f0ce31SBaptiste Daroussin 			res = ucl_object_validate_root_ext (schema_elt, obj, schema,
1160d9f0ce31SBaptiste Daroussin 					ext_refs, &err);
116139ee7a7aSBaptiste Daroussin 
116239ee7a7aSBaptiste Daroussin 			if (res) {
116339ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, res);
116439ee7a7aSBaptiste Daroussin 				lua_pushnil (L);
1165d9f0ce31SBaptiste Daroussin 
1166d9f0ce31SBaptiste Daroussin 				if (ext_refs) {
1167d9f0ce31SBaptiste Daroussin 					lua_ucl_push_opaque (L, ext_refs);
1168d9f0ce31SBaptiste Daroussin 				}
116939ee7a7aSBaptiste Daroussin 			}
117039ee7a7aSBaptiste Daroussin 			else {
117139ee7a7aSBaptiste Daroussin 				lua_pushboolean (L, res);
117239ee7a7aSBaptiste Daroussin 				lua_pushfstring (L, "validation error: %s", err.msg);
1173d9f0ce31SBaptiste Daroussin 
1174d9f0ce31SBaptiste Daroussin 				if (ext_refs) {
1175d9f0ce31SBaptiste Daroussin 					lua_ucl_push_opaque (L, ext_refs);
1176d9f0ce31SBaptiste Daroussin 				}
117739ee7a7aSBaptiste Daroussin 			}
117839ee7a7aSBaptiste Daroussin 		}
117939ee7a7aSBaptiste Daroussin 		else {
118039ee7a7aSBaptiste Daroussin 			lua_pushboolean (L, res);
118139ee7a7aSBaptiste Daroussin 
118239ee7a7aSBaptiste Daroussin 			lua_pushfstring (L, "cannot find the requested path: %s", path);
1183d9f0ce31SBaptiste Daroussin 
1184d9f0ce31SBaptiste Daroussin 			if (ext_refs) {
1185d9f0ce31SBaptiste Daroussin 				lua_ucl_push_opaque (L, ext_refs);
118639ee7a7aSBaptiste Daroussin 			}
118739ee7a7aSBaptiste Daroussin 		}
118839ee7a7aSBaptiste Daroussin 	}
118939ee7a7aSBaptiste Daroussin 	else {
119039ee7a7aSBaptiste Daroussin 		lua_pushboolean (L, res);
119139ee7a7aSBaptiste Daroussin 		lua_pushstring (L, "invalid object or schema");
119239ee7a7aSBaptiste Daroussin 	}
119339ee7a7aSBaptiste Daroussin 
1194d9f0ce31SBaptiste Daroussin 	if (ext_refs) {
1195d9f0ce31SBaptiste Daroussin 		return 3;
1196d9f0ce31SBaptiste Daroussin 	}
1197d9f0ce31SBaptiste Daroussin 
119839ee7a7aSBaptiste Daroussin 	return 2;
119939ee7a7aSBaptiste Daroussin }
120039ee7a7aSBaptiste Daroussin 
120139ee7a7aSBaptiste Daroussin static int
lua_ucl_object_gc(lua_State * L)120239ee7a7aSBaptiste Daroussin lua_ucl_object_gc (lua_State *L)
120339ee7a7aSBaptiste Daroussin {
120439ee7a7aSBaptiste Daroussin 	ucl_object_t *obj;
120539ee7a7aSBaptiste Daroussin 
120639ee7a7aSBaptiste Daroussin 	obj = lua_ucl_object_get (L, 1);
120739ee7a7aSBaptiste Daroussin 
120839ee7a7aSBaptiste Daroussin 	ucl_object_unref (obj);
120939ee7a7aSBaptiste Daroussin 
121039ee7a7aSBaptiste Daroussin 	return 0;
121139ee7a7aSBaptiste Daroussin }
121239ee7a7aSBaptiste Daroussin 
12134bf54857SBaptiste Daroussin static void
lua_ucl_parser_mt(lua_State * L)12144bf54857SBaptiste Daroussin lua_ucl_parser_mt (lua_State *L)
12154bf54857SBaptiste Daroussin {
12164bf54857SBaptiste Daroussin 	luaL_newmetatable (L, PARSER_META);
12174bf54857SBaptiste Daroussin 
12184bf54857SBaptiste Daroussin 	lua_pushvalue(L, -1);
12194bf54857SBaptiste Daroussin 	lua_setfield(L, -2, "__index");
12204bf54857SBaptiste Daroussin 
12214bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_gc);
12224bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__gc");
12234bf54857SBaptiste Daroussin 
12244bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_file);
12254bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_file");
12264bf54857SBaptiste Daroussin 
12274bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_string);
12284bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parse_string");
12294bf54857SBaptiste Daroussin 
1230*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_parse_text);
1231*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "parse_text");
1232*a0409676SBaptiste Daroussin 
1233*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_register_variable);
1234*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "register_variable");
1235*a0409676SBaptiste Daroussin 
1236*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_register_variables);
1237*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "register_variables");
1238*a0409676SBaptiste Daroussin 
12394bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_get_object);
12404bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "get_object");
12414bf54857SBaptiste Daroussin 
124239ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
124339ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "get_object_wrapped");
124439ee7a7aSBaptiste Daroussin 
124539ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_validate);
124639ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "validate");
124739ee7a7aSBaptiste Daroussin 
12484bf54857SBaptiste Daroussin 	lua_pop (L, 1);
12494bf54857SBaptiste Daroussin }
12504bf54857SBaptiste Daroussin 
125139ee7a7aSBaptiste Daroussin static void
lua_ucl_object_mt(lua_State * L)125239ee7a7aSBaptiste Daroussin lua_ucl_object_mt (lua_State *L)
12534bf54857SBaptiste Daroussin {
125439ee7a7aSBaptiste Daroussin 	luaL_newmetatable (L, OBJECT_META);
12554bf54857SBaptiste Daroussin 
125639ee7a7aSBaptiste Daroussin 	lua_pushvalue(L, -1);
125739ee7a7aSBaptiste Daroussin 	lua_setfield(L, -2, "__index");
12584bf54857SBaptiste Daroussin 
125939ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_gc);
126039ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "__gc");
12614bf54857SBaptiste Daroussin 
126239ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
126339ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
126439ee7a7aSBaptiste Daroussin 
126539ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
126639ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "tostring");
126739ee7a7aSBaptiste Daroussin 
126839ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_unwrap);
126939ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "unwrap");
127039ee7a7aSBaptiste Daroussin 
127139ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_unwrap);
127239ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "tolua");
127339ee7a7aSBaptiste Daroussin 
127439ee7a7aSBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_validate);
127539ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "validate");
127639ee7a7aSBaptiste Daroussin 
127739ee7a7aSBaptiste Daroussin 	lua_pushstring (L, OBJECT_META);
127839ee7a7aSBaptiste Daroussin 	lua_setfield (L, -2, "class");
127939ee7a7aSBaptiste Daroussin 
128039ee7a7aSBaptiste Daroussin 	lua_pop (L, 1);
12814bf54857SBaptiste Daroussin }
12824bf54857SBaptiste Daroussin 
1283*a0409676SBaptiste Daroussin static void
lua_ucl_types_mt(lua_State * L)1284*a0409676SBaptiste Daroussin lua_ucl_types_mt (lua_State *L)
1285*a0409676SBaptiste Daroussin {
1286*a0409676SBaptiste Daroussin 	luaL_newmetatable (L, UCL_OBJECT_TYPE_META);
1287*a0409676SBaptiste Daroussin 
1288*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1289*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
1290*a0409676SBaptiste Daroussin 
1291*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1292*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "tostring");
1293*a0409676SBaptiste Daroussin 
1294*a0409676SBaptiste Daroussin 	lua_pushstring (L, UCL_OBJECT_TYPE_META);
1295*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "class");
1296*a0409676SBaptiste Daroussin 
1297*a0409676SBaptiste Daroussin 	lua_pop (L, 1);
1298*a0409676SBaptiste Daroussin 
1299*a0409676SBaptiste Daroussin 	luaL_newmetatable (L, UCL_ARRAY_TYPE_META);
1300*a0409676SBaptiste Daroussin 
1301*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1302*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
1303*a0409676SBaptiste Daroussin 
1304*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1305*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "tostring");
1306*a0409676SBaptiste Daroussin 
1307*a0409676SBaptiste Daroussin 	lua_pushstring (L, UCL_ARRAY_TYPE_META);
1308*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "class");
1309*a0409676SBaptiste Daroussin 
1310*a0409676SBaptiste Daroussin 	lua_pop (L, 1);
1311*a0409676SBaptiste Daroussin 
1312*a0409676SBaptiste Daroussin 	luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
1313*a0409676SBaptiste Daroussin 
1314*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1315*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
1316*a0409676SBaptiste Daroussin 
1317*a0409676SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_object_tostring);
1318*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "tostring");
1319*a0409676SBaptiste Daroussin 
1320*a0409676SBaptiste Daroussin 	lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META);
1321*a0409676SBaptiste Daroussin 	lua_setfield (L, -2, "class");
1322*a0409676SBaptiste Daroussin 
1323*a0409676SBaptiste Daroussin 	lua_pop (L, 1);
1324*a0409676SBaptiste Daroussin }
1325*a0409676SBaptiste Daroussin 
13264bf54857SBaptiste Daroussin static int
lua_ucl_to_json(lua_State * L)13274bf54857SBaptiste Daroussin lua_ucl_to_json (lua_State *L)
13284bf54857SBaptiste Daroussin {
13294bf54857SBaptiste Daroussin 	ucl_object_t *obj;
13304bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
13314bf54857SBaptiste Daroussin 
13324bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
13334bf54857SBaptiste Daroussin 		if (lua_toboolean (L, 2)) {
13344bf54857SBaptiste Daroussin 			format = UCL_EMIT_JSON_COMPACT;
13354bf54857SBaptiste Daroussin 		}
13364bf54857SBaptiste Daroussin 	}
13374bf54857SBaptiste Daroussin 
13384bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
13394bf54857SBaptiste Daroussin 	if (obj != NULL) {
13404bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
13414bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
13424bf54857SBaptiste Daroussin 	}
13434bf54857SBaptiste Daroussin 	else {
13444bf54857SBaptiste Daroussin 		lua_pushnil (L);
13454bf54857SBaptiste Daroussin 	}
13464bf54857SBaptiste Daroussin 
13474bf54857SBaptiste Daroussin 	return 1;
13484bf54857SBaptiste Daroussin }
13494bf54857SBaptiste Daroussin 
13504bf54857SBaptiste Daroussin static int
lua_ucl_to_config(lua_State * L)13514bf54857SBaptiste Daroussin lua_ucl_to_config (lua_State *L)
13524bf54857SBaptiste Daroussin {
13534bf54857SBaptiste Daroussin 	ucl_object_t *obj;
13544bf54857SBaptiste Daroussin 
13554bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
13564bf54857SBaptiste Daroussin 	if (obj != NULL) {
13574bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
13584bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
13594bf54857SBaptiste Daroussin 	}
13604bf54857SBaptiste Daroussin 	else {
13614bf54857SBaptiste Daroussin 		lua_pushnil (L);
13624bf54857SBaptiste Daroussin 	}
13634bf54857SBaptiste Daroussin 
13644bf54857SBaptiste Daroussin 	return 1;
13654bf54857SBaptiste Daroussin }
13664bf54857SBaptiste Daroussin 
13674bf54857SBaptiste Daroussin /***
13684bf54857SBaptiste Daroussin  * @function ucl.to_format(var, format)
13694bf54857SBaptiste Daroussin  * Converts lua variable `var` to the specified `format`. Formats supported are:
13704bf54857SBaptiste Daroussin  *
13714bf54857SBaptiste Daroussin  * - `json` - fine printed json
13724bf54857SBaptiste Daroussin  * - `json-compact` - compacted json
13734bf54857SBaptiste Daroussin  * - `config` - fine printed configuration
13744bf54857SBaptiste Daroussin  * - `ucl` - same as `config`
13754bf54857SBaptiste Daroussin  * - `yaml` - embedded yaml
13764bf54857SBaptiste Daroussin  *
13774bf54857SBaptiste Daroussin  * If `var` contains function, they are called during output formatting and if
1378*a0409676SBaptiste Daroussin  * they return string value, then this value is used for output.
13794bf54857SBaptiste Daroussin  * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
13804bf54857SBaptiste Daroussin  * @param {string} format any available format
13814bf54857SBaptiste Daroussin  * @return {string} string representation of `var` in the specific `format`.
13824bf54857SBaptiste Daroussin  * @example
13834bf54857SBaptiste Daroussin local table = {
13844bf54857SBaptiste Daroussin   str = 'value',
13854bf54857SBaptiste Daroussin   num = 100500,
13864bf54857SBaptiste Daroussin   null = ucl.null,
13874bf54857SBaptiste Daroussin   func = function ()
13884bf54857SBaptiste Daroussin     return 'huh'
13894bf54857SBaptiste Daroussin   end
13904bf54857SBaptiste Daroussin }
13914bf54857SBaptiste Daroussin 
13924bf54857SBaptiste Daroussin print(ucl.to_format(table, 'ucl'))
13934bf54857SBaptiste Daroussin -- Output:
13944bf54857SBaptiste Daroussin --[[
13954bf54857SBaptiste Daroussin num = 100500;
13964bf54857SBaptiste Daroussin str = "value";
13974bf54857SBaptiste Daroussin null = null;
13984bf54857SBaptiste Daroussin func = "huh";
13994bf54857SBaptiste Daroussin --]]
14004bf54857SBaptiste Daroussin  */
14014bf54857SBaptiste Daroussin static int
lua_ucl_to_format(lua_State * L)14024bf54857SBaptiste Daroussin lua_ucl_to_format (lua_State *L)
14034bf54857SBaptiste Daroussin {
14044bf54857SBaptiste Daroussin 	ucl_object_t *obj;
14054bf54857SBaptiste Daroussin 	int format = UCL_EMIT_JSON;
1406*a0409676SBaptiste Daroussin 	bool sort = false;
14074bf54857SBaptiste Daroussin 
14084bf54857SBaptiste Daroussin 	if (lua_gettop (L) > 1) {
14094bf54857SBaptiste Daroussin 		if (lua_type (L, 2) == LUA_TNUMBER) {
14104bf54857SBaptiste Daroussin 			format = lua_tonumber (L, 2);
14114bf54857SBaptiste Daroussin 			if (format < 0 || format >= UCL_EMIT_YAML) {
14124bf54857SBaptiste Daroussin 				lua_pushnil (L);
14134bf54857SBaptiste Daroussin 				return 1;
14144bf54857SBaptiste Daroussin 			}
14154bf54857SBaptiste Daroussin 		}
14164bf54857SBaptiste Daroussin 		else if (lua_type (L, 2) == LUA_TSTRING) {
14174bf54857SBaptiste Daroussin 			const char *strtype = lua_tostring (L, 2);
14184bf54857SBaptiste Daroussin 
14194bf54857SBaptiste Daroussin 			if (strcasecmp (strtype, "json") == 0) {
14204bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON;
14214bf54857SBaptiste Daroussin 			}
14224bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "json-compact") == 0) {
14234bf54857SBaptiste Daroussin 				format = UCL_EMIT_JSON_COMPACT;
14244bf54857SBaptiste Daroussin 			}
14254bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "yaml") == 0) {
14264bf54857SBaptiste Daroussin 				format = UCL_EMIT_YAML;
14274bf54857SBaptiste Daroussin 			}
14284bf54857SBaptiste Daroussin 			else if (strcasecmp (strtype, "config") == 0 ||
14294bf54857SBaptiste Daroussin 				strcasecmp (strtype, "ucl") == 0) {
14304bf54857SBaptiste Daroussin 				format = UCL_EMIT_CONFIG;
14314bf54857SBaptiste Daroussin 			}
143211dd9ed6SBaptiste Daroussin 			else if (strcasecmp (strtype, "msgpack") == 0) {
143311dd9ed6SBaptiste Daroussin 				format = UCL_EMIT_MSGPACK;
143411dd9ed6SBaptiste Daroussin 			}
14354bf54857SBaptiste Daroussin 		}
1436*a0409676SBaptiste Daroussin 
1437*a0409676SBaptiste Daroussin 		if (lua_isboolean (L, 3)) {
1438*a0409676SBaptiste Daroussin 			sort = lua_toboolean (L, 3);
1439*a0409676SBaptiste Daroussin 		}
14404bf54857SBaptiste Daroussin 	}
14414bf54857SBaptiste Daroussin 
14424bf54857SBaptiste Daroussin 	obj = ucl_object_lua_import (L, 1);
1443*a0409676SBaptiste Daroussin 
14444bf54857SBaptiste Daroussin 	if (obj != NULL) {
1445*a0409676SBaptiste Daroussin 
1446*a0409676SBaptiste Daroussin 		if (sort) {
1447*a0409676SBaptiste Daroussin 			if (ucl_object_type (obj) == UCL_OBJECT) {
1448*a0409676SBaptiste Daroussin 				ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE);
1449*a0409676SBaptiste Daroussin 			}
1450*a0409676SBaptiste Daroussin 		}
1451*a0409676SBaptiste Daroussin 
14524bf54857SBaptiste Daroussin 		lua_ucl_to_string (L, obj, format);
14534bf54857SBaptiste Daroussin 		ucl_object_unref (obj);
14544bf54857SBaptiste Daroussin 	}
14554bf54857SBaptiste Daroussin 	else {
14564bf54857SBaptiste Daroussin 		lua_pushnil (L);
14574bf54857SBaptiste Daroussin 	}
14584bf54857SBaptiste Daroussin 
14594bf54857SBaptiste Daroussin 	return 1;
14604bf54857SBaptiste Daroussin }
14614bf54857SBaptiste Daroussin 
14624bf54857SBaptiste Daroussin static int
lua_ucl_null_tostring(lua_State * L)14634bf54857SBaptiste Daroussin lua_ucl_null_tostring (lua_State* L)
14644bf54857SBaptiste Daroussin {
14654bf54857SBaptiste Daroussin 	lua_pushstring (L, "null");
14664bf54857SBaptiste Daroussin 	return 1;
14674bf54857SBaptiste Daroussin }
14684bf54857SBaptiste Daroussin 
14694bf54857SBaptiste Daroussin static void
lua_ucl_null_mt(lua_State * L)14704bf54857SBaptiste Daroussin lua_ucl_null_mt (lua_State *L)
14714bf54857SBaptiste Daroussin {
14724bf54857SBaptiste Daroussin 	luaL_newmetatable (L, NULL_META);
14734bf54857SBaptiste Daroussin 
14744bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_null_tostring);
14754bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__tostring");
14764bf54857SBaptiste Daroussin 
14774bf54857SBaptiste Daroussin 	lua_pop (L, 1);
14784bf54857SBaptiste Daroussin }
14794bf54857SBaptiste Daroussin 
14804bf54857SBaptiste Daroussin int
luaopen_ucl(lua_State * L)14814bf54857SBaptiste Daroussin luaopen_ucl (lua_State *L)
14824bf54857SBaptiste Daroussin {
14834bf54857SBaptiste Daroussin 	lua_ucl_parser_mt (L);
14844bf54857SBaptiste Daroussin 	lua_ucl_null_mt (L);
148539ee7a7aSBaptiste Daroussin 	lua_ucl_object_mt (L);
1486*a0409676SBaptiste Daroussin 	lua_ucl_types_mt (L);
14874bf54857SBaptiste Daroussin 
14884bf54857SBaptiste Daroussin 	/* Create the refs weak table: */
14894bf54857SBaptiste Daroussin 	lua_createtable (L, 0, 2);
14904bf54857SBaptiste Daroussin 	lua_pushliteral (L, "v"); /* tbl, "v" */
14914bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "__mode");
14924bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1); /* tbl, tbl */
14934bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2); /* tbl */
14944bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
14954bf54857SBaptiste Daroussin 
14964bf54857SBaptiste Daroussin 	lua_newtable (L);
14974bf54857SBaptiste Daroussin 
14984bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_parser_init);
14994bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "parser");
15004bf54857SBaptiste Daroussin 
15014bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_json);
15024bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_json");
15034bf54857SBaptiste Daroussin 
15044bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_config);
15054bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_config");
15064bf54857SBaptiste Daroussin 
15074bf54857SBaptiste Daroussin 	lua_pushcfunction (L, lua_ucl_to_format);
15084bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "to_format");
15094bf54857SBaptiste Daroussin 
15104bf54857SBaptiste Daroussin 	ucl_null = lua_newuserdata (L, 0);
15114bf54857SBaptiste Daroussin 	luaL_getmetatable (L, NULL_META);
15124bf54857SBaptiste Daroussin 	lua_setmetatable (L, -2);
15134bf54857SBaptiste Daroussin 
15144bf54857SBaptiste Daroussin 	lua_pushvalue (L, -1);
15154bf54857SBaptiste Daroussin 	lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
15164bf54857SBaptiste Daroussin 
15174bf54857SBaptiste Daroussin 	lua_setfield (L, -2, "null");
15184bf54857SBaptiste Daroussin 
15194bf54857SBaptiste Daroussin 	return 1;
15204bf54857SBaptiste Daroussin }
15214bf54857SBaptiste Daroussin 
15224bf54857SBaptiste Daroussin struct ucl_lua_funcdata*
ucl_object_toclosure(const ucl_object_t * obj)15234bf54857SBaptiste Daroussin ucl_object_toclosure (const ucl_object_t *obj)
15244bf54857SBaptiste Daroussin {
15254bf54857SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_USERDATA) {
15264bf54857SBaptiste Daroussin 		return NULL;
15274bf54857SBaptiste Daroussin 	}
15284bf54857SBaptiste Daroussin 
15294bf54857SBaptiste Daroussin 	return (struct ucl_lua_funcdata*)obj->value.ud;
15304bf54857SBaptiste Daroussin }
1531