From f789d85b3a4b239a2a22a984eb6f403fd298dcbf Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 18 Apr 2016 18:30:08 +0100 Subject: [PATCH] [Fix] Backport fix for empty files inclusion from libucl Issue: #596 Reported by: @assistcontrol --- contrib/libucl/ucl.h | 22 ++++++++++++- contrib/libucl/ucl_parser.c | 61 ++++++++++++++++++++++++++----------- contrib/libucl/ucl_util.c | 50 +++++++++++++++++++++++++++--- 3 files changed, 109 insertions(+), 24 deletions(-) diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index bcc8049ac..024f5dd8f 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -107,7 +107,8 @@ typedef enum ucl_error { UCL_ENESTED, /**< Input has too many recursion levels */ UCL_EMACRO, /**< Error processing a macro */ UCL_EINTERNAL, /**< Internal unclassified error */ - UCL_ESSL /**< SSL error */ + UCL_ESSL, /**< SSL error */ + UCL_EMERGE /**< A merge error occured */ } ucl_error_t; /** @@ -1130,6 +1131,25 @@ UCL_EXTERN const ucl_object_t * ucl_parser_get_comments (struct ucl_parser *pars UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments, const ucl_object_t *srch); +/** + * Move comment from `from` object to `to` object + * @param comments comments object + * @param what source object + * @param whith destination object + * @return `true` if `from` has comment and it has been moved to `to` + */ +UCL_EXTERN bool ucl_comments_move (ucl_object_t *comments, + const ucl_object_t *from, const ucl_object_t *to); + +/** + * Adds a new comment for an object + * @param comments comments object + * @param obj object to add comment to + * @param comment string representation of a comment + */ +UCL_EXTERN void ucl_comments_add (ucl_object_t *comments, + const ucl_object_t *obj, const char *comment); + /** * Add new public key to parser for signatures check * @param parser parser object diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index 7a935a5c7..fc7cea07f 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/ucl_parser.c @@ -1068,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; @@ -1126,25 +1127,36 @@ 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 : "", - 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; } } @@ -2585,20 +2597,18 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, return false; } - if (data == NULL) { + if (data == NULL && len != 0) { 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 (parser->state != UCL_STATE_ERROR) { chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); if (chunk == NULL) { ucl_create_err (&parser->err, "cannot allocate chunk structure"); return false; } + chunk->begin = data; chunk->remain = len; chunk->pos = chunk->begin; @@ -2617,12 +2627,27 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, return false; } - switch (parse_type) { - default: - case UCL_PARSE_UCL: - return ucl_state_machine (parser); - case UCL_PARSE_MSGPACK: - return ucl_parse_msgpack (parser); + if (len > 0) { + /* Need to parse something */ + switch (parse_type) { + default: + case UCL_PARSE_UCL: + return ucl_state_machine (parser); + case UCL_PARSE_MSGPACK: + return ucl_parse_msgpack (parser); + } + } + else { + /* Just add empty chunk and go forward */ + if (parser->top_obj == NULL) { + /* + * In case of empty object, create one to indicate that we've + * read something + */ + parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority); + } + + return true; } } diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index 6376d6a42..1adb8c3b6 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -975,6 +975,7 @@ ucl_include_file_single (const unsigned char *data, size_t len, if (params->soft_fail) { return false; } + return (!params->must_exist || false); } @@ -1172,11 +1173,14 @@ ucl_include_file_single (const unsigned char *data, size_t len, res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, params->strat, params->parse_type); - if (!res && !params->must_exist) { - /* Free error */ - utstring_free (parser->err); - parser->err = NULL; - parser->state = UCL_STATE_AFTER_VALUE; + + if (!res) { + if (!params->must_exist) { + /* Free error */ + utstring_free (parser->err); + parser->err = NULL; + res = true; + } } /* Stop nesting the include, take 1 level off the stack */ @@ -3450,3 +3454,39 @@ ucl_comments_find (const ucl_object_t *comments, 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); + } +} -- 2.39.5