diff options
Diffstat (limited to 'src/ucl_parser.c')
-rw-r--r-- | src/ucl_parser.c | 552 |
1 files changed, 466 insertions, 86 deletions
diff --git a/src/ucl_parser.c b/src/ucl_parser.c index 9f44de10a6fc..23f5bce3056f 100644 --- a/src/ucl_parser.c +++ b/src/ucl_parser.c @@ -21,6 +21,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <math.h> #include "ucl.h" #include "ucl_internal.h" #include "ucl_chartable.h" @@ -44,16 +45,17 @@ struct ucl_parser_saved_state { * @param len * @return new position in chunk */ -#define ucl_chunk_skipc(chunk, p) do{ \ - if (*(p) == '\n') { \ - (chunk)->line ++; \ - (chunk)->column = 0; \ - } \ - else (chunk)->column ++; \ - (p++); \ - (chunk)->pos ++; \ - (chunk)->remain --; \ - } while (0) +#define ucl_chunk_skipc(chunk, p) \ +do { \ + if (*(p) == '\n') { \ + (chunk)->line ++; \ + (chunk)->column = 0; \ + } \ + else (chunk)->column ++; \ + (p++); \ + (chunk)->pos ++; \ + (chunk)->remain --; \ +} while (0) static inline void ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err) @@ -87,6 +89,7 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e } parser->err_code = code; + parser->state = UCL_STATE_ERROR; } static void @@ -342,7 +345,7 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema /* Call generic handler */ if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free, parser->var_data)) { - *out_len += dstlen; + *out_len = dstlen; *found = true; if (need_free) { free (dst); @@ -459,19 +462,15 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, } if (!found) { if (strict && parser->var_handler != NULL) { - size_t var_len = 0; - while (var_len < remain && p[var_len] != '}') - var_len ++; - - if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free, + if (parser->var_handler (p, remain, &dst, &dstlen, &need_free, parser->var_data)) { memcpy (d, dst, dstlen); - ret += var_len; + ret += remain; d += dstlen; + found = true; if (need_free) { free (dst); } - found = true; } } @@ -564,13 +563,15 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, * @param need_unescape need to unescape source (and copy it) * @param need_lowercase need to lowercase value (and copy) * @param need_expand need to expand variables (and copy as well) + * @param unescape_squote unescape single quoted string * @return output length (excluding \0 symbol) */ static inline ssize_t ucl_copy_or_store_ptr (struct ucl_parser *parser, const unsigned char *src, unsigned char **dst, const char **dst_const, size_t in_len, - bool need_unescape, bool need_lowercase, bool need_expand) + bool need_unescape, bool need_lowercase, bool need_expand, + bool unescape_squote) { ssize_t ret = -1, tret; unsigned char *tmp; @@ -593,8 +594,14 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser, } if (need_unescape) { - ret = ucl_unescape_json_string (*dst, ret); + if (!unescape_squote) { + ret = ucl_unescape_json_string (*dst, ret); + } + else { + ret = ucl_unescape_squoted_string (*dst, ret); + } } + if (need_expand) { tmp = *dst; tret = ret; @@ -628,47 +635,83 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser, */ static inline ucl_object_t * ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, - bool is_array, int level) + bool is_array, uint32_t level, bool has_obrace) { struct ucl_stack *st; + ucl_object_t *nobj; - if (!is_array) { - if (obj == NULL) { - obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority); + if (obj == NULL) { + nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority); + if (nobj == NULL) { + goto enomem0; } - else { - obj->type = UCL_OBJECT; - } - if (obj->value.ov == NULL) { - obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); + } else { + if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) { + /* Bad combination for merge: array and object */ + ucl_set_err (parser, UCL_EMERGE, + "cannot merge an object with an array", + &parser->err); + + return NULL; } - parser->state = UCL_STATE_KEY; + nobj = obj; + nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT; } - else { - if (obj == NULL) { - obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority); - } - else { - obj->type = UCL_ARRAY; + + if (!is_array) { + if (nobj->value.ov == NULL) { + nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); + if (nobj->value.ov == NULL) { + goto enomem1; + } } + parser->state = UCL_STATE_KEY; + } else { parser->state = UCL_STATE_VALUE; } st = UCL_ALLOC (sizeof (struct ucl_stack)); if (st == NULL) { - ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", + goto enomem1; + } + + st->obj = nobj; + + if (level >= UINT16_MAX) { + ucl_set_err (parser, UCL_ENESTED, + "objects are nesting too deep (over 65535 limit)", &parser->err); - ucl_object_unref (obj); + if (nobj != obj) { + ucl_object_unref (obj); + } + return NULL; } - st->obj = obj; - st->level = level; + + st->e.params.level = level; + st->e.params.line = parser->chunks->line; + st->chunk = parser->chunks; + + if (has_obrace) { + st->e.params.flags = UCL_STACK_HAS_OBRACE; + } + else { + st->e.params.flags = 0; + } + LL_PREPEND (parser->stack, st); - parser->cur_obj = obj; + parser->cur_obj = nobj; - return obj; + return nobj; +enomem1: + if (nobj != obj) + ucl_object_unref (nobj); +enomem0: + ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", + &parser->err); + return NULL; } int @@ -969,7 +1012,10 @@ ucl_lex_number (struct ucl_parser *parser, */ static bool ucl_lex_json_string (struct ucl_parser *parser, - struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand) + struct ucl_chunk *chunk, + bool *need_unescape, + bool *ucl_escape, + bool *var_expand) { const unsigned char *p = chunk->pos; unsigned char c; @@ -1009,7 +1055,8 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); } if (p >= chunk->end) { - ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", + ucl_set_err (parser, UCL_ESYNTAX, + "unfinished escape character", &parser->err); return false; } @@ -1035,7 +1082,54 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); } - ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string", + ucl_set_err (parser, UCL_ESYNTAX, + "no quote at the end of json string", + &parser->err); + return false; +} + +/** + * Process single quoted string + * @param parser + * @param chunk + * @param need_unescape + * @return + */ +static bool +ucl_lex_squoted_string (struct ucl_parser *parser, + struct ucl_chunk *chunk, bool *need_unescape) +{ + const unsigned char *p = chunk->pos; + unsigned char c; + + while (p < chunk->end) { + c = *p; + if (c == '\\') { + ucl_chunk_skipc (chunk, p); + + if (p >= chunk->end) { + ucl_set_err (parser, UCL_ESYNTAX, + "unfinished escape character", + &parser->err); + return false; + } + else { + ucl_chunk_skipc (chunk, p); + } + + *need_unescape = true; + continue; + } + else if (c == '\'') { + ucl_chunk_skipc (chunk, p); + return true; + } + + ucl_chunk_skipc (chunk, p); + } + + ucl_set_err (parser, UCL_ESYNTAX, + "no quote at the end of single quoted string", &parser->err); return false; } @@ -1075,15 +1169,26 @@ bool ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj) { ucl_hash_t *container; - ucl_object_t *tobj; + ucl_object_t *tobj = NULL, *cur; char errmsg[256]; container = parser->stack->obj->value.ov; - tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj)); + DL_FOREACH (parser->stack->obj, cur) { + tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (cur->value.ov, nobj)); + + if (tobj != NULL) { + break; + } + } + + if (tobj == NULL) { container = ucl_hash_insert_object (container, nobj, parser->flags & UCL_PARSER_KEY_LOWERCASE); + if (container == NULL) { + return false; + } nobj->prev = nobj; nobj->next = NULL; parser->stack->obj->len ++; @@ -1102,8 +1207,6 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj * - if a new object has bigger priority, then we overwrite an old one * - if a new object has lower priority, then we ignore it */ - - /* Special case for inherited objects */ if (tobj->flags & UCL_OBJECT_INHERITED) { prinew = priold + 1; @@ -1369,8 +1472,12 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, /* Create a new object */ nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); + if (nobj == NULL) { + return false; + } keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], - &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false); + &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, + false, false); if (keylen == -1) { ucl_object_unref (nobj); return false; @@ -1566,7 +1673,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) const unsigned char *p, *c; ucl_object_t *obj = NULL; unsigned int stripped_spaces; - int str_len; + ssize_t str_len; bool need_unescape = false, ucl_escape = false, var_expand = false; p = chunk->pos; @@ -1604,20 +1711,57 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE], &obj->value.sv, str_len, need_unescape, false, - var_expand)) == -1) { + var_expand, false)) == -1) { + return false; + } + + obj->len = str_len; + parser->state = UCL_STATE_AFTER_VALUE; + + return true; + break; + case '\'': + ucl_chunk_skipc (chunk, p); + + if (!ucl_lex_squoted_string (parser, chunk, &need_unescape)) { + return false; + } + + obj = ucl_parser_get_container (parser); + if (!obj) { + return false; + } + + str_len = chunk->pos - c - 2; + obj->type = UCL_STRING; + obj->flags |= UCL_OBJECT_SQUOTED; + + if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, + &obj->trash_stack[UCL_TRASH_VALUE], + &obj->value.sv, str_len, need_unescape, false, + var_expand, true)) == -1) { return false; } + obj->len = str_len; parser->state = UCL_STATE_AFTER_VALUE; - p = chunk->pos; return true; break; case '{': obj = ucl_parser_get_container (parser); + if (obj == NULL) { + return false; + } /* We have a new object */ - obj = ucl_parser_add_container (obj, parser, false, parser->stack->level); + if (parser->stack) { + obj = ucl_parser_add_container (obj, parser, false, + parser->stack->e.params.level, true); + } + else { + return false; + } if (obj == NULL) { return false; } @@ -1628,8 +1772,18 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) break; case '[': obj = ucl_parser_get_container (parser); + if (obj == NULL) { + return false; + } /* We have a new array */ - obj = ucl_parser_add_container (obj, parser, true, parser->stack->level); + if (parser->stack) { + obj = ucl_parser_add_container (obj, parser, true, + parser->stack->e.params.level, true); + } + else { + return false; + } + if (obj == NULL) { return false; } @@ -1660,8 +1814,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) } if (*p =='\n') { /* Set chunk positions and start multiline parsing */ + chunk->remain -= p - c + 1; c += 2; - chunk->remain -= p - c; chunk->pos = p + 1; chunk->column = 0; chunk->line ++; @@ -1677,7 +1831,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], &obj->value.sv, str_len - 1, false, - false, var_expand)) == -1) { + false, var_expand, false)) == -1) { return false; } obj->len = str_len; @@ -1689,6 +1843,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) } } /* Fallback to ordinary strings */ + /* FALLTHRU */ default: parse_string: if (obj == NULL) { @@ -1729,18 +1884,28 @@ parse_string: obj->len = 0; obj->type = UCL_NULL; } + else if (str_len == 3 && memcmp (c, "nan", 3) == 0) { + obj->len = 0; + obj->type = UCL_FLOAT; + obj->value.dv = NAN; + } + else if (str_len == 3 && memcmp (c, "inf", 3) == 0) { + obj->len = 0; + obj->type = UCL_FLOAT; + obj->value.dv = INFINITY; + } else if (!ucl_maybe_parse_boolean (obj, c, str_len)) { obj->type = UCL_STRING; if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], &obj->value.sv, str_len, need_unescape, - false, var_expand)) == -1) { + false, var_expand, false)) == -1) { return false; } obj->len = str_len; } + parser->state = UCL_STATE_AFTER_VALUE; - p = chunk->pos; return true; break; @@ -1792,6 +1957,17 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) /* Pop all nested objects from a stack */ st = parser->stack; + + if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) { + parser->err_code = UCL_EUNPAIRED; + ucl_create_err (&parser->err, + "%s:%d object closed with } is not opened with { at line %d", + chunk->fname ? chunk->fname : "memory", + parser->chunks->line, st->e.params.line); + + return false; + } + parser->stack = st->next; UCL_FREE (sizeof (struct ucl_stack), st); @@ -1802,10 +1978,14 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) while (parser->stack != NULL) { st = parser->stack; - if (st->next == NULL || st->next->level == st->level) { + if (st->next == NULL) { + break; + } + else if (st->next->e.params.level == st->e.params.level) { break; } + parser->stack = st->next; parser->cur_obj = st->obj; UCL_FREE (sizeof (struct ucl_stack), st); @@ -2180,6 +2360,8 @@ ucl_state_machine (struct ucl_parser *parser) return false; } else { + bool seen_obrace = false; + /* Skip any spaces */ while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { @@ -2188,23 +2370,33 @@ ucl_state_machine (struct ucl_parser *parser) p = chunk->pos; - if (*p == '[') { - parser->state = UCL_STATE_VALUE; - ucl_chunk_skipc (chunk, p); - } - else { - parser->state = UCL_STATE_KEY; - if (*p == '{') { + if (p < chunk->end) { + if (*p == '[') { + parser->state = UCL_STATE_VALUE; ucl_chunk_skipc (chunk, p); + seen_obrace = true; + } + else { + + if (*p == '{') { + ucl_chunk_skipc (chunk, p); + parser->state = UCL_STATE_KEY_OBRACE; + seen_obrace = true; + } + else { + parser->state = UCL_STATE_KEY; + } } } if (parser->top_obj == NULL) { if (parser->state == UCL_STATE_VALUE) { - obj = ucl_parser_add_container (NULL, parser, true, 0); + obj = ucl_parser_add_container (NULL, parser, true, 0, + seen_obrace); } else { - obj = ucl_parser_add_container (NULL, parser, false, 0); + obj = ucl_parser_add_container (NULL, parser, false, 0, + seen_obrace); } if (obj == NULL) { @@ -2218,6 +2410,7 @@ ucl_state_machine (struct ucl_parser *parser) } break; case UCL_STATE_KEY: + case UCL_STATE_KEY_OBRACE: /* Skip any spaces */ while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { ucl_chunk_skipc (chunk, p); @@ -2240,6 +2433,7 @@ ucl_state_machine (struct ucl_parser *parser) parser->state = UCL_STATE_ERROR; return false; } + if (end_of_object) { p = chunk->pos; parser->state = UCL_STATE_AFTER_VALUE; @@ -2248,8 +2442,11 @@ ucl_state_machine (struct ucl_parser *parser) else if (parser->state != UCL_STATE_MACRO_NAME) { if (next_key && parser->stack->obj->type == UCL_OBJECT) { /* Parse more keys and nest objects accordingly */ - obj = ucl_parser_add_container (parser->cur_obj, parser, false, - parser->stack->level + 1); + obj = ucl_parser_add_container (parser->cur_obj, + parser, + false, + parser->stack->e.params.level + 1, + parser->state == UCL_STATE_KEY_OBRACE); if (obj == NULL) { return false; } @@ -2301,7 +2498,8 @@ ucl_state_machine (struct ucl_parser *parser) 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", + "error at %s:%d at column %d: invalid macro", + chunk->fname ? chunk->fname : "memory", chunk->line, chunk->column); parser->state = UCL_STATE_ERROR; @@ -2324,8 +2522,9 @@ ucl_state_machine (struct ucl_parser *parser) HASH_FIND (hh, parser->macroes, c, macro_len, macro); if (macro == NULL) { ucl_create_err (&parser->err, - "error on line %d at column %d: " + "error at %s:%d at column %d: " "unknown macro: '%.*s', character: '%c'", + chunk->fname ? chunk->fname : "memory", chunk->line, chunk->column, (int) (p - c), @@ -2341,7 +2540,8 @@ ucl_state_machine (struct ucl_parser *parser) else { /* We have invalid macro name */ ucl_create_err (&parser->err, - "error on line %d at column %d: invalid macro name", + "error at %s:%d at column %d: invalid macro name", + chunk->fname ? chunk->fname : "memory", chunk->line, chunk->column); parser->state = UCL_STATE_ERROR; @@ -2440,9 +2640,43 @@ ucl_state_machine (struct ucl_parser *parser) } } + if (parser->stack != NULL && parser->state != UCL_STATE_ERROR) { + struct ucl_stack *st; + bool has_error = false; + + LL_FOREACH (parser->stack, st) { + if (st->chunk != parser->chunks) { + break; /* Not our chunk, give up */ + } + if (st->e.params.flags & UCL_STACK_HAS_OBRACE) { + if (parser->err == NULL) { + utstring_new (parser->err); + } + + utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ", + chunk->fname ? chunk->fname : "memory", + parser->chunks->line, + st->e.params.line); + + has_error = true; + } + } + + if (has_error) { + parser->err_code = UCL_EUNPAIRED; + + return false; + } + } + return true; } +#define UPRM_SAFE(fn, a, b, c, el) do { \ + if (!fn(a, b, c, a)) \ + goto el; \ + } while (0) + struct ucl_parser* ucl_parser_new (int flags) { @@ -2455,12 +2689,12 @@ ucl_parser_new (int flags) memset (parser, 0, sizeof (struct ucl_parser)); - 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); + UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0); + UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0); parser->flags = flags; parser->includepaths = NULL; @@ -2475,6 +2709,9 @@ ucl_parser_new (int flags) } return parser; +e0: + ucl_parser_free(parser); + return NULL; } bool @@ -2489,49 +2726,69 @@ ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio) return true; } -void +int +ucl_parser_get_default_priority (struct ucl_parser *parser) +{ + if (parser == NULL) { + return -1; + } + + return parser->default_priority; +} + +bool ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, ucl_macro_handler handler, void* ud) { struct ucl_macro *new; if (macro == NULL || handler == NULL) { - return; + return false; } new = UCL_ALLOC (sizeof (struct ucl_macro)); if (new == NULL) { - return; + return false; } memset (new, 0, sizeof (struct ucl_macro)); new->h.handler = handler; new->name = strdup (macro); + if (new->name == NULL) { + UCL_FREE (sizeof (struct ucl_macro), new); + return false; + } new->ud = ud; HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); + return true; } -void +bool ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro, ucl_context_macro_handler handler, void* ud) { struct ucl_macro *new; if (macro == NULL || handler == NULL) { - return; + return false; } new = UCL_ALLOC (sizeof (struct ucl_macro)); if (new == NULL) { - return; + return false; } memset (new, 0, sizeof (struct ucl_macro)); new->h.context_handler = handler; new->name = strdup (macro); + if (new->name == NULL) { + UCL_FREE (sizeof (struct ucl_macro), new); + return false; + } new->ud = ud; new->is_context = true; HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); + return true; } void @@ -2602,6 +2859,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, enum ucl_parse_type parse_type) { struct ucl_chunk *chunk; + struct ucl_parser_special_handler *special_handler; if (parser == NULL) { return false; @@ -2619,6 +2877,36 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, return false; } + memset (chunk, 0, sizeof (*chunk)); + + /* Apply all matching handlers from the first to the last */ + LL_FOREACH (parser->special_handlers, special_handler) { + if ((special_handler->flags & UCL_SPECIAL_HANDLER_PREPROCESS_ALL) || + (len >= special_handler->magic_len && + memcmp (data, special_handler->magic, special_handler->magic_len) == 0)) { + unsigned char *ndata = NULL; + size_t nlen = 0; + + if (!special_handler->handler (parser, data, len, &ndata, &nlen, + special_handler->user_data)) { + ucl_create_err (&parser->err, "call for external handler failed"); + return false; + } + + struct ucl_parser_special_handler_chain *nchain; + nchain = UCL_ALLOC (sizeof (*nchain)); + nchain->begin = ndata; + nchain->len = nlen; + nchain->special_handler = special_handler; + + /* Free order is reversed */ + LL_PREPEND (chunk->special_handlers, nchain); + + data = ndata; + len = nlen; + } + } + if (parse_type == UCL_PARSE_AUTO && len > 0) { /* We need to detect parse type by the first symbol */ if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) { @@ -2641,6 +2929,11 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, chunk->priority = priority; chunk->strategy = strat; chunk->parse_type = parse_type; + + if (parser->cur_file) { + chunk->fname = strdup (parser->cur_file); + } + LL_PREPEND (parser->chunks, chunk); parser->recursion ++; @@ -2707,6 +3000,41 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, } bool +ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data, + size_t len) +{ + if (parser == NULL || parser->top_obj == NULL) { + return false; + } + + bool res; + struct ucl_chunk *chunk; + + int state = parser->state; + parser->state = UCL_STATE_INIT; + + /* Prevent inserted chunks from unintentionally closing the current object */ + if (parser->stack != NULL && parser->stack->next != NULL) { + parser->stack->e.params.level = parser->stack->next->e.params.level; + } + + res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority, + parser->chunks->strategy, parser->chunks->parse_type); + + /* Remove chunk from the stack */ + chunk = parser->chunks; + if (chunk != NULL) { + parser->chunks = chunk->next; + ucl_chunk_free (chunk); + parser->recursion --; + } + + parser->state = state; + + return res; +} + +bool ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data, size_t len, unsigned priority) { @@ -2755,3 +3083,55 @@ ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths) return true; } + +unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser) +{ + if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL || + parser->chunks->pos == parser->chunks->end) { + return 0; + } + + return( *parser->chunks->pos ); +} + +bool ucl_parser_chunk_skip (struct ucl_parser *parser) +{ + if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL || + parser->chunks->pos == parser->chunks->end) { + return false; + } + + const unsigned char *p = parser->chunks->pos; + ucl_chunk_skipc( parser->chunks, p ); + if( parser->chunks->pos != NULL ) return true; + return false; +} + +ucl_object_t* +ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth) +{ + ucl_object_t *obj; + + if (parser == NULL || parser->stack == NULL) { + return NULL; + } + + struct ucl_stack *stack = parser->stack; + if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT) + { + return NULL; + } + + for( unsigned int i = 0; i < depth; ++i ) + { + stack = stack->next; + if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT) + { + return NULL; + } + } + + obj = ucl_object_ref (stack->obj); + return obj; +} + |