Browse Source

[Fix] Backport multiple fixes from libucl

pull/4935/head
Vsevolod Stakhov 2 weeks ago
parent
commit
e06474f8e8
No account linked to committer's email address
1 changed files with 42 additions and 18 deletions
  1. 42
    18
      contrib/libucl/ucl_parser.c

+ 42
- 18
contrib/libucl/ucl_parser.c View File

@@ -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);

Loading…
Cancel
Save