diff options
author | bapt <bapt@FreeBSD.org> | 2014-11-29 00:45:09 +0000 |
---|---|---|
committer | bapt <bapt@FreeBSD.org> | 2014-11-29 00:45:09 +0000 |
commit | 7d08b91413fa16522ce2fe9052df826886fe42e4 (patch) | |
tree | da7419ce979eaeb23133fbdfa13129abcde1cfc9 /contrib/libucl/src/ucl_parser.c | |
parent | 2aa5fef0aaa6b189fbabb79e67c84c76a4a40d3b (diff) | |
parent | 040f7be2fc3d89695611d460fd55d9b018fd7aa2 (diff) | |
download | FreeBSD-src-7d08b91413fa16522ce2fe9052df826886fe42e4.zip FreeBSD-src-7d08b91413fa16522ce2fe9052df826886fe42e4.tar.gz |
Update libucl to latest version
While here correctly link libucl to libm and register the dependency on libm
for static building
Diffstat (limited to 'contrib/libucl/src/ucl_parser.c')
-rw-r--r-- | contrib/libucl/src/ucl_parser.c | 422 |
1 files changed, 330 insertions, 92 deletions
diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c index e51a54b..0d118d8 100644 --- a/contrib/libucl/src/ucl_parser.c +++ b/contrib/libucl/src/ucl_parser.c @@ -26,8 +26,8 @@ #include "ucl_chartable.h" /** - * @file rcl_parser.c - * The implementation of rcl parser + * @file ucl_parser.c + * The implementation of ucl parser */ struct ucl_parser_saved_state { @@ -56,20 +56,33 @@ struct ucl_parser_saved_state { } while (0) static inline void -ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err) +ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err) { + const char *fmt_string, *filename; + struct ucl_chunk *chunk = parser->chunks; + + if (parser->cur_file) { + filename = parser->cur_file; + } + else { + filename = "<unknown>"; + } if (chunk->pos < chunk->end) { if (isgraph (*chunk->pos)) { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'", - chunk->line, chunk->column, str, *chunk->pos); + fmt_string = "error while parsing %s: " + "line: %d, column: %d - '%s', character: '%c'"; } else { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", - chunk->line, chunk->column, str, (int)*chunk->pos); + fmt_string = "error while parsing %s: " + "line: %d, column: %d - '%s', character: '0x%02x'"; } + ucl_create_err (err, fmt_string, + filename, chunk->line, chunk->column, + str, *chunk->pos); } else { - ucl_create_err (err, "error at the end of chunk: %s", str); + ucl_create_err (err, "error while parsing %s: at the end of chunk: %s", + filename, str); } } @@ -84,11 +97,12 @@ ucl_skip_comments (struct ucl_parser *parser) struct ucl_chunk *chunk = parser->chunks; const unsigned char *p; int comments_nested = 0; + bool quoted = false; p = chunk->pos; start: - if (*p == '#') { + if (chunk->remain > 0 && *p == '#') { if (parser->state != UCL_STATE_SCOMMENT && parser->state != UCL_STATE_MCOMMENT) { while (p < chunk->end) { @@ -100,34 +114,41 @@ start: } } } - else if (*p == '/' && chunk->remain >= 2) { + else if (chunk->remain >= 2 && *p == '/') { if (p[1] == '*') { ucl_chunk_skipc (chunk, p); comments_nested ++; ucl_chunk_skipc (chunk, p); while (p < chunk->end) { - if (*p == '*') { - ucl_chunk_skipc (chunk, p); - if (*p == '/') { - comments_nested --; - if (comments_nested == 0) { - ucl_chunk_skipc (chunk, p); - goto start; + if (*p == '"' && *(p - 1) != '\\') { + quoted = !quoted; + } + + if (!quoted) { + if (*p == '*') { + ucl_chunk_skipc (chunk, p); + if (*p == '/') { + comments_nested --; + if (comments_nested == 0) { + ucl_chunk_skipc (chunk, p); + goto start; + } } + ucl_chunk_skipc (chunk, p); + } + else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { + comments_nested ++; + ucl_chunk_skipc (chunk, p); + ucl_chunk_skipc (chunk, p); + continue; } - ucl_chunk_skipc (chunk, p); - } - else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { - comments_nested ++; - ucl_chunk_skipc (chunk, p); - ucl_chunk_skipc (chunk, p); - continue; } ucl_chunk_skipc (chunk, p); } if (comments_nested != 0) { - ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err); + ucl_set_err (parser, UCL_ENESTED, + "unfinished multiline comment", &parser->err); return false; } } @@ -492,7 +513,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser, /* Copy string */ *dst = UCL_ALLOC (in_len + 1); if (*dst == NULL) { - ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err); + ucl_set_err (parser, 0, "cannot allocate memory for a string", + &parser->err); return false; } if (need_lowercase) { @@ -514,6 +536,10 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser, *dst = tmp; ret = tret; } + else { + /* Free unexpanded value */ + UCL_FREE (in_len + 1, tmp); + } } *dst_const = *dst; } @@ -539,7 +565,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra if (!is_array) { if (obj == NULL) { - obj = ucl_object_typed_new (UCL_OBJECT); + obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority); } else { obj->type = UCL_OBJECT; @@ -549,7 +575,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra } else { if (obj == NULL) { - obj = ucl_object_typed_new (UCL_ARRAY); + obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority); } else { obj->type = UCL_ARRAY; @@ -559,7 +585,9 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra st = UCL_ALLOC (sizeof (struct ucl_stack)); if (st == NULL) { - ucl_set_err (parser->chunks, 0, "cannot allocate memory for an object", &parser->err); + ucl_set_err (parser, 0, "cannot allocate memory for an object", + &parser->err); + ucl_object_unref (obj); return NULL; } st->obj = obj; @@ -676,8 +704,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, } /* Now check endptr */ - if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' || - ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) { + if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { p = endptr; goto set_obj; } @@ -788,8 +815,21 @@ ucl_maybe_parse_number (ucl_object_t *obj, goto set_obj; } break; + case '\t': + case ' ': + while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) { + p++; + } + if (ucl_lex_is_atom_end(*p)) + goto set_obj; + break; } } + else if (endptr == end) { + /* Just a number at the end of chunk */ + p = endptr; + goto set_obj; + } *pos = c; return EINVAL; @@ -835,7 +875,7 @@ ucl_lex_number (struct ucl_parser *parser, return true; } else if (ret == ERANGE) { - ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err); + ucl_set_err (parser, ERANGE, "numeric value out of range", &parser->err); } return false; @@ -860,10 +900,12 @@ ucl_lex_json_string (struct ucl_parser *parser, if (c < 0x1F) { /* Unmasked control character */ if (c == '\n') { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline", + &parser->err); } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character", + &parser->err); } return false; } @@ -871,7 +913,8 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); c = *p; if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", + &parser->err); return false; } else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { @@ -879,13 +922,15 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); for (i = 0; i < 4 && p < chunk->end; i ++) { if (!isxdigit (*p)) { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape", + &parser->err); return false; } ucl_chunk_skipc (chunk, p); } if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", + &parser->err); return false; } } @@ -910,10 +955,42 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); } - ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string", + &parser->err); return false; } +static void +ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont, + ucl_object_t *top, + ucl_object_t *elt) +{ + ucl_object_t *nobj; + + if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) { + /* Implicit array */ + top->flags |= UCL_OBJECT_MULTIVALUE; + DL_APPEND (top, elt); + } + else { + if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) { + /* Just add to the explicit array */ + DL_APPEND (top->value.av, elt); + } + else { + /* Convert to an array */ + ucl_hash_delete (cont, top); + nobj = ucl_object_typed_new (UCL_ARRAY); + nobj->key = top->key; + nobj->keylen = top->keylen; + nobj->flags |= UCL_OBJECT_MULTIVALUE; + DL_APPEND (nobj->value.av, top); + DL_APPEND (nobj->value.av, elt); + ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen); + } + } +} + /** * Parse a key in an object * @param parser @@ -981,7 +1058,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke } else { /* Invalid identifier */ - ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter", + &parser->err); return false; } } @@ -997,7 +1075,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke break; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key", + &parser->err); return false; } } @@ -1015,7 +1094,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke } if (p >= chunk->end && got_content) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); return false; } else if (!got_content) { @@ -1033,7 +1112,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke got_eq = true; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character", + &parser->err); return false; } } @@ -1043,7 +1123,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke got_semicolon = true; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character", + &parser->err); return false; } } @@ -1061,7 +1142,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke } if (p >= chunk->end && got_content) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); return false; } @@ -1096,7 +1177,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke } /* Create a new object */ - nobj = ucl_object_new (); + nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); 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); if (keylen == -1) { @@ -1104,7 +1185,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke return false; } else if (keylen == 0) { - ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); ucl_object_unref (nobj); return false; } @@ -1120,7 +1201,27 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke parser->stack->obj->len ++; } else { - DL_APPEND (tobj, nobj); + /* + * The logic here is the following: + * + * - if we have two objects with the same priority, then we form an + * implicit or explicit array + * - if a new object has bigger priority, then we overwrite an old one + * - if a new object has lower priority, then we ignore it + */ + unsigned priold = ucl_object_get_priority (tobj), + prinew = ucl_object_get_priority (nobj); + if (priold == prinew) { + ucl_parser_append_elt (parser, container, tobj, nobj); + } + else if (priold > prinew) { + ucl_object_unref (nobj); + return true; + } + else { + ucl_hash_replace (container, tobj, nobj); + ucl_object_unref (tobj); + } } if (ucl_escape) { @@ -1197,11 +1298,6 @@ ucl_parse_string_value (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); } - if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err); - return false; - } - return true; } @@ -1219,7 +1315,7 @@ ucl_parse_multiline_string (struct ucl_parser *parser, int term_len, unsigned char const **beg, bool *var_expand) { - const unsigned char *p, *c; + const unsigned char *p, *c, *tend; bool newline = false; int len = 0; @@ -1232,7 +1328,13 @@ ucl_parse_multiline_string (struct ucl_parser *parser, if (chunk->end - p < term_len) { return 0; } - else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) { + else if (memcmp (p, term, term_len) == 0) { + tend = p + term_len; + if (*tend != '\n' && *tend != ';' && *tend != ',') { + /* Incomplete terminator */ + ucl_chunk_skipc (chunk, p); + continue; + } len = p - c; chunk->remain -= term_len; chunk->pos = p + term_len; @@ -1263,7 +1365,7 @@ ucl_get_value_object (struct ucl_parser *parser) if (parser->stack->obj->type == UCL_ARRAY) { /* Object must be allocated */ - obj = ucl_object_new (); + obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); t = parser->stack->obj->value.av; DL_APPEND (t, obj); parser->cur_obj = obj; @@ -1378,7 +1480,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) chunk->line ++; if ((str_len = ucl_parse_multiline_string (parser, chunk, c, p - c, &c, &var_expand)) == 0) { - ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, + "unterminated multiline value", &parser->err); return false; } obj->type = UCL_STRING; @@ -1423,7 +1526,8 @@ parse_string: } str_len = chunk->pos - c - stripped_spaces; if (str_len <= 0) { - ucl_set_err (chunk, 0, "string value must not be empty", &parser->err); + ucl_set_err (parser, 0, "string value must not be empty", + &parser->err); return false; } else if (str_len == 4 && memcmp (c, "null", 4) == 0) { @@ -1482,7 +1586,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { if (*p == '}' || *p == ']') { if (parser->stack == NULL) { - ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, + "end of array or object detected without corresponding start", + &parser->err); return false; } if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || @@ -1503,7 +1609,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) } } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, + "unexpected terminating symbol detected", + &parser->err); return false; } @@ -1525,7 +1633,8 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) else { /* Anything else */ if (!got_sep) { - ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing", + &parser->err); return false; } return true; @@ -1613,6 +1722,120 @@ ucl_parse_macro_value (struct ucl_parser *parser, } /** + * Parse macro arguments as UCL object + * @param parser parser structure + * @param chunk the current data chunk + * @return + */ +static ucl_object_t * +ucl_parse_macro_arguments (struct ucl_parser *parser, + struct ucl_chunk *chunk) +{ + ucl_object_t *res = NULL; + struct ucl_parser *params_parser; + int obraces = 1, ebraces = 0, state = 0; + const unsigned char *p, *c; + size_t args_len = 0; + struct ucl_parser_saved_state saved; + + saved.column = chunk->column; + saved.line = chunk->line; + saved.pos = chunk->pos; + saved.remain = chunk->remain; + p = chunk->pos; + + if (*p != '(' || chunk->remain < 2) { + return NULL; + } + + /* Set begin and start */ + ucl_chunk_skipc (chunk, p); + c = p; + + while ((p) < (chunk)->end) { + switch (state) { + case 0: + /* Parse symbols and check for '(', ')' and '"' */ + if (*p == '(') { + obraces ++; + } + else if (*p == ')') { + ebraces ++; + } + else if (*p == '"') { + state = 1; + } + /* Check pairing */ + if (obraces == ebraces) { + state = 99; + } + else { + args_len ++; + } + /* Check overflow */ + if (chunk->remain == 0) { + goto restore_chunk; + } + ucl_chunk_skipc (chunk, p); + break; + case 1: + /* We have quote character, so skip all but quotes */ + if (*p == '"' && *(p - 1) != '\\') { + state = 0; + } + if (chunk->remain == 0) { + goto restore_chunk; + } + ucl_chunk_skipc (chunk, p); + break; + case 99: + /* + * We have read the full body of arguments, so we need to parse and set + * object from that + */ + params_parser = ucl_parser_new (parser->flags); + if (!ucl_parser_add_chunk (params_parser, c, args_len)) { + ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error", + &parser->err); + } + else { + res = ucl_parser_get_object (params_parser); + } + ucl_parser_free (params_parser); + + return res; + + break; + } + } + + return res; + +restore_chunk: + chunk->column = saved.column; + chunk->line = saved.line; + chunk->pos = saved.pos; + chunk->remain = saved.remain; + + return NULL; +} + +#define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \ + while ((p) < (chunk)->end) { \ + if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \ + if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \ + if (!ucl_skip_comments (parser)) { \ + return false; \ + } \ + p = (chunk)->pos; \ + } \ + break; \ + } \ + ucl_chunk_skipc (chunk, p); \ + } \ +} while(0) + +/** * Handle the main states of rcl parser * @param parser parser structure * @param data the pointer to the beginning of a chunk @@ -1622,13 +1845,13 @@ ucl_parse_macro_value (struct ucl_parser *parser, static bool ucl_state_machine (struct ucl_parser *parser) { - ucl_object_t *obj; + ucl_object_t *obj, *macro_args; struct ucl_chunk *chunk = parser->chunks; const unsigned char *p, *c = NULL, *macro_start = NULL; unsigned char *macro_escaped; size_t macro_len = 0; struct ucl_macro *macro = NULL; - bool next_key = false, end_of_object = false; + bool next_key = false, end_of_object = false, ret; if (parser->top_obj == NULL) { if (*chunk->pos == '[') { @@ -1654,7 +1877,6 @@ ucl_state_machine (struct ucl_parser *parser) * if we got [ or { correspondingly or can just treat new data as * a key of newly created object */ - obj = parser->cur_obj; if (!ucl_skip_comments (parser)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; @@ -1691,7 +1913,7 @@ ucl_state_machine (struct ucl_parser *parser) } if (parser->stack == NULL) { /* No objects are on stack, but we want to parse a key */ - ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser " + ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser " "expects a key", &parser->err); parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; @@ -1757,7 +1979,8 @@ ucl_state_machine (struct ucl_parser *parser) p = chunk->pos; break; case UCL_STATE_MACRO_NAME: - if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { + if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && + *p != '(') { ucl_chunk_skipc (chunk, p); } else if (p - c > 0) { @@ -1772,48 +1995,51 @@ ucl_state_machine (struct ucl_parser *parser) return false; } /* Now we need to skip all spaces */ - while (p < chunk->end) { - if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { - /* Skip comment */ - if (!ucl_skip_comments (parser)) { - return false; - } - p = chunk->pos; - } - break; - } - ucl_chunk_skipc (chunk, p); - } + SKIP_SPACES_COMMENTS(parser, chunk, p); parser->state = UCL_STATE_MACRO; } break; case UCL_STATE_MACRO: + if (*chunk->pos == '(') { + macro_args = ucl_parse_macro_arguments (parser, chunk); + p = chunk->pos; + if (macro_args) { + SKIP_SPACES_COMMENTS(parser, chunk, p); + } + } + else { + macro_args = NULL; + } if (!ucl_parse_macro_value (parser, chunk, macro, ¯o_start, ¯o_len)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; } - macro_len = ucl_expand_variable (parser, ¯o_escaped, macro_start, macro_len); + macro_len = ucl_expand_variable (parser, ¯o_escaped, + macro_start, macro_len); parser->state = parser->prev_state; if (macro_escaped == NULL) { - if (!macro->handler (macro_start, macro_len, macro->ud)) { - return false; - } + ret = macro->handler (macro_start, macro_len, macro_args, + macro->ud); } else { - if (!macro->handler (macro_escaped, macro_len, macro->ud)) { - UCL_FREE (macro_len + 1, macro_escaped); - return false; - } + ret = macro->handler (macro_escaped, macro_len, macro_args, + macro->ud); UCL_FREE (macro_len + 1, macro_escaped); } p = chunk->pos; + if (macro_args) { + ucl_object_unref (macro_args); + } + if (!ret) { + return false; + } break; default: /* TODO: add all states */ - ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err); + ucl_set_err (parser, UCL_EINTERNAL, + "internal error: parser is in an unknown state", &parser->err); parser->state = UCL_STATE_ERROR; return false; } @@ -1888,7 +2114,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var, if (new != NULL) { /* Remove variable */ - LL_DELETE (parser->variables, new); + DL_DELETE (parser->variables, new); free (new->var); free (new->value); UCL_FREE (sizeof (struct ucl_variable), new); @@ -1910,7 +2136,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var, new->value = strdup (value); new->value_len = strlen (value); - LL_PREPEND (parser->variables, new); + DL_APPEND (parser->variables, new); } else { free (new->value); @@ -1929,15 +2155,19 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser, } bool -ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, - size_t len) +ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data, + size_t len, unsigned priority) { struct ucl_chunk *chunk; - if (data == NULL || len == 0) { + 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 (parser->state != UCL_STATE_ERROR) { chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); if (chunk == NULL) { @@ -1950,6 +2180,7 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, chunk->end = chunk->begin + len; chunk->line = 1; chunk->column = 0; + chunk->priority = priority; LL_PREPEND (parser->chunks, chunk); parser->recursion ++; if (parser->recursion > UCL_MAX_RECURSION) { @@ -1966,6 +2197,13 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, } bool +ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, + size_t len) +{ + return ucl_parser_add_chunk_priority (parser, data, len, 0); +} + +bool ucl_parser_add_string (struct ucl_parser *parser, const char *data, size_t len) { |