diff options
author | bapt <bapt@FreeBSD.org> | 2015-10-27 21:24:09 +0000 |
---|---|---|
committer | bapt <bapt@FreeBSD.org> | 2015-10-27 21:24:09 +0000 |
commit | 1db684f7ee1410ba0acf51937dc2748211c38efa (patch) | |
tree | 9b000a9777302debbb64fb5d2b8670bf0685b757 /contrib/libucl/lua/lua_ucl.c | |
parent | f4de602b0d1cd88f3d73de6148c83c4158e58a15 (diff) | |
parent | bf66c97c4a64e64410bf0223d221a54ca9555f52 (diff) | |
download | FreeBSD-src-1db684f7ee1410ba0acf51937dc2748211c38efa.zip FreeBSD-src-1db684f7ee1410ba0acf51937dc2748211c38efa.tar.gz |
Update libucl to latest git snapshot (20151027)
Diffstat (limited to 'contrib/libucl/lua/lua_ucl.c')
-rw-r--r-- | contrib/libucl/lua/lua_ucl.c | 360 |
1 files changed, 339 insertions, 21 deletions
diff --git a/contrib/libucl/lua/lua_ucl.c b/contrib/libucl/lua/lua_ucl.c index 682b0b5..b6162b4 100644 --- a/contrib/libucl/lua/lua_ucl.c +++ b/contrib/libucl/lua/lua_ucl.c @@ -69,6 +69,7 @@ func = "huh"; #define PARSER_META "ucl.parser.meta" #define EMITTER_META "ucl.emitter.meta" #define NULL_META "null.emitter.meta" +#define OBJECT_META "ucl.object.meta" static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj); static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array); @@ -172,19 +173,33 @@ static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj) { const ucl_object_t *cur; + ucl_object_iter_t it; int i = 1, nelt = 0; - /* Optimize allocation by preallocation of table */ - LL_FOREACH (obj, cur) { - nelt ++; + if (obj->type == UCL_ARRAY) { + nelt = obj->len; + it = ucl_object_iterate_new (obj); + lua_createtable (L, nelt, 0); + + while ((cur = ucl_object_iterate_safe (it, true))) { + ucl_object_push_lua (L, cur, false); + lua_rawseti (L, -2, i); + i ++; + } } + else { + /* Optimize allocation by preallocation of table */ + LL_FOREACH (obj, cur) { + nelt ++; + } - lua_createtable (L, nelt, 0); + lua_createtable (L, nelt, 0); - LL_FOREACH (obj, cur) { - ucl_object_push_lua (L, cur, false); - lua_rawseti (L, -2, i); - i ++; + LL_FOREACH (obj, cur) { + ucl_object_push_lua (L, cur, false); + lua_rawseti (L, -2, i); + i ++; + } } return 1; @@ -259,7 +274,7 @@ ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array) case UCL_OBJECT: return ucl_object_lua_push_object (L, obj, allow_array); case UCL_ARRAY: - return ucl_object_lua_push_array (L, obj->value.av); + return ucl_object_lua_push_array (L, obj); default: return ucl_object_lua_push_scalar (L, obj, allow_array); } @@ -322,6 +337,7 @@ ucl_object_lua_fromtable (lua_State *L, int idx) if (obj != NULL) { ucl_array_append (top, obj); } + lua_pop (L, 1); } } else { @@ -446,6 +462,24 @@ ucl_object_lua_import (lua_State *L, int idx) } static int +lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type) +{ + unsigned char *result; + + result = ucl_object_emit (obj, type); + + if (result != NULL) { + lua_pushstring (L, (const char *)result); + free (result); + } + else { + lua_pushnil (L); + } + + return 1; +} + +static int lua_ucl_parser_init (lua_State *L) { struct ucl_parser *parser, **pparser; @@ -474,6 +508,12 @@ lua_ucl_parser_get (lua_State *L, int index) return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META)); } +static ucl_object_t * +lua_ucl_object_get (lua_State *L, int index) +{ + return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META)); +} + /*** * @method parser:parse_file(name) * Parse UCL object from file. @@ -579,6 +619,108 @@ lua_ucl_parser_get_object (lua_State *L) return ret; } +/*** + * @method parser:get_object_wrapped() + * Get top object from parser and export it to userdata object without + * unwrapping to lua. + * @return {ucl.object or nil} ucl object wrapped variable + */ +static int +lua_ucl_parser_get_object_wrapped (lua_State *L) +{ + struct ucl_parser *parser; + ucl_object_t *obj, **pobj; + int ret = 1; + + parser = lua_ucl_parser_get (L, 1); + obj = ucl_parser_get_object (parser); + + if (obj != NULL) { + pobj = lua_newuserdata (L, sizeof (*pobj)); + *pobj = obj; + luaL_getmetatable (L, OBJECT_META); + lua_setmetatable (L, -2); + } + else { + lua_pushnil (L); + } + + return ret; +} + +/*** + * @method parser:validate(schema) + * Validates the top object in the parser against schema. Schema might be + * another object or a string that represents file to load schema from. + * + * @param {string/table} schema input schema + * @return {result,err} two values: boolean result and the corresponding error + * + */ +static int +lua_ucl_parser_validate (lua_State *L) +{ + struct ucl_parser *parser, *schema_parser; + ucl_object_t *schema; + const char *schema_file; + struct ucl_schema_error err; + + parser = lua_ucl_parser_get (L, 1); + + if (parser && parser->top_obj) { + if (lua_type (L, 2) == LUA_TTABLE) { + schema = ucl_object_lua_import (L, 2); + + if (schema == NULL) { + lua_pushboolean (L, false); + lua_pushstring (L, "cannot load schema from lua table"); + + return 2; + } + } + else if (lua_type (L, 2) == LUA_TSTRING) { + schema_parser = ucl_parser_new (0); + schema_file = luaL_checkstring (L, 2); + + if (!ucl_parser_add_file (schema_parser, schema_file)) { + lua_pushboolean (L, false); + lua_pushfstring (L, "cannot parse schema file \"%s\": " + "%s", schema_file, ucl_parser_get_error (parser)); + ucl_parser_free (schema_parser); + + return 2; + } + + schema = ucl_parser_get_object (schema_parser); + ucl_parser_free (schema_parser); + } + else { + lua_pushboolean (L, false); + lua_pushstring (L, "invalid schema argument"); + + return 2; + } + + if (!ucl_object_validate (schema, parser->top_obj, &err)) { + lua_pushboolean (L, false); + lua_pushfstring (L, "validation error: " + "%s", err.msg); + } + else { + lua_pushboolean (L, true); + lua_pushnil (L); + } + + ucl_object_unref (schema); + } + else { + lua_pushboolean (L, false); + lua_pushstring (L, "invalid parser or empty top object"); + } + + return 2; +} + static int lua_ucl_parser_gc (lua_State *L) { @@ -590,6 +732,161 @@ lua_ucl_parser_gc (lua_State *L) return 0; } +/*** + * @method object:unwrap() + * Unwraps opaque ucl object to the native lua object (performing copying) + * @return {variant} any lua object + */ +static int +lua_ucl_object_unwrap (lua_State *L) +{ + ucl_object_t *obj; + + obj = lua_ucl_object_get (L, 1); + + if (obj) { + ucl_object_push_lua (L, obj, true); + } + else { + lua_pushnil (L); + } + + return 1; +} + +/*** + * @method object:tostring(type) + * Unwraps opaque ucl object to string (json by default). Optionally you can + * specify output format: + * + * - `json` - fine printed json + * - `json-compact` - compacted json + * - `config` - fine printed configuration + * - `ucl` - same as `config` + * - `yaml` - embedded yaml + * @param {string} type optional + * @return {string} string representation of the opaque ucl object + */ +static int +lua_ucl_object_tostring (lua_State *L) +{ + ucl_object_t *obj; + enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; + + obj = lua_ucl_object_get (L, 1); + + if (obj) { + if (lua_gettop (L) > 1) { + if (lua_type (L, 2) == LUA_TSTRING) { + const char *strtype = lua_tostring (L, 2); + + if (strcasecmp (strtype, "json") == 0) { + format = UCL_EMIT_JSON; + } + else if (strcasecmp (strtype, "json-compact") == 0) { + format = UCL_EMIT_JSON_COMPACT; + } + else if (strcasecmp (strtype, "yaml") == 0) { + format = UCL_EMIT_YAML; + } + else if (strcasecmp (strtype, "config") == 0 || + strcasecmp (strtype, "ucl") == 0) { + format = UCL_EMIT_CONFIG; + } + } + } + + return lua_ucl_to_string (L, obj, format); + } + else { + lua_pushnil (L); + } + + return 1; +} + +/*** + * @method object:validate(schema, path) + * Validates the given ucl object using schema object represented as another + * opaque ucl object. You can also specify path in the form `#/path/def` to + * specify the specific schema element to perform validation. + * + * @param {ucl.object} schema schema object + * @param {string} path optional path for validation procedure + * @return {result,err} two values: boolean result and the corresponding error + */ +static int +lua_ucl_object_validate (lua_State *L) +{ + ucl_object_t *obj, *schema; + const ucl_object_t *schema_elt; + bool res = false; + struct ucl_schema_error err; + const char *path = NULL; + + obj = lua_ucl_object_get (L, 1); + schema = lua_ucl_object_get (L, 2); + + if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) { + if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TSTRING) { + path = lua_tostring (L, 3); + if (path[0] == '#') { + path ++; + } + } + + if (path) { + schema_elt = ucl_lookup_path_char (schema, path, '/'); + } + else { + /* Use the top object */ + schema_elt = schema; + } + + if (schema_elt) { + res = ucl_object_validate (schema_elt, obj, &err); + + if (res) { + lua_pushboolean (L, res); + lua_pushnil (L); + } + else { + lua_pushboolean (L, res); + lua_pushfstring (L, "validation error: %s", err.msg); + } + } + else { + lua_pushboolean (L, res); + + if (path) { + lua_pushfstring (L, "cannot find the requested path: %s", path); + } + else { + /* Should not be reached */ + lua_pushstring (L, "unknown error"); + } + } + } + else { + lua_pushboolean (L, res); + lua_pushstring (L, "invalid object or schema"); + } + + return 2; +} + +static int +lua_ucl_object_gc (lua_State *L) +{ + ucl_object_t *obj; + + obj = lua_ucl_object_get (L, 1); + + ucl_object_unref (obj); + + return 0; +} + static void lua_ucl_parser_mt (lua_State *L) { @@ -610,25 +907,45 @@ lua_ucl_parser_mt (lua_State *L) lua_pushcfunction (L, lua_ucl_parser_get_object); lua_setfield (L, -2, "get_object"); + lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped); + lua_setfield (L, -2, "get_object_wrapped"); + + lua_pushcfunction (L, lua_ucl_parser_validate); + lua_setfield (L, -2, "validate"); + lua_pop (L, 1); } -static int -lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type) +static void +lua_ucl_object_mt (lua_State *L) { - unsigned char *result; + luaL_newmetatable (L, OBJECT_META); - result = ucl_object_emit (obj, type); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); - if (result != NULL) { - lua_pushstring (L, (const char *)result); - free (result); - } - else { - lua_pushnil (L); - } + lua_pushcfunction (L, lua_ucl_object_gc); + lua_setfield (L, -2, "__gc"); - return 1; + lua_pushcfunction (L, lua_ucl_object_tostring); + lua_setfield (L, -2, "__tostring"); + + lua_pushcfunction (L, lua_ucl_object_tostring); + lua_setfield (L, -2, "tostring"); + + lua_pushcfunction (L, lua_ucl_object_unwrap); + lua_setfield (L, -2, "unwrap"); + + lua_pushcfunction (L, lua_ucl_object_unwrap); + lua_setfield (L, -2, "tolua"); + + lua_pushcfunction (L, lua_ucl_object_validate); + lua_setfield (L, -2, "validate"); + + lua_pushstring (L, OBJECT_META); + lua_setfield (L, -2, "class"); + + lua_pop (L, 1); } static int @@ -774,6 +1091,7 @@ luaopen_ucl (lua_State *L) { lua_ucl_parser_mt (L); lua_ucl_null_mt (L); + lua_ucl_object_mt (L); /* Create the refs weak table: */ lua_createtable (L, 0, 2); |