summaryrefslogtreecommitdiffstats
path: root/contrib/libucl/src/ucl_parser.c
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2014-11-29 00:45:09 +0000
committerbapt <bapt@FreeBSD.org>2014-11-29 00:45:09 +0000
commit7d08b91413fa16522ce2fe9052df826886fe42e4 (patch)
treeda7419ce979eaeb23133fbdfa13129abcde1cfc9 /contrib/libucl/src/ucl_parser.c
parent2aa5fef0aaa6b189fbabb79e67c84c76a4a40d3b (diff)
parent040f7be2fc3d89695611d460fd55d9b018fd7aa2 (diff)
downloadFreeBSD-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.c422
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,
&macro_start, &macro_len)) {
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
return false;
}
- macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
+ macro_len = ucl_expand_variable (parser, &macro_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)
{
OpenPOWER on IntegriCloud