aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2016-04-17 21:25:53 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2016-04-17 21:25:53 +0000
commit94f2b741289f8532938513e8379d6eed5077b687 (patch)
treef8c605ecc03d848a1aff2296e3de9ba8aa8a5aff /src
parent4e2fa78ea36ec2cf6583bc025b4127c5ea238fd2 (diff)
downloadsrc-94f2b741289f8532938513e8379d6eed5077b687.tar.gz
src-94f2b741289f8532938513e8379d6eed5077b687.zip
Import libucl 0.8.0vendor/libucl/libucl-0.8.0
Notes
Notes: svn path=/vendor/libucl/dist/; revision=298162 svn path=/vendor/libucl/libucl-0.8.0/; revision=298163; tag=vendor/libucl/libucl-0.8.0
Diffstat (limited to 'src')
-rw-r--r--src/ucl_emitter.c47
-rw-r--r--src/ucl_emitter_streamline.c10
-rw-r--r--src/ucl_hash.c6
-rw-r--r--src/ucl_hash.h6
-rw-r--r--src/ucl_internal.h30
-rw-r--r--src/ucl_msgpack.c40
-rw-r--r--src/ucl_parser.c354
-rw-r--r--src/ucl_schema.c360
-rw-r--r--src/ucl_sexp.c4
-rw-r--r--src/ucl_util.c377
10 files changed, 927 insertions, 307 deletions
diff --git a/src/ucl_emitter.c b/src/ucl_emitter.c
index 8bfbf09b8bd7..a15cd08cfb98 100644
--- a/src/ucl_emitter.c
+++ b/src/ucl_emitter.c
@@ -268,7 +268,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
if (obj->type == UCL_ARRAY) {
/* explicit array */
- while ((cur = ucl_iterate_object (obj, &iter, true)) != NULL) {
+ while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) {
ucl_emitter_common_elt (ctx, cur, first, false, compact);
first = false;
}
@@ -362,6 +362,7 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
const struct ucl_emitter_functions *func = ctx->func;
bool flag;
struct ucl_object_userdata *ud;
+ const ucl_object_t *comment = NULL, *cur_comment;
const char *ud_out = "";
if (ctx->id != UCL_EMIT_CONFIG && !first) {
@@ -379,6 +380,25 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_add_tabs (func, ctx->indent, compact);
+ if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
+ comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj,
+ sizeof (void *));
+
+ if (comment) {
+ if (!(comment->flags & UCL_OBJECT_INHERITED)) {
+ DL_FOREACH (comment, cur_comment) {
+ func->ucl_emitter_append_len (cur_comment->value.sv,
+ cur_comment->len,
+ func->ud);
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
+ ucl_add_tabs (func, ctx->indent, compact);
+ }
+
+ comment = NULL;
+ }
+ }
+ }
+
switch (obj->type) {
case UCL_INT:
ucl_emitter_print_key (print_key, ctx, obj, compact);
@@ -438,6 +458,19 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
break;
}
+
+ if (comment) {
+ DL_FOREACH (comment, cur_comment) {
+ func->ucl_emitter_append_len (cur_comment->value.sv,
+ cur_comment->len,
+ func->ud);
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
+
+ if (cur_comment->next) {
+ ucl_add_tabs (func, ctx->indent, compact);
+ }
+ }
+ }
}
/*
@@ -518,7 +551,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
ucl_emit_msgpack_start_obj (ctx, obj, print_key);
it = NULL;
- while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
+ while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
LL_FOREACH (cur, celt) {
ucl_emit_msgpack_elt (ctx, celt, false, true);
/* XXX:
@@ -537,7 +570,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
ucl_emit_msgpack_start_array (ctx, obj, print_key);
it = NULL;
- while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
+ while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
ucl_emit_msgpack_elt (ctx, cur, false, false);
}
@@ -605,10 +638,10 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
}
func = ucl_object_emit_memory_funcs ((void **)&res);
- s = func->ud;
if (func != NULL) {
- ucl_object_emit_full (obj, emit_type, func);
+ s = func->ud;
+ ucl_object_emit_full (obj, emit_type, func, NULL);
if (outlen != NULL) {
*outlen = s->i;
@@ -622,7 +655,8 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
bool
ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
- struct ucl_emitter_functions *emitter)
+ struct ucl_emitter_functions *emitter,
+ const ucl_object_t *comments)
{
const struct ucl_emitter_context *ctx;
struct ucl_emitter_context my_ctx;
@@ -634,6 +668,7 @@ ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
my_ctx.func = emitter;
my_ctx.indent = 0;
my_ctx.top = obj;
+ my_ctx.comments = comments;
my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
res = true;
diff --git a/src/ucl_emitter_streamline.c b/src/ucl_emitter_streamline.c
index ff27c88244a5..a7178c5d74b0 100644
--- a/src/ucl_emitter_streamline.c
+++ b/src/ucl_emitter_streamline.c
@@ -38,12 +38,20 @@ struct ucl_emitter_streamline_stack {
struct ucl_emitter_context_streamline {
/* Inherited from the main context */
+ /** Name of emitter (e.g. json, compact_json) */
const char *name;
+ /** Unique id (e.g. UCL_EMIT_JSON for standard emitters */
int id;
+ /** A set of output functions */
const struct ucl_emitter_functions *func;
+ /** A set of output operations */
const struct ucl_emitter_operations *ops;
- unsigned int ident;
+ /** Current amount of indent tabs */
+ unsigned int indent;
+ /** Top level object */
const ucl_object_t *top;
+ /** Optional comments */
+ const ucl_object_t *comments;
/* Streamline specific fields */
struct ucl_emitter_streamline_stack *containers;
diff --git a/src/ucl_hash.c b/src/ucl_hash.c
index 7de8196fa014..c54fba7c90a5 100644
--- a/src/ucl_hash.c
+++ b/src/ucl_hash.c
@@ -117,7 +117,7 @@ static inline int
ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)
{
if (k1->keylen == k2->keylen) {
- return strncmp (k1->key, k2->key, k1->keylen) == 0;
+ return memcmp (k1->key, k2->key, k1->keylen) == 0;
}
return 0;
@@ -216,7 +216,7 @@ static inline int
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
{
if (k1->keylen == k2->keylen) {
- return strncasecmp (k1->key, k2->key, k1->keylen) == 0;
+ return memcmp (k1->key, k2->key, k1->keylen) == 0;
}
return 0;
@@ -247,7 +247,7 @@ ucl_hash_create (bool ignore_case)
return new;
}
-void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
+void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
{
const ucl_object_t *cur, *tmp;
diff --git a/src/ucl_hash.h b/src/ucl_hash.h
index 64c83eac8bc1..92021e34075e 100644
--- a/src/ucl_hash.h
+++ b/src/ucl_hash.h
@@ -31,8 +31,8 @@
struct ucl_hash_node_s;
typedef struct ucl_hash_node_s ucl_hash_node_t;
-typedef int ucl_hash_cmp_func (const void* void_a, const void* void_b);
-typedef void ucl_hash_free_func (void *ptr);
+typedef int (*ucl_hash_cmp_func) (const void* void_a, const void* void_b);
+typedef void (*ucl_hash_free_func) (void *ptr);
typedef void* ucl_hash_iter_t;
@@ -51,7 +51,7 @@ ucl_hash_t* ucl_hash_create (bool ignore_case);
/**
* Deinitializes the hashtable.
*/
-void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
+void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func);
/**
* Inserts an element in the the hashtable.
diff --git a/src/ucl_internal.h b/src/ucl_internal.h
index 31d6b1361383..db8a12c408b1 100644
--- a/src/ucl_internal.h
+++ b/src/ucl_internal.h
@@ -211,6 +211,8 @@ struct ucl_parser {
struct ucl_variable *variables;
ucl_variable_handler var_handler;
void *var_data;
+ ucl_object_t *comments;
+ ucl_object_t *last_comment;
UT_string *err;
};
@@ -524,6 +526,34 @@ void ucl_emitter_print_key_msgpack (bool print_key,
const ucl_object_t *obj);
/**
+ * Fetch URL into a buffer
+ * @param url url to fetch
+ * @param buf pointer to buffer (must be freed by callee)
+ * @param buflen pointer to buffer length
+ * @param err pointer to error argument
+ * @param must_exist fail if cannot find a url
+ */
+bool ucl_fetch_url (const unsigned char *url,
+ unsigned char **buf,
+ size_t *buflen,
+ UT_string **err,
+ bool must_exist);
+
+/**
+ * Fetch a file and save results to the memory buffer
+ * @param filename filename to fetch
+ * @param len length of filename
+ * @param buf target buffer
+ * @param buflen target length
+ * @return
+ */
+bool ucl_fetch_file (const unsigned char *filename,
+ unsigned char **buf,
+ size_t *buflen,
+ UT_string **err,
+ bool must_exist);
+
+/**
* Add new element to an object using the current merge strategy and priority
* @param parser
* @param nobj
diff --git a/src/ucl_msgpack.c b/src/ucl_msgpack.c
index e8ebfba8a35e..96f4809f892f 100644
--- a/src/ucl_msgpack.c
+++ b/src/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;
@@ -750,7 +751,7 @@ ucl_msgpack_get_parser_from_type (unsigned char t)
shift = CHAR_BIT - parsers[i].prefixlen;
mask = parsers[i].prefix >> shift;
- if (mask == (t >> shift)) {
+ if (mask == (((unsigned int)t) >> shift)) {
return &parsers[i];
}
}
@@ -969,8 +970,8 @@ ucl_msgpack_consume (struct ucl_parser *parser)
finish_array_value,
error_state
} state = read_type, next_state = error_state;
- struct ucl_msgpack_parser *obj_parser;
- uint64_t len;
+ struct ucl_msgpack_parser *obj_parser = NULL;
+ uint64_t len = 0;
ssize_t ret, remain, keylen = 0;
#ifdef MSGPACK_DEBUG_PARSER
uint64_t i;
@@ -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/src/ucl_parser.c b/src/ucl_parser.c
index 9bd41391ba36..0aaa4dd988db 100644
--- a/src/ucl_parser.c
+++ b/src/ucl_parser.c
@@ -89,6 +89,39 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
parser->err_code = code;
}
+static void
+ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
+{
+ ucl_object_t *nobj;
+
+ if (len > 0 && begin != NULL) {
+ nobj = ucl_object_fromstring_common (begin, len, 0);
+
+ if (parser->last_comment) {
+ /* We need to append data to an existing object */
+ DL_APPEND (parser->last_comment, nobj);
+ }
+ else {
+ parser->last_comment = nobj;
+ }
+ }
+}
+
+static void
+ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
+{
+ if (parser->last_comment) {
+ ucl_object_insert_key (parser->comments, parser->last_comment,
+ (const char *)&obj, sizeof (void *), true);
+
+ if (before) {
+ parser->last_comment->flags |= UCL_OBJECT_INHERITED;
+ }
+
+ parser->last_comment = NULL;
+ }
+}
+
/**
* Skip all comments from the current pos resolving nested and multiline comments
* @param parser
@@ -98,7 +131,7 @@ static bool
ucl_skip_comments (struct ucl_parser *parser)
{
struct ucl_chunk *chunk = parser->chunks;
- const unsigned char *p;
+ const unsigned char *p, *beg = NULL;
int comments_nested = 0;
bool quoted = false;
@@ -108,9 +141,17 @@ start:
if (chunk->remain > 0 && *p == '#') {
if (parser->state != UCL_STATE_SCOMMENT &&
parser->state != UCL_STATE_MCOMMENT) {
+ beg = p;
+
while (p < chunk->end) {
if (*p == '\n') {
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, beg, p - beg);
+ beg = NULL;
+ }
+
ucl_chunk_skipc (chunk, p);
+
goto start;
}
ucl_chunk_skipc (chunk, p);
@@ -119,6 +160,7 @@ start:
}
else if (chunk->remain >= 2 && *p == '/') {
if (p[1] == '*') {
+ beg = p;
ucl_chunk_skipc (chunk, p);
comments_nested ++;
ucl_chunk_skipc (chunk, p);
@@ -134,6 +176,11 @@ start:
if (*p == '/') {
comments_nested --;
if (comments_nested == 0) {
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, beg, p - beg + 1);
+ beg = NULL;
+ }
+
ucl_chunk_skipc (chunk, p);
goto start;
}
@@ -147,6 +194,7 @@ start:
continue;
}
}
+
ucl_chunk_skipc (chunk, p);
}
if (comments_nested != 0) {
@@ -157,6 +205,10 @@ start:
}
}
+ if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
+ ucl_save_comment (parser, beg, p - beg);
+ }
+
return true;
}
@@ -207,7 +259,7 @@ ucl_lex_time_multiplier (const unsigned char c) {
{'h', 60 * 60},
{'d', 60 * 60 * 24},
{'w', 60 * 60 * 24 * 7},
- {'y', 60 * 60 * 24 * 7 * 365}
+ {'y', 60 * 60 * 24 * 365}
};
int i;
@@ -451,6 +503,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
size_t out_len = 0;
bool vars_found = false;
+ if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+ *dst = NULL;
+ return in_len;
+ }
+
p = src;
while (p != end) {
if (*p == '$') {
@@ -590,12 +647,14 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
}
st = UCL_ALLOC (sizeof (struct ucl_stack));
+
if (st == NULL) {
ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
&parser->err);
ucl_object_unref (obj);
return NULL;
}
+
st->obj = obj;
st->level = level;
LL_PREPEND (parser->stack, st);
@@ -1009,6 +1068,7 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
{
ucl_hash_t *container;
ucl_object_t *tobj;
+ char errmsg[256];
container = parser->stack->obj->value.ov;
@@ -1067,31 +1127,43 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
break;
case UCL_DUPLICATE_ERROR:
- ucl_create_err (&parser->err, "error while parsing %s: "
- "line: %d, column: %d: duplicate element for key '%s' "
- "has been found",
- parser->cur_file ? parser->cur_file : "<unknown>",
- parser->chunks->line, parser->chunks->column, nobj->key);
+ snprintf(errmsg, sizeof(errmsg),
+ "duplicate element for key '%s' found",
+ nobj->key);
+ ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
return false;
case UCL_DUPLICATE_MERGE:
/*
* Here we do have some old object so we just push it on top of objects stack
+ * Check priority and then perform the merge on the remaining objects
*/
if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
ucl_object_unref (nobj);
nobj = tobj;
}
- else {
- /* For other types we create implicit array as usual */
+ else if (priold == prinew) {
ucl_parser_append_elt (parser, container, tobj, nobj);
}
+ else if (priold > prinew) {
+ /*
+ * We add this new object to a list of trash objects just to ensure
+ * that it won't come to any real object
+ * XXX: rather inefficient approach
+ */
+ DL_APPEND (parser->trash_objs, nobj);
+ }
+ else {
+ ucl_hash_replace (container, tobj, nobj);
+ ucl_object_unref (tobj);
+ }
break;
}
}
parser->stack->obj->value.ov = container;
parser->cur_obj = nobj;
+ ucl_attach_comment (parser, nobj, false);
return true;
}
@@ -1120,7 +1192,10 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
if (*p == '.') {
/* It is macro actually */
- ucl_chunk_skipc (chunk, p);
+ if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
+ ucl_chunk_skipc (chunk, p);
+ }
+
parser->prev_state = parser->state;
parser->state = UCL_STATE_MACRO_NAME;
*end_of_object = false;
@@ -1461,6 +1536,7 @@ ucl_parser_get_container (struct ucl_parser *parser)
}
parser->cur_obj = obj;
+ ucl_attach_comment (parser, obj, false);
}
else {
/* Object has been already allocated */
@@ -1511,6 +1587,10 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
}
obj = ucl_parser_get_container (parser);
+ if (!obj) {
+ return false;
+ }
+
str_len = chunk->pos - c - 2;
obj->type = UCL_STRING;
if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
@@ -1707,12 +1787,19 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
parser->stack = st->next;
UCL_FREE (sizeof (struct ucl_stack), st);
+ if (parser->cur_obj) {
+ ucl_attach_comment (parser, parser->cur_obj, true);
+ }
+
while (parser->stack != NULL) {
st = parser->stack;
+
if (st->next == NULL || st->next->level == st->level) {
break;
}
+
parser->stack = st->next;
+ parser->cur_obj = st->obj;
UCL_FREE (sizeof (struct ucl_stack), st);
}
}
@@ -1752,6 +1839,109 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
return true;
}
+static bool
+ucl_skip_macro_as_comment (struct ucl_parser *parser,
+ struct ucl_chunk *chunk)
+{
+ const unsigned char *p, *c;
+ enum {
+ macro_skip_start = 0,
+ macro_has_symbols,
+ macro_has_obrace,
+ macro_has_quote,
+ macro_has_backslash,
+ macro_has_sqbrace,
+ macro_save
+ } state = macro_skip_start, prev_state = macro_skip_start;
+
+ p = chunk->pos;
+ c = chunk->pos;
+
+ while (p < chunk->end) {
+ switch (state) {
+ case macro_skip_start:
+ if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+ state = macro_has_symbols;
+ }
+ else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+ state = macro_save;
+ continue;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_symbols:
+ if (*p == '{') {
+ state = macro_has_sqbrace;
+ }
+ else if (*p == '(') {
+ state = macro_has_obrace;
+ }
+ else if (*p == '"') {
+ state = macro_has_quote;
+ }
+ else if (*p == '\n') {
+ state = macro_save;
+ continue;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_obrace:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == ')') {
+ state = macro_has_symbols;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_sqbrace:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == '}') {
+ state = macro_save;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_quote:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == '"') {
+ state = macro_save;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_backslash:
+ state = prev_state;
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_save:
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, c, p - c);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* Handle macro data
* @param parser
@@ -2024,7 +2214,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;
@@ -2067,7 +2257,7 @@ ucl_state_machine (struct ucl_parser *parser)
break;
case UCL_STATE_VALUE:
/* We need to check what we do have */
- if (!ucl_parse_value (parser, chunk)) {
+ if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
return false;
@@ -2095,42 +2285,60 @@ ucl_state_machine (struct ucl_parser *parser)
/* Skip everything at the end */
return true;
}
+
p = chunk->pos;
break;
case UCL_STATE_MACRO_NAME:
- if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
- *p != '(') {
- ucl_chunk_skipc (chunk, p);
+ if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+ if (!ucl_skip_macro_as_comment (parser, chunk)) {
+ /* We have invalid macro */
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: invalid macro",
+ chunk->line,
+ chunk->column);
+ parser->state = UCL_STATE_ERROR;
+ return false;
+ }
+ else {
+ p = chunk->pos;
+ parser->state = parser->prev_state;
+ }
}
else {
- if (p - c > 0) {
- /* We got macro name */
- macro_len = (size_t) (p - c);
- HASH_FIND (hh, parser->macroes, c, macro_len, macro);
- if (macro == NULL) {
+ if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
+ *p != '(') {
+ ucl_chunk_skipc (chunk, p);
+ }
+ else {
+ if (c != NULL && p - c > 0) {
+ /* We got macro name */
+ macro_len = (size_t) (p - c);
+ HASH_FIND (hh, parser->macroes, c, macro_len, macro);
+ if (macro == NULL) {
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: "
+ "unknown macro: '%.*s', character: '%c'",
+ chunk->line,
+ chunk->column,
+ (int) (p - c),
+ c,
+ *chunk->pos);
+ parser->state = UCL_STATE_ERROR;
+ return false;
+ }
+ /* Now we need to skip all spaces */
+ SKIP_SPACES_COMMENTS(parser, chunk, p);
+ parser->state = UCL_STATE_MACRO;
+ }
+ else {
+ /* We have invalid macro name */
ucl_create_err (&parser->err,
- "error on line %d at column %d: "
- "unknown macro: '%.*s', character: '%c'",
+ "error on line %d at column %d: invalid macro name",
chunk->line,
- chunk->column,
- (int) (p - c),
- c,
- *chunk->pos);
+ chunk->column);
parser->state = UCL_STATE_ERROR;
return false;
}
- /* Now we need to skip all spaces */
- SKIP_SPACES_COMMENTS(parser, chunk, p);
- parser->state = UCL_STATE_MACRO;
- }
- else {
- /* We have invalid macro name */
- ucl_create_err (&parser->err,
- "error on line %d at column %d: invalid macro name",
- chunk->line,
- chunk->column);
- parser->state = UCL_STATE_ERROR;
- return false;
}
}
break;
@@ -2154,7 +2362,8 @@ ucl_state_machine (struct ucl_parser *parser)
macro_len = ucl_expand_variable (parser, &macro_escaped,
macro_start, macro_len);
parser->state = parser->prev_state;
- if (macro_escaped == NULL) {
+
+ if (macro_escaped == NULL && macro != NULL) {
if (macro->is_context) {
ret = macro->h.context_handler (macro_start, macro_len,
macro_args,
@@ -2166,7 +2375,7 @@ ucl_state_machine (struct ucl_parser *parser)
macro->ud);
}
}
- else {
+ else if (macro != NULL) {
if (macro->is_context) {
ret = macro->h.context_handler (macro_escaped, macro_len,
macro_args,
@@ -2180,21 +2389,27 @@ ucl_state_machine (struct ucl_parser *parser)
UCL_FREE (macro_len + 1, macro_escaped);
}
+ else {
+ ret = false;
+ ucl_set_err (parser, UCL_EINTERNAL,
+ "internal error: parser has macro undefined", &parser->err);
+ }
/*
* Chunk can be modified within macro handler
*/
chunk = parser->chunks;
p = chunk->pos;
+
if (macro_args) {
ucl_object_unref (macro_args);
}
+
if (!ret) {
return false;
}
break;
default:
- /* TODO: add all states */
ucl_set_err (parser, UCL_EINTERNAL,
"internal error: parser is in an unknown state", &parser->err);
parser->state = UCL_STATE_ERROR;
@@ -2202,35 +2417,54 @@ ucl_state_machine (struct ucl_parser *parser)
}
}
+ if (parser->last_comment) {
+ if (parser->cur_obj) {
+ ucl_attach_comment (parser, parser->cur_obj, true);
+ }
+ else if (parser->stack && parser->stack->obj) {
+ ucl_attach_comment (parser, parser->stack->obj, true);
+ }
+ else if (parser->top_obj) {
+ ucl_attach_comment (parser, parser->top_obj, true);
+ }
+ else {
+ ucl_object_unref (parser->last_comment);
+ }
+ }
+
return true;
}
struct ucl_parser*
ucl_parser_new (int flags)
{
- struct ucl_parser *new;
+ struct ucl_parser *parser;
- new = UCL_ALLOC (sizeof (struct ucl_parser));
- if (new == NULL) {
+ parser = UCL_ALLOC (sizeof (struct ucl_parser));
+ if (parser == NULL) {
return NULL;
}
- memset (new, 0, sizeof (struct ucl_parser));
+ memset (parser, 0, sizeof (struct ucl_parser));
- ucl_parser_register_macro (new, "include", ucl_include_handler, new);
- ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
- ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
- ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
- ucl_parser_register_macro (new, "load", ucl_load_handler, new);
- ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
+ ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
+ ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
+ ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
+ ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
+ ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
+ ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
- new->flags = flags;
- new->includepaths = NULL;
+ parser->flags = flags;
+ parser->includepaths = NULL;
+
+ if (flags & UCL_PARSER_SAVE_COMMENTS) {
+ parser->comments = ucl_object_typed_new (UCL_OBJECT);
+ }
/* Initial assumption about filevars */
- ucl_parser_set_filevars (new, NULL, false);
+ ucl_parser_set_filevars (parser, NULL, false);
- return new;
+ return parser;
}
bool
@@ -2363,14 +2597,16 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
return false;
}
- if (data == NULL) {
- ucl_create_err (&parser->err, "invalid chunk added");
- return false;
- }
if (len == 0) {
parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
return true;
}
+
+ if (data == NULL) {
+ ucl_create_err (&parser->err, "invalid chunk added");
+ return false;
+ }
+
if (parser->state != UCL_STATE_ERROR) {
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
if (chunk == NULL) {
diff --git a/src/ucl_schema.c b/src/ucl_schema.c
index 834b62accb5f..4d7c871ff9f8 100644
--- a/src/ucl_schema.c
+++ b/src/ucl_schema.c
@@ -43,72 +43,8 @@
static bool ucl_schema_validate (const ucl_object_t *schema,
const ucl_object_t *obj, bool try_array,
struct ucl_schema_error *err,
- const ucl_object_t *root);
-
-static bool
-ucl_string_to_type (const char *input, ucl_type_t *res)
-{
- if (strcasecmp (input, "object") == 0) {
- *res = UCL_OBJECT;
- }
- else if (strcasecmp (input, "array") == 0) {
- *res = UCL_ARRAY;
- }
- else if (strcasecmp (input, "integer") == 0) {
- *res = UCL_INT;
- }
- else if (strcasecmp (input, "number") == 0) {
- *res = UCL_FLOAT;
- }
- else if (strcasecmp (input, "string") == 0) {
- *res = UCL_STRING;
- }
- else if (strcasecmp (input, "boolean") == 0) {
- *res = UCL_BOOLEAN;
- }
- else if (strcasecmp (input, "null") == 0) {
- *res = UCL_NULL;
- }
- else {
- return false;
- }
-
- return true;
-}
-
-static const char *
-ucl_object_type_to_string (ucl_type_t type)
-{
- const char *res = "unknown";
-
- switch (type) {
- case UCL_OBJECT:
- res = "object";
- break;
- case UCL_ARRAY:
- res = "array";
- break;
- case UCL_INT:
- res = "integer";
- break;
- case UCL_FLOAT:
- case UCL_TIME:
- res = "number";
- break;
- case UCL_STRING:
- res = "string";
- break;
- case UCL_BOOLEAN:
- res = "boolean";
- break;
- case UCL_NULL:
- case UCL_USERDATA:
- res = "null";
- break;
- }
-
- return res;
-}
+ const ucl_object_t *root,
+ ucl_object_t *ext_ref);
/*
* Create validation error
@@ -142,7 +78,7 @@ ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern)
ucl_object_iter_t iter = NULL;
if (regcomp (&reg, pattern, REG_EXTENDED | REG_NOSUB) == 0) {
- while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
+ while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
if (regexec (&reg, ucl_object_key (elt), 0, NULL, 0) == 0) {
res = elt;
break;
@@ -160,20 +96,21 @@ ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern)
static bool
ucl_schema_validate_dependencies (const ucl_object_t *deps,
const ucl_object_t *obj, struct ucl_schema_error *err,
- const ucl_object_t *root)
+ const ucl_object_t *root,
+ ucl_object_t *ext_ref)
{
const ucl_object_t *elt, *cur, *cur_dep;
ucl_object_iter_t iter = NULL, piter;
bool ret = true;
- while (ret && (cur = ucl_iterate_object (deps, &iter, true)) != NULL) {
- elt = ucl_object_find_key (obj, ucl_object_key (cur));
+ while (ret && (cur = ucl_object_iterate (deps, &iter, true)) != NULL) {
+ elt = ucl_object_lookup (obj, ucl_object_key (cur));
if (elt != NULL) {
/* Need to check dependencies */
if (cur->type == UCL_ARRAY) {
piter = NULL;
- while (ret && (cur_dep = ucl_iterate_object (cur, &piter, true)) != NULL) {
- if (ucl_object_find_key (obj, ucl_object_tostring (cur_dep)) == NULL) {
+ while (ret && (cur_dep = ucl_object_iterate (cur, &piter, true)) != NULL) {
+ if (ucl_object_lookup (obj, ucl_object_tostring (cur_dep)) == NULL) {
ucl_schema_create_error (err, UCL_SCHEMA_MISSING_DEPENDENCY, elt,
"dependency %s is missing for key %s",
ucl_object_tostring (cur_dep), ucl_object_key (cur));
@@ -183,7 +120,7 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
}
}
else if (cur->type == UCL_OBJECT) {
- ret = ucl_schema_validate (cur, obj, true, err, root);
+ ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
}
}
}
@@ -197,7 +134,8 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
static bool
ucl_schema_validate_object (const ucl_object_t *schema,
const ucl_object_t *obj, struct ucl_schema_error *err,
- const ucl_object_t *root)
+ const ucl_object_t *root,
+ ucl_object_t *ext_ref)
{
const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
*required = NULL, *pat, *pelt;
@@ -205,14 +143,15 @@ ucl_schema_validate_object (const ucl_object_t *schema,
bool ret = true, allow_additional = true;
int64_t minmax;
- while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
+ while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
if (elt->type == UCL_OBJECT &&
strcmp (ucl_object_key (elt), "properties") == 0) {
piter = NULL;
- while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
- found = ucl_object_find_key (obj, ucl_object_key (prop));
+ while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
+ found = ucl_object_lookup (obj, ucl_object_key (prop));
if (found) {
- ret = ucl_schema_validate (prop, found, true, err, root);
+ ret = ucl_schema_validate (prop, found, true, err, root,
+ ext_ref);
}
}
}
@@ -267,16 +206,18 @@ ucl_schema_validate_object (const ucl_object_t *schema,
}
else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) {
piter = NULL;
- while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
+ while (ret && (prop = ucl_object_iterate (elt, &piter, true)) != NULL) {
found = ucl_schema_test_pattern (obj, ucl_object_key (prop));
if (found) {
- ret = ucl_schema_validate (prop, found, true, err, root);
+ ret = ucl_schema_validate (prop, found, true, err, root,
+ ext_ref);
}
}
}
else if (elt->type == UCL_OBJECT &&
strcmp (ucl_object_key (elt), "dependencies") == 0) {
- ret = ucl_schema_validate_dependencies (elt, obj, err, root);
+ ret = ucl_schema_validate_dependencies (elt, obj, err, root,
+ ext_ref);
}
}
@@ -285,14 +226,14 @@ ucl_schema_validate_object (const ucl_object_t *schema,
if (!allow_additional || additional_schema != NULL) {
/* Check if we have exactly the same properties in schema and object */
iter = NULL;
- prop = ucl_object_find_key (schema, "properties");
- while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
- found = ucl_object_find_key (prop, ucl_object_key (elt));
+ prop = ucl_object_lookup (schema, "properties");
+ while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
+ found = ucl_object_lookup (prop, ucl_object_key (elt));
if (found == NULL) {
/* Try patternProperties */
piter = NULL;
- pat = ucl_object_find_key (schema, "patternProperties");
- while ((pelt = ucl_iterate_object (pat, &piter, true)) != NULL) {
+ pat = ucl_object_lookup (schema, "patternProperties");
+ while ((pelt = ucl_object_iterate (pat, &piter, true)) != NULL) {
found = ucl_schema_test_pattern (obj, ucl_object_key (pelt));
if (found != NULL) {
break;
@@ -308,7 +249,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
break;
}
else if (additional_schema != NULL) {
- if (!ucl_schema_validate (additional_schema, elt, true, err, root)) {
+ if (!ucl_schema_validate (additional_schema, elt,
+ true, err, root, ext_ref)) {
ret = false;
break;
}
@@ -319,8 +261,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
/* Required properties */
if (required != NULL) {
iter = NULL;
- while ((elt = ucl_iterate_object (required, &iter, true)) != NULL) {
- if (ucl_object_find_key (obj, ucl_object_tostring (elt)) == NULL) {
+ while ((elt = ucl_object_iterate (required, &iter, true)) != NULL) {
+ if (ucl_object_lookup (obj, ucl_object_tostring (elt)) == NULL) {
ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj,
"object has missing property %s",
ucl_object_tostring (elt));
@@ -345,7 +287,7 @@ ucl_schema_validate_number (const ucl_object_t *schema,
double constraint, val;
const double alpha = 1e-16;
- while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
+ while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
strcmp (ucl_object_key (elt), "multipleOf") == 0) {
constraint = ucl_object_todouble (elt);
@@ -367,7 +309,7 @@ ucl_schema_validate_number (const ucl_object_t *schema,
else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
strcmp (ucl_object_key (elt), "maximum") == 0) {
constraint = ucl_object_todouble (elt);
- test = ucl_object_find_key (schema, "exclusiveMaximum");
+ test = ucl_object_lookup (schema, "exclusiveMaximum");
if (test && test->type == UCL_BOOLEAN) {
exclusive = ucl_object_toboolean (test);
}
@@ -383,7 +325,7 @@ ucl_schema_validate_number (const ucl_object_t *schema,
else if ((elt->type == UCL_FLOAT || elt->type == UCL_INT) &&
strcmp (ucl_object_key (elt), "minimum") == 0) {
constraint = ucl_object_todouble (elt);
- test = ucl_object_find_key (schema, "exclusiveMinimum");
+ test = ucl_object_lookup (schema, "exclusiveMinimum");
if (test && test->type == UCL_BOOLEAN) {
exclusive = ucl_object_toboolean (test);
}
@@ -413,7 +355,7 @@ ucl_schema_validate_string (const ucl_object_t *schema,
regex_t re;
#endif
- while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
+ while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
if (elt->type == UCL_INT &&
strcmp (ucl_object_key (elt), "maxLength") == 0) {
constraint = ucl_object_toint (elt);
@@ -487,7 +429,7 @@ ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *er
struct ucl_compare_node *node, test, *nodes = NULL, *tmp;
bool ret = true;
- while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
+ while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
test.obj = elt;
node = TREE_FIND (&tree, ucl_compare_node, link, &test);
if (node != NULL) {
@@ -518,7 +460,8 @@ ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *er
static bool
ucl_schema_validate_array (const ucl_object_t *schema,
const ucl_object_t *obj, struct ucl_schema_error *err,
- const ucl_object_t *root)
+ const ucl_object_t *root,
+ ucl_object_t *ext_ref)
{
const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
*first_unvalidated = NULL;
@@ -527,13 +470,14 @@ ucl_schema_validate_array (const ucl_object_t *schema,
int64_t minmax;
unsigned int idx = 0;
- while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
+ while (ret && (elt = ucl_object_iterate (schema, &iter, true)) != NULL) {
if (strcmp (ucl_object_key (elt), "items") == 0) {
if (elt->type == UCL_ARRAY) {
found = ucl_array_head (obj);
- while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) {
+ while (ret && (it = ucl_object_iterate (elt, &piter, true)) != NULL) {
if (found) {
- ret = ucl_schema_validate (it, found, false, err, root);
+ ret = ucl_schema_validate (it, found, false, err,
+ root, ext_ref);
found = ucl_array_find_index (obj, ++idx);
}
}
@@ -544,8 +488,9 @@ ucl_schema_validate_array (const ucl_object_t *schema,
}
else if (elt->type == UCL_OBJECT) {
/* Validate all items using the specified schema */
- while (ret && (it = ucl_iterate_object (obj, &piter, true)) != NULL) {
- ret = ucl_schema_validate (elt, it, false, err, root);
+ while (ret && (it = ucl_object_iterate (obj, &piter, true)) != NULL) {
+ ret = ucl_schema_validate (elt, it, false, err, root,
+ ext_ref);
}
}
else {
@@ -612,7 +557,7 @@ ucl_schema_validate_array (const ucl_object_t *schema,
elt = ucl_array_find_index (obj, idx);
while (elt) {
if (!ucl_schema_validate (additional_schema, elt, false,
- err, root)) {
+ err, root, ext_ref)) {
ret = false;
break;
}
@@ -649,7 +594,7 @@ ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
if (type->type == UCL_ARRAY) {
/* One of allowed types */
- while ((elt = ucl_iterate_object (type, &iter, true)) != NULL) {
+ while ((elt = ucl_object_iterate (type, &iter, true)) != NULL) {
if (ucl_schema_type_is_allowed (elt, obj, err)) {
return true;
}
@@ -657,7 +602,7 @@ ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
}
else if (type->type == UCL_STRING) {
type_str = ucl_object_tostring (type);
- if (!ucl_string_to_type (type_str, &t)) {
+ if (!ucl_object_string_to_type (type_str, &t)) {
ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
"Type attribute is invalid in schema");
return false;
@@ -697,7 +642,7 @@ ucl_schema_validate_enum (const ucl_object_t *en, const ucl_object_t *obj,
const ucl_object_t *elt;
bool ret = false;
- while ((elt = ucl_iterate_object (en, &iter, true)) != NULL) {
+ while ((elt = ucl_object_iterate (en, &iter, true)) != NULL) {
if (ucl_object_compare (elt, obj) == 0) {
ret = true;
break;
@@ -727,7 +672,7 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur,
if (cur->type == UCL_OBJECT) {
/* Find a key inside an object */
- res = ucl_object_find_keyl (cur, refc, len);
+ res = ucl_object_lookup_len (cur, refc, len);
if (res == NULL) {
ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, cur,
"reference %s is invalid, missing path component", refc);
@@ -771,31 +716,114 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur,
*/
static const ucl_object_t *
ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
- struct ucl_schema_error *err)
+ struct ucl_schema_error *err, ucl_object_t *ext_ref,
+ ucl_object_t const ** nroot)
{
- const char *p, *c;
- const ucl_object_t *res = NULL;
-
+ UT_string *url_err = NULL;
+ struct ucl_parser *parser;
+ const ucl_object_t *res = NULL, *ext_obj = NULL;
+ ucl_object_t *url_obj;
+ const char *p, *c, *hash_ptr = NULL;
+ char *url_copy = NULL;
+ unsigned char *url_buf;
+ size_t url_buflen;
if (ref[0] != '#') {
- ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
- "reference %s is invalid, not started with #", ref);
- return NULL;
+ hash_ptr = strrchr (ref, '#');
+
+ if (hash_ptr) {
+ url_copy = malloc (hash_ptr - ref + 1);
+
+ if (url_copy == NULL) {
+ ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
+ "cannot allocate memory");
+ return NULL;
+ }
+
+ ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
+ p = url_copy;
+ }
+ else {
+ /* Full URL */
+ p = ref;
+ }
+
+ ext_obj = ucl_object_lookup (ext_ref, p);
+
+ if (ext_obj == NULL) {
+ if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
+ if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
+
+ ucl_schema_create_error (err,
+ UCL_SCHEMA_INVALID_SCHEMA,
+ root,
+ "cannot fetch reference %s: %s",
+ p,
+ url_err != NULL ? utstring_body (url_err)
+ : "unknown");
+ free (url_copy);
+
+ return NULL;
+ }
+ }
+ else {
+ if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
+ true)) {
+ ucl_schema_create_error (err,
+ UCL_SCHEMA_INVALID_SCHEMA,
+ root,
+ "cannot fetch reference %s: %s",
+ p,
+ url_err != NULL ? utstring_body (url_err)
+ : "unknown");
+ free (url_copy);
+
+ return NULL;
+ }
+ }
+
+ parser = ucl_parser_new (0);
+
+ if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
+ ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
+ "cannot fetch reference %s: %s", p,
+ ucl_parser_get_error (parser));
+ ucl_parser_free (parser);
+ free (url_copy);
+
+ return NULL;
+ }
+
+ url_obj = ucl_parser_get_object (parser);
+ ext_obj = url_obj;
+ ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
+ free (url_buf);
+ }
+
+ free (url_copy);
+
+ if (hash_ptr) {
+ p = hash_ptr + 1;
+ }
+ else {
+ p = "";
+ }
}
- if (ref[1] == '/') {
- p = &ref[2];
+ else {
+ p = ref + 1;
}
- else if (ref[1] == '\0') {
- return root;
+
+ res = ext_obj != NULL ? ext_obj : root;
+ *nroot = res;
+
+ if (*p == '/') {
+ p++;
}
- else {
- ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
- "reference %s is invalid, not started with #/", ref);
- return NULL;
+ else if (*p == '\0') {
+ return res;
}
c = p;
- res = root;
while (*p != '\0') {
if (*p == '/') {
@@ -835,7 +863,7 @@ ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
const ucl_object_t *elt, *cur;
int64_t constraint, i;
- elt = ucl_object_find_key (schema, "maxValues");
+ elt = ucl_object_lookup (schema, "maxValues");
if (elt != NULL && elt->type == UCL_INT) {
constraint = ucl_object_toint (elt);
cur = obj;
@@ -851,7 +879,7 @@ ucl_schema_validate_values (const ucl_object_t *schema, const ucl_object_t *obj,
cur = cur->next;
}
}
- elt = ucl_object_find_key (schema, "minValues");
+ elt = ucl_object_lookup (schema, "minValues");
if (elt != NULL && elt->type == UCL_INT) {
constraint = ucl_object_toint (elt);
cur = obj;
@@ -878,15 +906,17 @@ static bool
ucl_schema_validate (const ucl_object_t *schema,
const ucl_object_t *obj, bool try_array,
struct ucl_schema_error *err,
- const ucl_object_t *root)
+ const ucl_object_t *root,
+ ucl_object_t *external_refs)
{
- const ucl_object_t *elt, *cur;
+ const ucl_object_t *elt, *cur, *ref_root;
ucl_object_iter_t iter = NULL;
bool ret;
if (schema->type != UCL_OBJECT) {
ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
- "schema is %s instead of object", ucl_object_type_to_string (schema->type));
+ "schema is %s instead of object",
+ ucl_object_type_to_string (schema->type));
return false;
}
@@ -898,36 +928,36 @@ ucl_schema_validate (const ucl_object_t *schema,
return false;
}
LL_FOREACH (obj, cur) {
- if (!ucl_schema_validate (schema, cur, false, err, root)) {
+ if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
return false;
}
}
return true;
}
- elt = ucl_object_find_key (schema, "enum");
+ elt = ucl_object_lookup (schema, "enum");
if (elt != NULL && elt->type == UCL_ARRAY) {
if (!ucl_schema_validate_enum (elt, obj, err)) {
return false;
}
}
- elt = ucl_object_find_key (schema, "allOf");
+ elt = ucl_object_lookup (schema, "allOf");
if (elt != NULL && elt->type == UCL_ARRAY) {
iter = NULL;
- while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
- ret = ucl_schema_validate (cur, obj, true, err, root);
+ while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
+ ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
if (!ret) {
return false;
}
}
}
- elt = ucl_object_find_key (schema, "anyOf");
+ elt = ucl_object_lookup (schema, "anyOf");
if (elt != NULL && elt->type == UCL_ARRAY) {
iter = NULL;
- while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
- ret = ucl_schema_validate (cur, obj, true, err, root);
+ while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
+ ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
if (ret) {
break;
}
@@ -941,15 +971,15 @@ ucl_schema_validate (const ucl_object_t *schema,
}
}
- elt = ucl_object_find_key (schema, "oneOf");
+ elt = ucl_object_lookup (schema, "oneOf");
if (elt != NULL && elt->type == UCL_ARRAY) {
iter = NULL;
ret = false;
- while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
+ while ((cur = ucl_object_iterate (elt, &iter, true)) != NULL) {
if (!ret) {
- ret = ucl_schema_validate (cur, obj, true, err, root);
+ ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
}
- else if (ucl_schema_validate (cur, obj, true, err, root)) {
+ else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
ret = false;
break;
}
@@ -959,9 +989,9 @@ ucl_schema_validate (const ucl_object_t *schema,
}
}
- elt = ucl_object_find_key (schema, "not");
+ elt = ucl_object_lookup (schema, "not");
if (elt != NULL && elt->type == UCL_OBJECT) {
- if (ucl_schema_validate (elt, obj, true, err, root)) {
+ if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
return false;
}
else {
@@ -970,28 +1000,32 @@ ucl_schema_validate (const ucl_object_t *schema,
}
}
- elt = ucl_object_find_key (schema, "$ref");
+ elt = ucl_object_lookup (schema, "$ref");
if (elt != NULL) {
- cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), err);
+ ref_root = root;
+ cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
+ err, external_refs, &ref_root);
+
if (cur == NULL) {
return false;
}
- if (!ucl_schema_validate (cur, obj, try_array, err, root)) {
+ if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
+ external_refs)) {
return false;
}
}
- elt = ucl_object_find_key (schema, "type");
+ elt = ucl_object_lookup (schema, "type");
if (!ucl_schema_type_is_allowed (elt, obj, err)) {
return false;
}
switch (obj->type) {
case UCL_OBJECT:
- return ucl_schema_validate_object (schema, obj, err, root);
+ return ucl_schema_validate_object (schema, obj, err, root, external_refs);
break;
case UCL_ARRAY:
- return ucl_schema_validate_array (schema, obj, err, root);
+ return ucl_schema_validate_array (schema, obj, err, root, external_refs);
break;
case UCL_INT:
case UCL_FLOAT:
@@ -1011,5 +1045,37 @@ bool
ucl_object_validate (const ucl_object_t *schema,
const ucl_object_t *obj, struct ucl_schema_error *err)
{
- return ucl_schema_validate (schema, obj, true, err, schema);
+ return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
+}
+
+bool
+ucl_object_validate_root (const ucl_object_t *schema,
+ const ucl_object_t *obj,
+ const ucl_object_t *root,
+ struct ucl_schema_error *err)
+{
+ return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
+}
+
+bool
+ucl_object_validate_root_ext (const ucl_object_t *schema,
+ const ucl_object_t *obj,
+ const ucl_object_t *root,
+ ucl_object_t *ext_refs,
+ struct ucl_schema_error *err)
+{
+ bool ret, need_unref = false;
+
+ if (ext_refs == NULL) {
+ ext_refs = ucl_object_typed_new (UCL_OBJECT);
+ need_unref = true;
+ }
+
+ ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
+
+ if (need_unref) {
+ ucl_object_unref (ext_refs);
+ }
+
+ return ret;
}
diff --git a/src/ucl_sexp.c b/src/ucl_sexp.c
index 3ca7eb102925..1ad93d23458e 100644
--- a/src/ucl_sexp.c
+++ b/src/ucl_sexp.c
@@ -108,6 +108,7 @@ ucl_parse_csexp (struct ucl_parser *parser)
if (st->obj == NULL) {
ucl_create_err (&parser->err, "no memory");
state = parse_err;
+ free (st);
continue;
}
@@ -205,6 +206,7 @@ ucl_parse_csexp (struct ucl_parser *parser)
}
free (st);
+ st = NULL;
p++;
NEXT_STATE;
break;
@@ -221,4 +223,4 @@ ucl_parse_csexp (struct ucl_parser *parser)
}
return true;
-} \ No newline at end of file
+}
diff --git a/src/ucl_util.c b/src/ucl_util.c
index 730a5c4afd57..261bf95f5b7d 100644
--- a/src/ucl_util.c
+++ b/src/ucl_util.c
@@ -27,6 +27,7 @@
#include "ucl_chartable.h"
#include "kvec.h"
#include <stdarg.h>
+#include <stdio.h> /* for snprintf */
#ifndef _WIN32
#include <glob.h>
@@ -50,6 +51,8 @@ typedef kvec_t(ucl_object_t *) ucl_array_t;
#endif
#ifdef CURL_FOUND
+/* Seems to be broken */
+#define CURL_DISABLE_TYPECHECK 1
#include <curl/curl.h>
#endif
#ifdef HAVE_FETCH_H
@@ -236,7 +239,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dto
}
else if (obj->type == UCL_OBJECT) {
if (obj->value.ov != NULL) {
- ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
+ ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
}
obj->value.ov = NULL;
}
@@ -306,6 +309,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 +328,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 +345,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 +354,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';
@@ -437,7 +454,7 @@ ucl_copy_value_trash (const ucl_object_t *obj)
}
deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
}
-
+
return obj->trash_stack[UCL_TRASH_VALUE];
}
@@ -504,6 +521,10 @@ ucl_parser_free (struct ucl_parser *parser)
free (parser->cur_file);
}
+ if (parser->comments) {
+ ucl_object_unref (parser->comments);
+ }
+
UCL_FREE (sizeof (struct ucl_parser), parser);
}
@@ -628,7 +649,7 @@ ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
* @param buflen target length
* @return
*/
-static bool
+bool
ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
UT_string **err, bool must_exist)
{
@@ -690,8 +711,8 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
return false;
}
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
- cbdata.buf = *buf;
- cbdata.buflen = *buflen;
+ cbdata.buf = NULL;
+ cbdata.buflen = 0;
curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
if ((r = curl_easy_perform (curl)) != CURLE_OK) {
@@ -723,7 +744,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
* @param buflen target length
* @return
*/
-static bool
+bool
ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
UT_string **err, bool must_exist)
{
@@ -739,7 +760,7 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
}
if (st.st_size == 0) {
/* Do not map empty files */
- *buf = "";
+ *buf = NULL;
*buflen = 0;
}
else {
@@ -752,6 +773,8 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
close (fd);
ucl_create_err (err, "cannot mmap file %s: %s",
filename, strerror (errno));
+ *buf = NULL;
+
return false;
}
*buflen = st.st_size;
@@ -848,7 +871,7 @@ ucl_include_url (const unsigned char *data, size_t len,
snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
- return (!params->must_exist || false);
+ return !params->must_exist;
}
if (params->check_signature) {
@@ -968,12 +991,12 @@ ucl_include_file_single (const unsigned char *data, size_t len,
ucl_create_err (&parser->err, "cannot verify file %s: %s",
filebuf,
ERR_error_string (ERR_get_error (), NULL));
- if (siglen > 0) {
+ if (sigbuf) {
ucl_munmap (sigbuf, siglen);
}
return false;
}
- if (siglen > 0) {
+ if (sigbuf) {
ucl_munmap (sigbuf, siglen);
}
#endif
@@ -1037,6 +1060,16 @@ ucl_include_file_single (const unsigned char *data, size_t len,
else if (old_obj == NULL) {
/* Create an object with key: prefix */
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
+
nest_obj->key = params->prefix;
nest_obj->keylen = strlen (params->prefix);
ucl_copy_key_trash(nest_obj);
@@ -1052,6 +1085,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
if (ucl_object_type(old_obj) == UCL_ARRAY) {
/* Append to the existing array */
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
nest_obj->prev = nest_obj;
nest_obj->next = NULL;
@@ -1060,6 +1101,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
else {
/* Convert the object to an array */
new_obj = ucl_object_typed_new (UCL_ARRAY);
+ if (new_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
new_obj->key = old_obj->key;
new_obj->keylen = old_obj->keylen;
new_obj->flags |= UCL_OBJECT_MULTIVALUE;
@@ -1067,6 +1116,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
new_obj->next = NULL;
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
nest_obj->prev = nest_obj;
nest_obj->next = NULL;
@@ -1085,6 +1142,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,
ucl_create_err (&parser->err,
"Conflicting type for key: %s",
params->prefix);
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
return false;
}
}
@@ -1092,18 +1153,21 @@ ucl_include_file_single (const unsigned char *data, size_t len,
/* Put all of the content of the include inside that object */
parser->stack->obj->value.ov = container;
- if (nest_obj != NULL) {
- st = UCL_ALLOC (sizeof (struct ucl_stack));
- if (st == NULL) {
- ucl_create_err (&parser->err, "cannot allocate memory for an object");
- ucl_object_unref (nest_obj);
- return NULL;
+ st = UCL_ALLOC (sizeof (struct ucl_stack));
+ if (st == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ ucl_object_unref (nest_obj);
+
+ if (buf) {
+ ucl_munmap (buf, buflen);
}
- st->obj = nest_obj;
- st->level = parser->stack->level;
- LL_PREPEND (parser->stack, st);
- parser->cur_obj = nest_obj;
+
+ return false;
}
+ st->obj = nest_obj;
+ st->level = parser->stack->level;
+ LL_PREPEND (parser->stack, st);
+ parser->cur_obj = nest_obj;
}
res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
@@ -1232,7 +1296,7 @@ ucl_include_file (const unsigned char *data, size_t len,
treat allow_glob/need_glob as a NOOP and just return */
return ucl_include_file_single (data, len, parser, params);
#endif
-
+
return true;
}
@@ -1252,7 +1316,7 @@ ucl_include_common (const unsigned char *data, size_t len,
bool default_try,
bool default_sign)
{
- bool allow_url, search;
+ bool allow_url = false, search = false;
const char *duplicate;
const ucl_object_t *param;
ucl_object_iter_t it = NULL, ip = NULL;
@@ -1271,11 +1335,9 @@ ucl_include_common (const unsigned char *data, size_t len,
params.strat = UCL_DUPLICATE_APPEND;
params.must_exist = !default_try;
- search = false;
-
/* Process arguments */
if (args != NULL && args->type == UCL_OBJECT) {
- while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
+ while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
if (param->type == UCL_BOOLEAN) {
if (strncmp (param->key, "try", param->keylen) == 0) {
params.must_exist = !ucl_object_toboolean (param);
@@ -1450,7 +1512,7 @@ ucl_priority_handler (const unsigned char *data, size_t len,
/* Process arguments */
if (args != NULL && args->type == UCL_OBJECT) {
- while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
+ while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
if (param->type == UCL_INT) {
if (strncmp (param->key, "priority", param->keylen) == 0) {
priority = ucl_object_toint (param);
@@ -1506,7 +1568,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 */
@@ -1529,7 +1591,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
/* Process arguments */
if (args != NULL && args->type == UCL_OBJECT) {
- while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
+ while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
if (param->type == UCL_BOOLEAN) {
if (strncmp (param->key, "try", param->keylen) == 0) {
try_load = ucl_object_toboolean (param);
@@ -1566,21 +1628,39 @@ 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)) {
+ load_file = malloc (len + 1);
+ if (!load_file) {
+ ucl_create_err (&parser->err, "cannot allocate memory for suffix");
+
+ return false;
+ }
+
+ snprintf (load_file, len + 1, "%.*s", (int)len, data);
+
+ 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_lookup (container,
+ prefix));
+
if (old_obj != NULL) {
ucl_create_err (&parser->err, "Key %s already exists", prefix);
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
return false;
}
@@ -1592,26 +1672,37 @@ 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);
+ tmp = malloc (buflen + 1);
+
+ if (tmp == NULL) {
+ ucl_create_err (&parser->err, "Memory allocation failed");
+ if (buf) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
+
+ snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf);
+ iv = strtoll (tmp, NULL, 10);
+ obj = ucl_object_fromint (iv);
+ free (tmp);
}
- if (buflen > 0) {
+ if (buf) {
ucl_munmap (buf, buflen);
}
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;
}
@@ -1629,7 +1720,7 @@ ucl_inherit_handler (const unsigned char *data, size_t len,
bool replace = false;
struct ucl_parser *parser = ud;
- parent = ucl_object_find_keyl (ctx, data, len);
+ parent = ucl_object_lookup_len (ctx, data, len);
/* Some sanity checks */
if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
@@ -1646,13 +1737,13 @@ ucl_inherit_handler (const unsigned char *data, size_t len,
target = parser->stack->obj;
- if (args && (cur = ucl_object_find_key (args, "replace")) != NULL) {
+ if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) {
replace = ucl_object_toboolean (cur);
}
- while ((cur = ucl_iterate_object (parent, &it, true))) {
+ while ((cur = ucl_object_iterate (parent, &it, true))) {
/* We do not replace existing keys */
- if (!replace && ucl_object_find_keyl (target, cur->key, cur->keylen)) {
+ if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) {
continue;
}
@@ -2097,7 +2188,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
}
else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
/* Mix two hashes */
- while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
+ while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
tmp = ucl_object_ref (cur);
ucl_object_insert_key_common (found, tmp, cur->key,
cur->keylen, copy_key, false, false);
@@ -2126,7 +2217,7 @@ ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
return false;
}
- found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen));
+ found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen));
if (found == NULL) {
return false;
@@ -2153,7 +2244,7 @@ ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
if (top == NULL || key == NULL) {
return false;
}
- found = ucl_object_find_keyl (top, key, keylen);
+ found = ucl_object_lookup_len (top, key, keylen);
if (found == NULL) {
return NULL;
@@ -2226,7 +2317,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
}
const ucl_object_t *
-ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
+ucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen)
{
const ucl_object_t *ret;
ucl_object_t srch;
@@ -2243,17 +2334,17 @@ ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
}
const ucl_object_t *
-ucl_object_find_key (const ucl_object_t *obj, const char *key)
+ucl_object_lookup (const ucl_object_t *obj, const char *key)
{
if (key == NULL) {
return NULL;
}
- return ucl_object_find_keyl (obj, key, strlen (key));
+ return ucl_object_lookup_len (obj, key, strlen (key));
}
const ucl_object_t*
-ucl_object_find_any_key (const ucl_object_t *obj,
+ucl_object_lookup_any (const ucl_object_t *obj,
const char *key, ...)
{
va_list ap;
@@ -2264,7 +2355,7 @@ ucl_object_find_any_key (const ucl_object_t *obj,
return NULL;
}
- ret = ucl_object_find_keyl (obj, key, strlen (key));
+ ret = ucl_object_lookup_len (obj, key, strlen (key));
if (ret == NULL) {
va_start (ap, key);
@@ -2276,7 +2367,7 @@ ucl_object_find_any_key (const ucl_object_t *obj,
break;
}
else {
- ret = ucl_object_find_keyl (obj, nk, strlen (nk));
+ ret = ucl_object_lookup_len (obj, nk, strlen (nk));
}
}
@@ -2287,7 +2378,7 @@ ucl_object_find_any_key (const ucl_object_t *obj,
}
const ucl_object_t*
-ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
+ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
{
const ucl_object_t *elt = NULL;
@@ -2394,7 +2485,7 @@ ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
}
if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
- ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true);
+ ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
if (ret == NULL) {
/* Need to switch to another implicit object in chain */
@@ -2429,13 +2520,13 @@ ucl_object_iterate_free (ucl_object_iter_t it)
}
const ucl_object_t *
-ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
- return ucl_lookup_path_char (top, path_in, '.');
+ucl_object_lookup_path (const ucl_object_t *top, const char *path_in) {
+ return ucl_object_lookup_path_char (top, path_in, '.');
}
const ucl_object_t *
-ucl_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
+ucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
const ucl_object_t *o = NULL, *found;
const char *p, *c;
char *err_str;
@@ -2468,7 +2559,7 @@ ucl_lookup_path_char (const ucl_object_t *top, const char *path_in, const char s
o = ucl_array_find_index (top, index);
break;
default:
- o = ucl_object_find_keyl (top, c, p - c);
+ o = ucl_object_lookup_len (top, c, p - c);
break;
}
if (o == NULL) {
@@ -2527,7 +2618,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);
}
@@ -2535,7 +2626,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);
@@ -2549,6 +2642,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;
@@ -2691,14 +2785,16 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
UCL_ARRAY_GET (v1, top);
UCL_ARRAY_GET (v2, cp);
- kv_concat (ucl_object_t *, *v1, *v2);
+ if (v1 && v2) {
+ kv_concat (ucl_object_t *, *v1, *v2);
- for (i = v2->n; i < v1->n; i ++) {
- obj = &kv_A (*v1, i);
- if (*obj == NULL) {
- continue;
+ for (i = v2->n; i < v1->n; i ++) {
+ obj = &kv_A (*v1, i);
+ if (*obj == NULL) {
+ continue;
+ }
+ top->len ++;
}
- top->len ++;
}
return true;
@@ -3087,7 +3183,7 @@ ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
/* reset old value */
memset (&new->value, 0, sizeof (new->value));
- while ((cur = ucl_iterate_object (other, &it, true)) != NULL) {
+ while ((cur = ucl_object_iterate (other, &it, true)) != NULL) {
if (other->type == UCL_ARRAY) {
ucl_array_append (new, ucl_object_copy_internal (cur, false));
}
@@ -3193,8 +3289,8 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
break;
case UCL_OBJECT:
if (o1->len == o2->len && o1->len > 0) {
- while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
- it2 = ucl_object_find_key (o2, ucl_object_key (it1));
+ while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) {
+ it2 = ucl_object_lookup (o2, ucl_object_key (it1));
if (it2 == NULL) {
ret = 1;
break;
@@ -3217,6 +3313,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))
@@ -3255,3 +3358,131 @@ ucl_object_set_priority (ucl_object_t *obj,
obj->flags = priority;
}
}
+
+bool
+ucl_object_string_to_type (const char *input, ucl_type_t *res)
+{
+ if (strcasecmp (input, "object") == 0) {
+ *res = UCL_OBJECT;
+ }
+ else if (strcasecmp (input, "array") == 0) {
+ *res = UCL_ARRAY;
+ }
+ else if (strcasecmp (input, "integer") == 0) {
+ *res = UCL_INT;
+ }
+ else if (strcasecmp (input, "number") == 0) {
+ *res = UCL_FLOAT;
+ }
+ else if (strcasecmp (input, "string") == 0) {
+ *res = UCL_STRING;
+ }
+ else if (strcasecmp (input, "boolean") == 0) {
+ *res = UCL_BOOLEAN;
+ }
+ else if (strcasecmp (input, "null") == 0) {
+ *res = UCL_NULL;
+ }
+ else if (strcasecmp (input, "userdata") == 0) {
+ *res = UCL_USERDATA;
+ }
+ else {
+ return false;
+ }
+
+ return true;
+}
+
+const char *
+ucl_object_type_to_string (ucl_type_t type)
+{
+ const char *res = "unknown";
+
+ switch (type) {
+ case UCL_OBJECT:
+ res = "object";
+ break;
+ case UCL_ARRAY:
+ res = "array";
+ break;
+ case UCL_INT:
+ res = "integer";
+ break;
+ case UCL_FLOAT:
+ case UCL_TIME:
+ res = "number";
+ break;
+ case UCL_STRING:
+ res = "string";
+ break;
+ case UCL_BOOLEAN:
+ res = "boolean";
+ break;
+ case UCL_USERDATA:
+ res = "userdata";
+ break;
+ case UCL_NULL:
+ res = "null";
+ break;
+ }
+
+ return res;
+}
+
+const ucl_object_t *
+ucl_parser_get_comments (struct ucl_parser *parser)
+{
+ if (parser && parser->comments) {
+ return parser->comments;
+ }
+
+ return NULL;
+}
+
+const ucl_object_t *
+ucl_comments_find (const ucl_object_t *comments,
+ const ucl_object_t *srch)
+{
+ if (comments && srch) {
+ return ucl_object_lookup_len (comments, (const char *)&srch,
+ sizeof (void *));
+ }
+
+ return NULL;
+}
+
+bool
+ucl_comments_move (ucl_object_t *comments,
+ const ucl_object_t *from, const ucl_object_t *to)
+{
+ const ucl_object_t *found;
+ ucl_object_t *obj;
+
+ if (comments && from && to) {
+ found = ucl_object_lookup_len (comments,
+ (const char *)&from, sizeof (void *));
+
+ if (found) {
+ /* Replace key */
+ obj = ucl_object_ref (found);
+ ucl_object_delete_keyl (comments, (const char *)&from,
+ sizeof (void *));
+ ucl_object_insert_key (comments, obj, (const char *)&to,
+ sizeof (void *), true);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
+ const char *comment)
+{
+ if (comments && obj && comment) {
+ ucl_object_insert_key (comments, ucl_object_fromstring (comment),
+ (const char *)&obj, sizeof (void *), true);
+ }
+}