aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-14 13:34:42 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-14 13:34:42 +0000
commitd212dc2bf89ec79a85fed3e368d171edd77aa7be (patch)
treede2ba2d1f0580fdf9313b7a00796357286e2a97f /contrib
parentb7420cb4cb0a2c9c96abc18ecd4de3c2bfec98d3 (diff)
downloadrspamd-d212dc2bf89ec79a85fed3e368d171edd77aa7be.tar.gz
rspamd-d212dc2bf89ec79a85fed3e368d171edd77aa7be.zip
Backport fixes from libucl
Diffstat (limited to 'contrib')
-rw-r--r--contrib/libucl/lua_ucl.c368
-rw-r--r--contrib/libucl/ucl.h17
-rw-r--r--contrib/libucl/ucl_msgpack.c34
-rw-r--r--contrib/libucl/ucl_parser.c2
-rw-r--r--contrib/libucl/ucl_util.c64
5 files changed, 443 insertions, 42 deletions
diff --git a/contrib/libucl/lua_ucl.c b/contrib/libucl/lua_ucl.c
index 1cb716b24..3c42adbfe 100644
--- a/contrib/libucl/lua_ucl.c
+++ b/contrib/libucl/lua_ucl.c
@@ -29,6 +29,7 @@
#include "ucl_internal.h"
#include "lua_ucl.h"
#include <strings.h>
+#include <zconf.h>
/***
* @module ucl
@@ -69,6 +70,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);
@@ -420,9 +422,7 @@ ucl_object_lua_fromelt (lua_State *L, int idx)
fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
- lua_ucl_userdata_emitter);
- obj->type = UCL_USERDATA;
- obj->value.ud = (void *)fd;
+ lua_ucl_userdata_emitter, (void *)fd);
}
}
}
@@ -461,6 +461,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;
@@ -489,6 +507,23 @@ 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));
+}
+
+static void
+lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
+{
+ ucl_object_t **pobj;
+
+ pobj = lua_newuserdata (L, sizeof (*pobj));
+ *pobj = obj;
+ luaL_getmetatable (L, OBJECT_META);
+ lua_setmetatable (L, -2);
+}
+
/***
* @method parser:parse_file(name)
* Parse UCL object from file.
@@ -594,6 +629,105 @@ 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;
+ int ret = 1;
+
+ parser = lua_ucl_parser_get (L, 1);
+ obj = ucl_parser_get_object (parser);
+
+ if (obj != NULL) {
+ lua_ucl_push_opaque (L, obj);
+ }
+ 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)
{
@@ -605,6 +739,189 @@ 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[, ext_refs]])
+ * 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, if `ext_refs` are also specified, then they are returned as opaque
+ * ucl object as {result,err,ext_refs}
+ */
+static int
+lua_ucl_object_validate (lua_State *L)
+{
+ ucl_object_t *obj, *schema, *ext_refs = NULL;
+ 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) {
+ if (lua_type (L, 3) == LUA_TSTRING) {
+ path = lua_tostring (L, 3);
+ if (path[0] == '#') {
+ path++;
+ }
+ }
+ else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) ==
+ LUA_TTABLE) {
+ /* External refs */
+ ext_refs = lua_ucl_object_get (L, 3);
+ }
+
+ if (lua_gettop (L) > 3) {
+ if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) ==
+ LUA_TTABLE) {
+ /* External refs */
+ ext_refs = lua_ucl_object_get (L, 4);
+ }
+ }
+ }
+
+ 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_root_ext (schema_elt, obj, schema,
+ ext_refs, &err);
+
+ if (res) {
+ lua_pushboolean (L, res);
+ lua_pushnil (L);
+
+ if (ext_refs) {
+ lua_ucl_push_opaque (L, ext_refs);
+ }
+ }
+ else {
+ lua_pushboolean (L, res);
+ lua_pushfstring (L, "validation error: %s", err.msg);
+
+ if (ext_refs) {
+ lua_ucl_push_opaque (L, ext_refs);
+ }
+ }
+ }
+ else {
+ lua_pushboolean (L, res);
+
+ lua_pushfstring (L, "cannot find the requested path: %s", path);
+
+ if (ext_refs) {
+ lua_ucl_push_opaque (L, ext_refs);
+ }
+ }
+ }
+ else {
+ lua_pushboolean (L, res);
+ lua_pushstring (L, "invalid object or schema");
+ }
+
+ if (ext_refs) {
+ return 3;
+ }
+
+ 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)
{
@@ -625,25 +942,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
@@ -789,6 +1126,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);
diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h
index 14e72d119..ba18380a9 100644
--- a/contrib/libucl/ucl.h
+++ b/contrib/libucl/ucl.h
@@ -288,10 +288,12 @@ UCL_EXTERN ucl_object_t* ucl_object_new_full (ucl_type_t type, unsigned priority
/**
* Create new object with userdata dtor
* @param dtor destructor function
+ * @param emitter emitter for userdata
+ * @param ptr opaque pointer
* @return new object
*/
UCL_EXTERN ucl_object_t* ucl_object_new_userdata (ucl_userdata_dtor dtor,
- ucl_userdata_emitter emitter) UCL_WARN_UNUSED_RESULT;
+ ucl_userdata_emitter emitter, void *ptr) UCL_WARN_UNUSED_RESULT;
/**
* Perform deep copy of an object copying everything
@@ -752,6 +754,19 @@ UCL_EXTERN int ucl_object_compare (const ucl_object_t *o1,
const ucl_object_t *o2);
/**
+ * Compare objects `o1` and `o2` useful for sorting
+ * @param o1 the first object
+ * @param o2 the second object
+ * @return values >0, 0 and <0 if `o1` is more than, equal and less than `o2`.
+ * The order of comparison:
+ * 1) Type of objects
+ * 2) Size of objects
+ * 3) Content of objects
+ */
+UCL_EXTERN int ucl_object_compare_qsort (const ucl_object_t **o1,
+ const ucl_object_t **o2);
+
+/**
* Sort UCL array using `cmp` compare function
* @param ar
* @param cmp
diff --git a/contrib/libucl/ucl_msgpack.c b/contrib/libucl/ucl_msgpack.c
index 5620a7b11..96f4809f8 100644
--- a/contrib/libucl/ucl_msgpack.c
+++ b/contrib/libucl/ucl_msgpack.c
@@ -113,19 +113,19 @@ ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, int64_t val)
len = 1;
buf[0] = mask_positive & val;
}
- else if (val <= 0xff) {
+ else if (val <= UINT8_MAX) {
len = 2;
buf[0] = uint8_ch;
buf[1] = val & 0xff;
}
- else if (val <= 0xffff) {
+ else if (val <= UINT16_MAX) {
uint16_t v = TO_BE16 (val);
len = 3;
buf[0] = uint16_ch;
memcpy (&buf[1], &v, sizeof (v));
}
- else if (val <= 0xffffffff) {
+ else if (val <= UINT32_MAX) {
uint32_t v = TO_BE32 (val);
len = 5;
@@ -149,19 +149,20 @@ ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, int64_t val)
len = 1;
buf[0] = (mask_negative | uval) & 0xff;
}
- else if (uval <= 0xff) {
+ else if (uval <= INT8_MAX) {
+ uint8_t v = (uint8_t)val;
len = 2;
buf[0] = int8_ch;
- buf[1] = (unsigned char)val;
+ buf[1] = v;
}
- else if (uval <= 0xffff) {
+ else if (uval <= INT16_MAX) {
uint16_t v = TO_BE16 (val);
len = 3;
buf[0] = int16_ch;
memcpy (&buf[1], &v, sizeof (v));
}
- else if (uval <= 0xffffffff) {
+ else if (uval <= INT32_MAX) {
uint32_t v = TO_BE32 (val);
len = 5;
@@ -1418,6 +1419,10 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
const unsigned char *pos, size_t remain)
{
ucl_object_t *obj;
+ int8_t iv8;
+ int16_t iv16;
+ int32_t iv32;
+ int64_t iv64;
if (len > remain) {
return -1;
@@ -1439,11 +1444,14 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
len = 1;
break;
case msgpack_int8:
- obj->value.iv = (signed char)*pos;
+ memcpy (&iv8, pos, sizeof (iv8));
+ obj->value.iv = iv8;
len = 1;
break;
case msgpack_int16:
- obj->value.iv = FROM_BE16 (*(int16_t *)pos);
+ memcpy (&iv16, pos, sizeof (iv16));
+ iv16 = FROM_BE16 (iv16);
+ obj->value.iv = iv16;
len = 2;
break;
case msgpack_uint16:
@@ -1451,7 +1459,9 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
len = 2;
break;
case msgpack_int32:
- obj->value.iv = FROM_BE32 (*(int32_t *)pos);
+ memcpy (&iv32, pos, sizeof (iv32));
+ iv32 = FROM_BE32 (iv32);
+ obj->value.iv = iv32;
len = 4;
break;
case msgpack_uint32:
@@ -1459,7 +1469,9 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
len = 4;
break;
case msgpack_int64:
- obj->value.iv = FROM_BE64 (*(int64_t *)pos);
+ memcpy (&iv64, pos, sizeof (iv64));
+ iv64 = FROM_BE64 (iv64);
+ obj->value.iv = iv64;
len = 8;
break;
case msgpack_uint64:
diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c
index fa906b7fe..9ac535cbe 100644
--- a/contrib/libucl/ucl_parser.c
+++ b/contrib/libucl/ucl_parser.c
@@ -2198,7 +2198,7 @@ ucl_state_machine (struct ucl_parser *parser)
while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
ucl_chunk_skipc (chunk, p);
}
- if (*p == '}') {
+ if (p == chunk->end || *p == '}') {
/* We have the end of an object */
parser->state = UCL_STATE_AFTER_VALUE;
continue;
diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c
index 15439feea..7626e0996 100644
--- a/contrib/libucl/ucl_util.c
+++ b/contrib/libucl/ucl_util.c
@@ -27,6 +27,7 @@
#include "ucl_chartable.h"
#include "kvec.h"
#include <stdarg.h>
+#include <stdio.h> /* for asprintf */
#ifndef _WIN32
#include <glob.h>
@@ -306,6 +307,9 @@ ucl_unescape_json_string (char *str, size_t len)
case 'u':
/* Unicode escape */
uval = 0;
+ h ++; /* u character */
+ len --;
+
if (len > 3) {
for (i = 0; i < 4; i++) {
uval <<= 4;
@@ -322,8 +326,7 @@ ucl_unescape_json_string (char *str, size_t len)
break;
}
}
- h += 3;
- len -= 3;
+
/* Encode */
if(uval < 0x80) {
t[0] = (char)uval;
@@ -340,6 +343,8 @@ ucl_unescape_json_string (char *str, size_t len)
t[2] = 0x80 + ((uval & 0x003F));
t += 3;
}
+#if 0
+ /* It's not actually supported now */
else if(uval <= 0x10FFFF) {
t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
t[1] = 0x80 + ((uval & 0x03F000) >> 12);
@@ -347,9 +352,19 @@ ucl_unescape_json_string (char *str, size_t len)
t[3] = 0x80 + ((uval & 0x00003F));
t += 4;
}
+#endif
else {
*t++ = '?';
}
+
+ /* Consume 4 characters of source */
+ h += 4;
+ len -= 4;
+
+ if (len > 0) {
+ len --; /* for '\' character */
+ }
+ continue;
}
else {
*t++ = 'u';
@@ -1550,7 +1565,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
size_t buflen;
unsigned priority;
int64_t iv;
- ucl_hash_t *container = NULL;
+ ucl_object_t *container = NULL;
enum ucl_string_flags flags;
/* Default values */
@@ -1610,19 +1625,32 @@ ucl_load_handler (const unsigned char *data, size_t len,
}
}
- if (prefix == NULL || strlen(prefix) == 0) {
+ if (prefix == NULL || strlen (prefix) == 0) {
ucl_create_err (&parser->err, "No Key specified in load macro");
return false;
}
if (len > 0) {
asprintf (&load_file, "%.*s", (int)len, data);
- if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, !try_load)) {
+
+ if (!load_file) {
+ ucl_create_err (&parser->err, "cannot allocate memory for suffix");
+
+ return false;
+ }
+
+ if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
+ !try_load)) {
+ free (load_file);
+
return (try_load || false);
}
- container = parser->stack->obj->value.ov;
- old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix)));
+ free (load_file);
+ container = parser->stack->obj;
+ old_obj = __DECONST (ucl_object_t *, ucl_object_find_key (container,
+ prefix));
+
if (old_obj != NULL) {
ucl_create_err (&parser->err, "Key %s already exists", prefix);
if (buflen > 0) {
@@ -1642,7 +1670,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
else if (strcasecmp (target, "int") == 0) {
asprintf(&tmp, "%.*s", (int)buflen, buf);
iv = strtoll(tmp, NULL, 10);
- obj = ucl_object_fromint(iv);
+ obj = ucl_object_fromint (iv);
}
if (buflen > 0) {
@@ -1652,13 +1680,11 @@ ucl_load_handler (const unsigned char *data, size_t len,
if (obj != NULL) {
obj->key = prefix;
obj->keylen = strlen (prefix);
- ucl_copy_key_trash(obj);
+ ucl_copy_key_trash (obj);
obj->prev = obj;
obj->next = NULL;
ucl_object_set_priority (obj, priority);
- container = ucl_hash_insert_object (container, obj,
- parser->flags & UCL_PARSER_KEY_LOWERCASE);
- parser->stack->obj->value.ov = container;
+ ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
}
return true;
@@ -2576,7 +2602,7 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
}
}
else {
- new = ucl_object_new_userdata (NULL, NULL);
+ new = ucl_object_new_userdata (NULL, NULL, NULL);
ucl_object_set_priority (new, priority);
}
@@ -2584,7 +2610,9 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
}
ucl_object_t*
-ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
+ucl_object_new_userdata (ucl_userdata_dtor dtor,
+ ucl_userdata_emitter emitter,
+ void *ptr)
{
struct ucl_object_userdata *new;
size_t nsize = sizeof (*new);
@@ -2598,6 +2626,7 @@ ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
new->obj.prev = (ucl_object_t *)new;
new->dtor = dtor;
new->emitter = emitter;
+ new->obj.value.ud = ptr;
}
return (ucl_object_t *)new;
@@ -3266,6 +3295,13 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
return ret;
}
+int
+ucl_object_compare_qsort (const ucl_object_t **o1,
+ const ucl_object_t **o2)
+{
+ return ucl_object_compare (*o1, *o2);
+}
+
void
ucl_object_array_sort (ucl_object_t *ar,
int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))