diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/libucl/CMakeLists.txt | 3 | ||||
-rw-r--r-- | contrib/libucl/ucl.h | 51 | ||||
-rw-r--r-- | contrib/libucl/ucl_emitter.c | 41 | ||||
-rw-r--r-- | contrib/libucl/ucl_emitter_streamline.c | 10 | ||||
-rw-r--r-- | contrib/libucl/ucl_hash.c | 2 | ||||
-rw-r--r-- | contrib/libucl/ucl_hash.h | 6 | ||||
-rw-r--r-- | contrib/libucl/ucl_internal.h | 2 | ||||
-rw-r--r-- | contrib/libucl/ucl_parser.c | 299 | ||||
-rw-r--r-- | contrib/libucl/ucl_schema.c | 13 | ||||
-rw-r--r-- | contrib/libucl/ucl_sexp.c | 226 | ||||
-rw-r--r-- | contrib/libucl/ucl_util.c | 77 |
11 files changed, 656 insertions, 74 deletions
diff --git a/contrib/libucl/CMakeLists.txt b/contrib/libucl/CMakeLists.txt index a1e919484..cda809116 100644 --- a/contrib/libucl/CMakeLists.txt +++ b/contrib/libucl/CMakeLists.txt @@ -6,7 +6,8 @@ SET(UCLSRC ucl_util.c ucl_hash.c ucl_schema.c lua_ucl.c - ucl_msgpack.c) + ucl_msgpack.c + ucl_sexp.c) SET (LIB_TYPE STATIC) diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index cfe62c081..14e72d119 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -147,11 +147,13 @@ typedef enum ucl_emitter { * UCL still has to perform copying implicitly. */ typedef enum ucl_parser_flags { - UCL_PARSER_DEFAULT = 0x0, /**< No special flags */ - UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */ - UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */ - UCL_PARSER_NO_TIME = 0x4, /**< Do not parse time and treat time values as strings */ - UCL_PARSER_NO_IMPLICIT_ARRAYS = 0x8 /** Create explicit arrays instead of implicit ones */ + UCL_PARSER_DEFAULT = 0, /**< No special flags */ + UCL_PARSER_KEY_LOWERCASE = (1 << 0), /**< Convert all keys to lower case */ + UCL_PARSER_ZEROCOPY = (1 << 1), /**< Parse input in zero-copy mode if possible */ + UCL_PARSER_NO_TIME = (1 << 2), /**< Do not parse time and treat time values as strings */ + UCL_PARSER_NO_IMPLICIT_ARRAYS = (1 << 3), /** Create explicit arrays instead of implicit ones */ + UCL_PARSER_SAVE_COMMENTS = (1 << 4), /** Save comments in the parser context */ + UCL_PARSER_DISABLE_MACRO = (1 << 5) /** Treat macros as comments */ } ucl_parser_flags_t; /** @@ -159,17 +161,17 @@ typedef enum ucl_parser_flags { */ typedef enum ucl_string_flags { UCL_STRING_RAW = 0x0, /**< Treat string as is */ - UCL_STRING_ESCAPE = 0x1, /**< Perform JSON escape */ - UCL_STRING_TRIM = 0x2, /**< Trim leading and trailing whitespaces */ - UCL_STRING_PARSE_BOOLEAN = 0x4, /**< Parse passed string and detect boolean */ - UCL_STRING_PARSE_INT = 0x8, /**< Parse passed string and detect integer number */ - UCL_STRING_PARSE_DOUBLE = 0x10, /**< Parse passed string and detect integer or float number */ - UCL_STRING_PARSE_TIME = 0x20, /**< Parse time strings */ + UCL_STRING_ESCAPE = (1 << 0), /**< Perform JSON escape */ + UCL_STRING_TRIM = (1 << 1), /**< Trim leading and trailing whitespaces */ + UCL_STRING_PARSE_BOOLEAN = (1 << 2), /**< Parse passed string and detect boolean */ + UCL_STRING_PARSE_INT = (1 << 3), /**< Parse passed string and detect integer number */ + UCL_STRING_PARSE_DOUBLE = (1 << 4), /**< Parse passed string and detect integer or float number */ + UCL_STRING_PARSE_TIME = (1 << 5), /**< Parse time strings */ UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE|UCL_STRING_PARSE_TIME, /**< Parse passed string and detect number */ UCL_STRING_PARSE = UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER, /**< Parse passed string (and detect booleans and numbers) */ - UCL_STRING_PARSE_BYTES = 0x40 /**< Treat numbers as bytes */ + UCL_STRING_PARSE_BYTES = (1 << 6) /**< Treat numbers as bytes */ } ucl_string_flags_t; /** @@ -1091,6 +1093,23 @@ UCL_EXTERN void ucl_parser_clear_error(struct ucl_parser *parser); UCL_EXTERN void ucl_parser_free (struct ucl_parser *parser); /** + * Get constant opaque pointer to comments structure for this parser. Increase + * refcount to prevent this object to be destroyed on parser's destruction + * @param parser parser structure + * @return ucl comments pointer or NULL + */ +UCL_EXTERN const ucl_object_t * ucl_parser_get_comments (struct ucl_parser *parser); + +/** + * Utility function to find a comment object for the specified object in the input + * @param comments comments object + * @param srch search object + * @return string comment enclosed in ucl_object_t + */ +UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments, + const ucl_object_t *srch); + +/** * Add new public key to parser for signatures check * @param parser parser object * @param key PEM representation of a key @@ -1171,8 +1190,8 @@ struct ucl_emitter_context { unsigned int indent; /** Top level object */ const ucl_object_t *top; - /** The rest of context */ - unsigned char data[1]; + /** Optional comments */ + const ucl_object_t *comments; }; /** @@ -1202,11 +1221,13 @@ UCL_EXTERN unsigned char *ucl_object_emit_len (const ucl_object_t *obj, * @param emit_type if type is #UCL_EMIT_JSON then emit json, if type is * #UCL_EMIT_CONFIG then emit config like object * @param emitter a set of emitter functions + * @param comments optional comments for the parser * @return dump of an object (must be freed after using) or NULL in case of error */ UCL_EXTERN 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); /** * Start streamlined UCL object emitter diff --git a/contrib/libucl/ucl_emitter.c b/contrib/libucl/ucl_emitter.c index 8bfbf09b8..84108e21d 100644 --- a/contrib/libucl/ucl_emitter.c +++ b/contrib/libucl/ucl_emitter.c @@ -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_find_keyl (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); + } + } + } } /* @@ -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/contrib/libucl/ucl_emitter_streamline.c b/contrib/libucl/ucl_emitter_streamline.c index ff27c8824..a7178c5d7 100644 --- a/contrib/libucl/ucl_emitter_streamline.c +++ b/contrib/libucl/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/contrib/libucl/ucl_hash.c b/contrib/libucl/ucl_hash.c index 7de8196fa..174ebb685 100644 --- a/contrib/libucl/ucl_hash.c +++ b/contrib/libucl/ucl_hash.c @@ -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/contrib/libucl/ucl_hash.h b/contrib/libucl/ucl_hash.h index 64c83eac8..92021e340 100644 --- a/contrib/libucl/ucl_hash.h +++ b/contrib/libucl/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/contrib/libucl/ucl_internal.h b/contrib/libucl/ucl_internal.h index 64938592a..db8a12c40 100644 --- a/contrib/libucl/ucl_internal.h +++ b/contrib/libucl/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; }; diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index 9bd41391b..fa906b7fe 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/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; } @@ -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); @@ -1092,6 +1151,7 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj parser->stack->obj->value.ov = container; parser->cur_obj = nobj; + ucl_attach_comment (parser, nobj, false); return true; } @@ -1120,7 +1180,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 +1524,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 */ @@ -1707,12 +1771,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 +1823,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 @@ -2067,7 +2241,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 +2269,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 (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,6 +2346,7 @@ 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->is_context) { ret = macro->h.context_handler (macro_start, macro_len, @@ -2194,7 +2387,6 @@ ucl_state_machine (struct ucl_parser *parser) } 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 +2394,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 diff --git a/contrib/libucl/ucl_schema.c b/contrib/libucl/ucl_schema.c index 9b96da5ef..531cf848c 100644 --- a/contrib/libucl/ucl_schema.c +++ b/contrib/libucl/ucl_schema.c @@ -753,7 +753,7 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, if (ext_obj == NULL) { if (ucl_strnstr (p, "://", strlen (p)) != NULL) { if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) { - free (url_copy); + ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root, @@ -761,13 +761,14 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, 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)) { - free (url_copy); ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root, @@ -775,6 +776,8 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, p, url_err != NULL ? utstring_body (url_err) : "unknown"); + free (url_copy); + return NULL; } } @@ -782,11 +785,12 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, parser = ucl_parser_new (0); if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) { - free (url_copy); 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; } @@ -794,9 +798,10 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, ext_obj = url_obj; ucl_object_insert_key (ext_ref, url_obj, p, 0, true); free (url_buf); - free (url_copy); } + free (url_copy); + if (hash_ptr) { p = hash_ptr + 1; } diff --git a/contrib/libucl/ucl_sexp.c b/contrib/libucl/ucl_sexp.c new file mode 100644 index 000000000..1ad93d234 --- /dev/null +++ b/contrib/libucl/ucl_sexp.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ucl.h> +#include "ucl.h" +#include "ucl_internal.h" +#include "utlist.h" + +#define NEXT_STATE do { \ +if (p >= end) { \ + if (state != read_ebrace) { \ + ucl_create_err (&parser->err,\ + "extra data");\ + state = parse_err; \ + } \ +} \ +else { \ +switch (*p) { \ + case '(': \ + state = read_obrace; \ + break; \ + case ')': \ + state = read_ebrace; \ + break; \ + default: \ + len = 0; \ + mult = 1; \ + state = read_length; \ + break; \ + } \ +} \ +} while(0) + +bool +ucl_parse_csexp (struct ucl_parser *parser) +{ + const unsigned char *p, *end; + ucl_object_t *obj; + struct ucl_stack *st; + uint64_t len = 0, mult = 1; + enum { + start_parse, + read_obrace, + read_length, + read_value, + read_ebrace, + parse_err + } state = start_parse; + + assert (parser != NULL); + assert (parser->chunks != NULL); + assert (parser->chunks->begin != NULL); + assert (parser->chunks->remain != 0); + + p = parser->chunks->begin; + end = p + parser->chunks->remain; + + while (p < end) { + switch (state) { + case start_parse: + /* At this point we expect open brace */ + if (*p == '(') { + state = read_obrace; + } + else { + ucl_create_err (&parser->err, "bad starting character for " + "sexp block: %x", (int)*p); + state = parse_err; + } + break; + + case read_obrace: + st = calloc (1, sizeof (*st)); + + if (st == NULL) { + ucl_create_err (&parser->err, "no memory"); + state = parse_err; + continue; + } + + st->obj = ucl_object_typed_new (UCL_ARRAY); + + if (st->obj == NULL) { + ucl_create_err (&parser->err, "no memory"); + state = parse_err; + free (st); + continue; + } + + if (parser->stack == NULL) { + /* We have no stack */ + parser->stack = st; + + if (parser->top_obj == NULL) { + parser->top_obj = st->obj; + } + } + else { + /* Prepend new element to the stack */ + LL_PREPEND (parser->stack, st); + } + + p ++; + NEXT_STATE; + + break; + + case read_length: + if (*p == ':') { + if (len == 0) { + ucl_create_err (&parser->err, "zero length element"); + state = parse_err; + continue; + } + + state = read_value; + } + else if (*p >= '0' && *p <= '9') { + len += (*p - '0') * mult; + mult *= 10; + + if (len > UINT32_MAX) { + ucl_create_err (&parser->err, "too big length of an " + "element"); + state = parse_err; + continue; + } + } + else { + ucl_create_err (&parser->err, "bad length character: %x", + (int)*p); + state = parse_err; + continue; + } + + p ++; + break; + + case read_value: + if ((uint64_t)(end - p) > len || len == 0) { + ucl_create_err (&parser->err, "invalid length: %llu, %ld " + "remain", (long long unsigned)len, (long)(end - p)); + state = parse_err; + continue; + } + obj = ucl_object_typed_new (UCL_STRING); + + obj->value.sv = (const char*)p; + obj->len = len; + obj->flags |= UCL_OBJECT_BINARY; + + if (!(parser->flags & UCL_PARSER_ZEROCOPY)) { + ucl_copy_value_trash (obj); + } + + ucl_array_append (parser->stack->obj, obj); + p += len; + NEXT_STATE; + break; + + case read_ebrace: + if (parser->stack == NULL) { + /* We have an extra end brace */ + ucl_create_err (&parser->err, "invalid length: %llu, %ld " + "remain", (long long unsigned)len, (long)(end - p)); + state = parse_err; + continue; + } + /* Pop the container */ + st = parser->stack; + parser->stack = st->next; + + if (parser->stack->obj->type == UCL_ARRAY) { + ucl_array_append (parser->stack->obj, st->obj); + } + else { + ucl_create_err (&parser->err, "bad container object, array " + "expected"); + state = parse_err; + continue; + } + + free (st); + st = NULL; + p++; + NEXT_STATE; + break; + + case parse_err: + default: + return false; + } + } + + if (state != read_ebrace) { + ucl_create_err (&parser->err, "invalid finishing state: %d", state); + return false; + } + + return true; +} diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index 2bd0c2a3f..15439feea 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -236,7 +236,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; } @@ -504,6 +504,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); } @@ -1037,6 +1041,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 (buflen > 0) { + 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 +1066,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 (buflen > 0) { + ucl_munmap (buf, buflen); + } + + return false; + } nest_obj->prev = nest_obj; nest_obj->next = NULL; @@ -1060,6 +1082,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 (buflen > 0) { + 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 +1097,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 (buflen > 0) { + ucl_munmap (buf, buflen); + } + + return false; + } nest_obj->prev = nest_obj; nest_obj->next = NULL; @@ -1085,6 +1123,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 (buflen > 0) { + ucl_munmap (buf, buflen); + } + return false; } } @@ -1097,7 +1139,11 @@ ucl_include_file_single (const unsigned char *data, size_t len, if (st == NULL) { ucl_create_err (&parser->err, "cannot allocate memory for an object"); ucl_object_unref (nest_obj); - return NULL; + if (buflen > 0) { + ucl_munmap (buf, buflen); + } + + return false; } st->obj = nest_obj; st->level = parser->stack->level; @@ -1579,6 +1625,10 @@ ucl_load_handler (const unsigned char *data, size_t len, old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix))); if (old_obj != NULL) { ucl_create_err (&parser->err, "Key %s already exists", prefix); + if (buflen > 0) { + ucl_munmap (buf, buflen); + } + return false; } @@ -1610,6 +1660,7 @@ ucl_load_handler (const unsigned char *data, size_t len, parser->flags & UCL_PARSER_KEY_LOWERCASE); parser->stack->obj->value.ov = container; } + return true; } @@ -3323,3 +3374,25 @@ ucl_object_type_to_string (ucl_type_t type) 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_find_keyl (comments, (const char *)&srch, + sizeof (void *)); + } + + return NULL; +} |