diff options
author | Baptiste Daroussin <bapt@FreeBSD.org> | 2016-04-17 21:25:53 +0000 |
---|---|---|
committer | Baptiste Daroussin <bapt@FreeBSD.org> | 2016-04-17 21:25:53 +0000 |
commit | 94f2b741289f8532938513e8379d6eed5077b687 (patch) | |
tree | f8c605ecc03d848a1aff2296e3de9ba8aa8a5aff /src | |
parent | 4e2fa78ea36ec2cf6583bc025b4127c5ea238fd2 (diff) | |
download | src-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.c | 47 | ||||
-rw-r--r-- | src/ucl_emitter_streamline.c | 10 | ||||
-rw-r--r-- | src/ucl_hash.c | 6 | ||||
-rw-r--r-- | src/ucl_hash.h | 6 | ||||
-rw-r--r-- | src/ucl_internal.h | 30 | ||||
-rw-r--r-- | src/ucl_msgpack.c | 40 | ||||
-rw-r--r-- | src/ucl_parser.c | 354 | ||||
-rw-r--r-- | src/ucl_schema.c | 360 | ||||
-rw-r--r-- | src/ucl_sexp.c | 4 | ||||
-rw-r--r-- | src/ucl_util.c | 377 |
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, ¯o_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 (®, 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 (®, 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); + } +} |