|
|
@@ -348,8 +348,9 @@ 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; |
|
|
|
*found = true; |
|
|
|
*out_len = dstlen; |
|
|
|
|
|
|
|
if (need_free) { |
|
|
|
free (dst); |
|
|
|
} |
|
|
@@ -880,6 +881,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, |
|
|
|
} |
|
|
|
|
|
|
|
if (endptr < end && endptr != start) { |
|
|
|
p = endptr; |
|
|
|
switch (*p) { |
|
|
|
case 'm': |
|
|
|
case 'M': |
|
|
@@ -1358,24 +1360,20 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj |
|
|
|
*/ |
|
|
|
static bool |
|
|
|
ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, |
|
|
|
bool *next_key, bool *end_of_object) |
|
|
|
bool *next_key, bool *end_of_object, bool *got_content) |
|
|
|
{ |
|
|
|
const unsigned char *p, *c = NULL, *end, *t; |
|
|
|
const char *key = NULL; |
|
|
|
bool got_quote = false, got_eq = false, got_semicolon = false, |
|
|
|
need_unescape = false, ucl_escape = false, var_expand = false, |
|
|
|
got_content = false, got_sep = false; |
|
|
|
got_sep = false; |
|
|
|
ucl_object_t *nobj; |
|
|
|
ssize_t keylen; |
|
|
|
|
|
|
|
p = chunk->pos; |
|
|
|
|
|
|
|
if (*p == '.') { |
|
|
|
/* It is macro actually */ |
|
|
|
if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) { |
|
|
|
ucl_chunk_skipc (chunk, p); |
|
|
|
} |
|
|
|
|
|
|
|
if (*p == '.' && !(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; |
|
|
@@ -1399,13 +1397,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, |
|
|
|
/* The first symbol */ |
|
|
|
c = p; |
|
|
|
ucl_chunk_skipc (chunk, p); |
|
|
|
got_content = true; |
|
|
|
*got_content = true; |
|
|
|
} |
|
|
|
else if (*p == '"') { |
|
|
|
/* JSON style key */ |
|
|
|
c = p + 1; |
|
|
|
got_quote = true; |
|
|
|
got_content = true; |
|
|
|
*got_content = true; |
|
|
|
ucl_chunk_skipc (chunk, p); |
|
|
|
} |
|
|
|
else if (*p == '}') { |
|
|
@@ -1413,7 +1411,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, |
|
|
|
*end_of_object = true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
else if (*p == '.') { |
|
|
|
else if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) { |
|
|
|
ucl_chunk_skipc (chunk, p); |
|
|
|
parser->prev_state = parser->state; |
|
|
|
parser->state = UCL_STATE_MACRO_NAME; |
|
|
@@ -1430,7 +1428,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, |
|
|
|
/* Parse the body of a key */ |
|
|
|
if (!got_quote) { |
|
|
|
if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { |
|
|
|
got_content = true; |
|
|
|
*got_content = true; |
|
|
|
ucl_chunk_skipc (chunk, p); |
|
|
|
} |
|
|
|
else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { |
|
|
@@ -1456,11 +1454,11 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (p >= chunk->end && got_content) { |
|
|
|
if (p >= chunk->end && *got_content) { |
|
|
|
ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
else if (!got_content) { |
|
|
|
else if (!*got_content) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
*end_of_object = false; |
|
|
@@ -1821,6 +1819,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) |
|
|
|
case '{': |
|
|
|
obj = ucl_parser_get_container (parser); |
|
|
|
if (obj == NULL) { |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
ucl_set_err(parser, UCL_ESYNTAX, "object value must be a part of an object", |
|
|
|
&parser->err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
/* We have a new object */ |
|
|
@@ -1842,6 +1843,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) |
|
|
|
case '[': |
|
|
|
obj = ucl_parser_get_container (parser); |
|
|
|
if (obj == NULL) { |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
ucl_set_err(parser, UCL_ESYNTAX, "array value must be a part of an object", |
|
|
|
&parser->err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
/* We have a new array */ |
|
|
@@ -1873,6 +1877,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) |
|
|
|
break; |
|
|
|
case '<': |
|
|
|
obj = ucl_parser_get_container (parser); |
|
|
|
if (obj == NULL) { |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
ucl_set_err(parser, UCL_ESYNTAX, "multiline value must be a part of an object", |
|
|
|
&parser->err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
/* We have something like multiline value, which must be <<[A-Z]+\n */ |
|
|
|
if (chunk->end - p > 3) { |
|
|
|
if (memcmp (p, "<<", 2) == 0) { |
|
|
@@ -1924,6 +1934,13 @@ parse_string: |
|
|
|
obj = ucl_parser_get_container (parser); |
|
|
|
} |
|
|
|
|
|
|
|
if (obj == NULL) { |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
ucl_set_err(parser, UCL_ESYNTAX, "value must be a part of an object", |
|
|
|
&parser->err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/* Parse atom */ |
|
|
|
if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { |
|
|
|
if (!ucl_lex_number (parser, chunk, obj)) { |
|
|
@@ -2413,7 +2430,7 @@ ucl_state_machine (struct ucl_parser *parser) |
|
|
|
unsigned char *macro_escaped; |
|
|
|
size_t macro_len = 0; |
|
|
|
struct ucl_macro *macro = NULL; |
|
|
|
bool next_key = false, end_of_object = false, ret; |
|
|
|
bool next_key = false, end_of_object = false, got_content = false, ret; |
|
|
|
|
|
|
|
if (parser->top_obj == NULL) { |
|
|
|
parser->state = UCL_STATE_INIT; |
|
|
@@ -2502,7 +2519,10 @@ ucl_state_machine (struct ucl_parser *parser) |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { |
|
|
|
|
|
|
|
got_content = false; |
|
|
|
|
|
|
|
if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object, &got_content)) { |
|
|
|
parser->prev_state = parser->state; |
|
|
|
parser->state = UCL_STATE_ERROR; |
|
|
|
return false; |
|
|
@@ -2525,7 +2545,8 @@ ucl_state_machine (struct ucl_parser *parser) |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else if (got_content) { |
|
|
|
/* Do not switch state if we have not read any content */ |
|
|
|
parser->state = UCL_STATE_VALUE; |
|
|
|
} |
|
|
|
} |
|
|
@@ -2691,6 +2712,9 @@ ucl_state_machine (struct ucl_parser *parser) |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
case UCL_STATE_ERROR: |
|
|
|
/* Already in the error state */ |
|
|
|
return false; |
|
|
|
default: |
|
|
|
ucl_set_err (parser, UCL_EINTERNAL, |
|
|
|
"internal error: parser is in an unknown state", &parser->err); |