summaryrefslogtreecommitdiff
path: root/contrib/libucl/src/ucl_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libucl/src/ucl_parser.c')
-rw-r--r--contrib/libucl/src/ucl_parser.c476
1 files changed, 369 insertions, 107 deletions
diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c
index 75acba8ecbd3..9bd41391ba36 100644
--- a/contrib/libucl/src/ucl_parser.c
+++ b/contrib/libucl/src/ucl_parser.c
@@ -67,6 +67,7 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
else {
filename = "<unknown>";
}
+
if (chunk->pos < chunk->end) {
if (isgraph (*chunk->pos)) {
fmt_string = "error while parsing %s: "
@@ -84,6 +85,8 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
filename, str);
}
+
+ parser->err_code = code;
}
/**
@@ -513,7 +516,7 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
/* Copy string */
*dst = UCL_ALLOC (in_len + 1);
if (*dst == NULL) {
- ucl_set_err (parser, 0, "cannot allocate memory for a string",
+ ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
&parser->err);
return false;
}
@@ -559,7 +562,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
* @return
*/
static inline ucl_object_t *
-ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level)
+ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
+ bool is_array, int level)
{
struct ucl_stack *st;
@@ -570,7 +574,9 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
else {
obj->type = UCL_OBJECT;
}
- obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+ if (obj->value.ov == NULL) {
+ obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+ }
parser->state = UCL_STATE_KEY;
}
else {
@@ -585,7 +591,7 @@ 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, 0, "cannot allocate memory for an object",
+ ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
&parser->err);
ucl_object_unref (obj);
return NULL;
@@ -834,19 +840,21 @@ ucl_maybe_parse_number (ucl_object_t *obj,
*pos = c;
return EINVAL;
- set_obj:
- if (allow_double && (need_double || is_time)) {
- if (!is_time) {
- obj->type = UCL_FLOAT;
+set_obj:
+ if (obj != NULL) {
+ if (allow_double && (need_double || is_time)) {
+ if (!is_time) {
+ obj->type = UCL_FLOAT;
+ }
+ else {
+ obj->type = UCL_TIME;
+ }
+ obj->value.dv = is_neg ? (-dv) : dv;
}
else {
- obj->type = UCL_TIME;
+ obj->type = UCL_INT;
+ obj->value.iv = is_neg ? (-lv) : lv;
}
- obj->value.dv = is_neg ? (-dv) : dv;
- }
- else {
- obj->type = UCL_INT;
- obj->value.iv = is_neg ? (-lv) : lv;
}
*pos = p;
return 0;
@@ -856,6 +864,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
* Parse possible number
* @param parser
* @param chunk
+ * @param obj
* @return true if a number has been parsed
*/
static bool
@@ -875,7 +884,8 @@ ucl_lex_number (struct ucl_parser *parser,
return true;
}
else if (ret == ERANGE) {
- ucl_set_err (parser, ERANGE, "numeric value out of range", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
+ &parser->err);
}
return false;
@@ -885,6 +895,9 @@ ucl_lex_number (struct ucl_parser *parser,
* Parse quoted string with possible escapes
* @param parser
* @param chunk
+ * @param need_unescape
+ * @param ucl_escape
+ * @param var_expand
* @return true if a string has been parsed
*/
static bool
@@ -971,6 +984,7 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
/* Implicit array */
top->flags |= UCL_OBJECT_MULTIVALUE;
DL_APPEND (top, elt);
+ parser->stack->obj->len ++;
}
else {
if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
@@ -979,34 +993,127 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
}
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;
ucl_array_append (nobj, top);
ucl_array_append (nobj, elt);
- ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen);
+ ucl_hash_replace (cont, top, nobj);
+ }
+ }
+}
+
+bool
+ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
+{
+ ucl_hash_t *container;
+ ucl_object_t *tobj;
+
+ container = parser->stack->obj->value.ov;
+
+ tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
+ if (tobj == NULL) {
+ container = ucl_hash_insert_object (container, nobj,
+ parser->flags & UCL_PARSER_KEY_LOWERCASE);
+ nobj->prev = nobj;
+ nobj->next = NULL;
+ parser->stack->obj->len ++;
+ }
+ else {
+ unsigned priold = ucl_object_get_priority (tobj),
+ prinew = ucl_object_get_priority (nobj);
+ switch (parser->chunks->strategy) {
+
+ case UCL_DUPLICATE_APPEND:
+ /*
+ * 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
+ */
+
+
+ /* Special case for inherited objects */
+ if (tobj->flags & UCL_OBJECT_INHERITED) {
+ prinew = priold + 1;
+ }
+
+ if (priold == prinew) {
+ ucl_parser_append_elt (parser, container, tobj, nobj);
+ }
+ else if (priold > prinew) {
+ /*
+ * We add this new object to a list of trash objects just to ensure
+ * that it won't come to any real object
+ * XXX: rather inefficient approach
+ */
+ DL_APPEND (parser->trash_objs, nobj);
+ }
+ else {
+ ucl_hash_replace (container, tobj, nobj);
+ ucl_object_unref (tobj);
+ }
+
+ break;
+
+ case UCL_DUPLICATE_REWRITE:
+ /* We just rewrite old values regardless of priority */
+ ucl_hash_replace (container, tobj, nobj);
+ ucl_object_unref (tobj);
+
+ break;
+
+ case UCL_DUPLICATE_ERROR:
+ ucl_create_err (&parser->err, "error while parsing %s: "
+ "line: %d, column: %d: duplicate element for key '%s' "
+ "has been found",
+ parser->cur_file ? parser->cur_file : "<unknown>",
+ parser->chunks->line, parser->chunks->column, nobj->key);
+ return false;
+
+ case UCL_DUPLICATE_MERGE:
+ /*
+ * Here we do have some old object so we just push it on top of objects stack
+ */
+ if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
+ ucl_object_unref (nobj);
+ nobj = tobj;
+ }
+ else {
+ /* For other types we create implicit array as usual */
+ ucl_parser_append_elt (parser, container, tobj, nobj);
+ }
+ break;
}
}
+
+ parser->stack->obj->value.ov = container;
+ parser->cur_obj = nobj;
+
+ return true;
}
/**
* Parse a key in an object
* @param parser
* @param chunk
+ * @param next_key
+ * @param end_of_object
* @return true if a key has been parsed
*/
static bool
-ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object)
+ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
+ bool *next_key, bool *end_of_object)
{
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;
- ucl_object_t *nobj, *tobj;
- ucl_hash_t *container;
+ ucl_object_t *nobj;
ssize_t keylen;
p = chunk->pos;
@@ -1191,47 +1298,17 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
return false;
}
- container = parser->stack->obj->value.ov;
nobj->key = key;
nobj->keylen = keylen;
- tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
- if (tobj == NULL) {
- container = ucl_hash_insert_object (container, nobj,
- parser->flags & UCL_PARSER_KEY_LOWERCASE);
- nobj->prev = nobj;
- nobj->next = NULL;
- parser->stack->obj->len ++;
- }
- else {
- /*
- * 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_parser_process_object_element (parser, nobj)) {
+ return false;
}
if (ucl_escape) {
nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
}
- parser->stack->obj->value.ov = container;
- parser->cur_obj = nobj;
return true;
}
@@ -1240,6 +1317,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
* Parse a cl string
* @param parser
* @param chunk
+ * @param var_expand
+ * @param need_unescape
* @return true if a key has been parsed
*/
static bool
@@ -1309,6 +1388,8 @@ ucl_parse_string_value (struct ucl_parser *parser,
* @param chunk
* @param term
* @param term_len
+ * @param beg
+ * @param var_expand
* @return size of multiline string or 0 in case of error
*/
static int
@@ -1360,8 +1441,8 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
return len;
}
-static ucl_object_t*
-ucl_get_value_object (struct ucl_parser *parser)
+static inline ucl_object_t*
+ucl_parser_get_container (struct ucl_parser *parser)
{
ucl_object_t *t, *obj = NULL;
@@ -1373,7 +1454,12 @@ ucl_get_value_object (struct ucl_parser *parser)
/* Object must be allocated */
obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
t = parser->stack->obj;
- ucl_array_append (t, obj);
+
+ if (!ucl_array_append (t, obj)) {
+ ucl_object_unref (obj);
+ return NULL;
+ }
+
parser->cur_obj = obj;
}
else {
@@ -1417,42 +1503,51 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
c = p;
switch (*p) {
case '"':
- obj = ucl_get_value_object (parser);
ucl_chunk_skipc (chunk, p);
- if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
+
+ if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
+ &var_expand)) {
return false;
}
+
+ obj = ucl_parser_get_container (parser);
str_len = chunk->pos - c - 2;
obj->type = UCL_STRING;
- 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) {
+ 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) {
return false;
}
obj->len = str_len;
+
parser->state = UCL_STATE_AFTER_VALUE;
p = chunk->pos;
+
return true;
break;
case '{':
- obj = ucl_get_value_object (parser);
+ obj = ucl_parser_get_container (parser);
/* We have a new object */
- obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
+ obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
if (obj == NULL) {
return false;
}
ucl_chunk_skipc (chunk, p);
+
return true;
break;
case '[':
- obj = ucl_get_value_object (parser);
+ obj = ucl_parser_get_container (parser);
/* We have a new array */
- obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
+ obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
if (obj == NULL) {
return false;
}
ucl_chunk_skipc (chunk, p);
+
return true;
break;
case ']':
@@ -1466,7 +1561,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
}
break;
case '<':
- obj = ucl_get_value_object (parser);
+ obj = ucl_parser_get_container (parser);
/* We have something like multiline value, which must be <<[A-Z]+\n */
if (chunk->end - p > 3) {
if (memcmp (p, "<<", 2) == 0) {
@@ -1488,13 +1583,19 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
"unterminated multiline value", &parser->err);
return false;
}
+
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 - 1, false, false, var_expand)) == -1) {
+ obj->flags |= UCL_OBJECT_MULTILINE;
+ 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) {
return false;
}
obj->len = str_len;
+
parser->state = UCL_STATE_AFTER_VALUE;
+
return true;
}
}
@@ -1503,8 +1604,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
default:
parse_string:
if (obj == NULL) {
- obj = ucl_get_value_object (parser);
+ obj = ucl_parser_get_container (parser);
}
+
/* Parse atom */
if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
if (!ucl_lex_number (parser, chunk, obj)) {
@@ -1519,7 +1621,8 @@ parse_string:
/* Fallback to normal string */
}
- if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) {
+ if (!ucl_parse_string_value (parser, chunk, &var_expand,
+ &need_unescape)) {
return false;
}
/* Cut trailing spaces */
@@ -1530,7 +1633,7 @@ parse_string:
}
str_len = chunk->pos - c - stripped_spaces;
if (str_len <= 0) {
- ucl_set_err (parser, 0, "string value must not be empty",
+ ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
&parser->err);
return false;
}
@@ -1540,7 +1643,8 @@ parse_string:
}
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],
+ 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) {
return false;
@@ -1652,6 +1756,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
* Handle macro data
* @param parser
* @param chunk
+ * @param marco
+ * @param macro_start
+ * @param macro_len
* @return
*/
static bool
@@ -1790,6 +1897,7 @@ ucl_parse_macro_arguments (struct ucl_parser *parser,
if (chunk->remain == 0) {
goto restore_chunk;
}
+ args_len ++;
ucl_chunk_skipc (chunk, p);
break;
case 99:
@@ -1842,8 +1950,6 @@ restore_chunk:
/**
* Handle the main states of rcl parser
* @param parser parser structure
- * @param data the pointer to the beginning of a chunk
- * @param len the length of a chunk
* @return true if chunk has been parsed and false in case of error
*/
static bool
@@ -1858,17 +1964,6 @@ ucl_state_machine (struct ucl_parser *parser)
bool next_key = false, end_of_object = false, ret;
if (parser->top_obj == NULL) {
- if (*chunk->pos == '[') {
- obj = ucl_add_parser_stack (NULL, parser, true, 0);
- }
- else {
- obj = ucl_add_parser_stack (NULL, parser, false, 0);
- }
- if (obj == NULL) {
- return false;
- }
- parser->top_obj = obj;
- parser->cur_obj = obj;
parser->state = UCL_STATE_INIT;
}
@@ -1892,7 +1987,9 @@ ucl_state_machine (struct ucl_parser *parser)
UCL_CHARACTER_WHITESPACE_UNSAFE)) {
ucl_chunk_skipc (chunk, p);
}
+
p = chunk->pos;
+
if (*p == '[') {
parser->state = UCL_STATE_VALUE;
ucl_chunk_skipc (chunk, p);
@@ -1903,6 +2000,23 @@ ucl_state_machine (struct ucl_parser *parser)
ucl_chunk_skipc (chunk, p);
}
}
+
+ if (parser->top_obj == NULL) {
+ if (parser->state == UCL_STATE_VALUE) {
+ obj = ucl_parser_add_container (NULL, parser, true, 0);
+ }
+ else {
+ obj = ucl_parser_add_container (NULL, parser, false, 0);
+ }
+
+ if (obj == NULL) {
+ return false;
+ }
+
+ parser->top_obj = obj;
+ parser->cur_obj = obj;
+ }
+
}
break;
case UCL_STATE_KEY:
@@ -1936,7 +2050,7 @@ 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_add_parser_stack (parser->cur_obj, parser, false,
+ obj = ucl_parser_add_container (parser->cur_obj, parser, false,
parser->stack->level + 1);
if (obj == NULL) {
return false;
@@ -1967,6 +2081,7 @@ ucl_state_machine (struct ucl_parser *parser)
parser->state = UCL_STATE_ERROR;
return false;
}
+
if (parser->stack != NULL) {
if (parser->stack->obj->type == UCL_OBJECT) {
parser->state = UCL_STATE_KEY;
@@ -1987,20 +2102,36 @@ ucl_state_machine (struct ucl_parser *parser)
*p != '(') {
ucl_chunk_skipc (chunk, p);
}
- else if (p - c > 0) {
- /* We got macro name */
- macro_len = (size_t)(p - c);
- HASH_FIND (hh, parser->macroes, c, macro_len, macro);
- if (macro == NULL) {
- ucl_create_err (&parser->err, "error on line %d at column %d: "
- "unknown macro: '%.*s', character: '%c'",
- chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
+ else {
+ if (p - c > 0) {
+ /* We got macro name */
+ macro_len = (size_t) (p - c);
+ HASH_FIND (hh, parser->macroes, c, macro_len, macro);
+ if (macro == NULL) {
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: "
+ "unknown macro: '%.*s', character: '%c'",
+ chunk->line,
+ chunk->column,
+ (int) (p - c),
+ c,
+ *chunk->pos);
+ parser->state = UCL_STATE_ERROR;
+ return false;
+ }
+ /* Now we need to skip all spaces */
+ SKIP_SPACES_COMMENTS(parser, chunk, p);
+ parser->state = UCL_STATE_MACRO;
+ }
+ else {
+ /* We have invalid macro name */
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: invalid macro name",
+ chunk->line,
+ chunk->column);
parser->state = UCL_STATE_ERROR;
return false;
}
- /* Now we need to skip all spaces */
- SKIP_SPACES_COMMENTS(parser, chunk, p);
- parser->state = UCL_STATE_MACRO;
}
break;
case UCL_STATE_MACRO:
@@ -2024,14 +2155,36 @@ ucl_state_machine (struct ucl_parser *parser)
macro_start, macro_len);
parser->state = parser->prev_state;
if (macro_escaped == NULL) {
- ret = macro->handler (macro_start, macro_len, macro_args,
- macro->ud);
+ if (macro->is_context) {
+ ret = macro->h.context_handler (macro_start, macro_len,
+ macro_args,
+ parser->top_obj,
+ macro->ud);
+ }
+ else {
+ ret = macro->h.handler (macro_start, macro_len, macro_args,
+ macro->ud);
+ }
}
else {
- ret = macro->handler (macro_escaped, macro_len, macro_args,
+ if (macro->is_context) {
+ ret = macro->h.context_handler (macro_escaped, macro_len,
+ macro_args,
+ parser->top_obj,
+ macro->ud);
+ }
+ else {
+ ret = macro->h.handler (macro_escaped, macro_len, macro_args,
macro->ud);
+ }
+
UCL_FREE (macro_len + 1, macro_escaped);
}
+
+ /*
+ * Chunk can be modified within macro handler
+ */
+ chunk = parser->chunks;
p = chunk->pos;
if (macro_args) {
ucl_object_unref (macro_args);
@@ -2061,13 +2214,18 @@ ucl_parser_new (int flags)
if (new == NULL) {
return NULL;
}
+
memset (new, 0, sizeof (struct ucl_parser));
ucl_parser_register_macro (new, "include", ucl_include_handler, new);
ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
+ ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
+ ucl_parser_register_macro (new, "load", ucl_load_handler, new);
+ ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
new->flags = flags;
+ new->includepaths = NULL;
/* Initial assumption about filevars */
ucl_parser_set_filevars (new, NULL, false);
@@ -2075,6 +2233,17 @@ ucl_parser_new (int flags)
return new;
}
+bool
+ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
+{
+ if (parser == NULL) {
+ return false;
+ }
+
+ parser->default_priority = prio;
+
+ return true;
+}
void
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
@@ -2085,14 +2254,39 @@ ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
if (macro == NULL || handler == NULL) {
return;
}
+
+ new = UCL_ALLOC (sizeof (struct ucl_macro));
+ if (new == NULL) {
+ return;
+ }
+
+ memset (new, 0, sizeof (struct ucl_macro));
+ new->h.handler = handler;
+ new->name = strdup (macro);
+ new->ud = ud;
+ HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
+}
+
+void
+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;
+ }
+
new = UCL_ALLOC (sizeof (struct ucl_macro));
if (new == NULL) {
return;
}
+
memset (new, 0, sizeof (struct ucl_macro));
- new->handler = handler;
+ new->h.context_handler = handler;
new->name = strdup (macro);
new->ud = ud;
+ new->is_context = true;
HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
}
@@ -2159,11 +2353,16 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser,
}
bool
-ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data,
- size_t len, unsigned priority)
+ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
+ size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
+ enum ucl_parse_type parse_type)
{
struct ucl_chunk *chunk;
+ if (parser == NULL) {
+ return false;
+ }
+
if (data == NULL) {
ucl_create_err (&parser->err, "invalid chunk added");
return false;
@@ -2185,14 +2384,24 @@ ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *d
chunk->line = 1;
chunk->column = 0;
chunk->priority = priority;
+ chunk->strategy = strat;
+ chunk->parse_type = parse_type;
LL_PREPEND (parser->chunks, chunk);
parser->recursion ++;
+
if (parser->recursion > UCL_MAX_RECURSION) {
ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
parser->recursion);
return false;
}
- return ucl_state_machine (parser);
+
+ switch (parse_type) {
+ default:
+ case UCL_PARSE_UCL:
+ return ucl_state_machine (parser);
+ case UCL_PARSE_MSGPACK:
+ return ucl_parse_msgpack (parser);
+ }
}
ucl_create_err (&parser->err, "a parser is in an invalid state");
@@ -2201,15 +2410,33 @@ ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *d
}
bool
+ucl_parser_add_chunk_priority (struct ucl_parser *parser,
+ const unsigned char *data, size_t len, unsigned priority)
+{
+ /* We dereference parser, so this check is essential */
+ if (parser == NULL) {
+ return false;
+ }
+
+ return ucl_parser_add_chunk_full (parser, data, len,
+ priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
+}
+
+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);
+ if (parser == NULL) {
+ return false;
+ }
+
+ return ucl_parser_add_chunk_full (parser, data, len,
+ parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
}
bool
-ucl_parser_add_string (struct ucl_parser *parser, const char *data,
- size_t len)
+ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
+ size_t len, unsigned priority)
{
if (data == NULL) {
ucl_create_err (&parser->err, "invalid string added");
@@ -2219,5 +2446,40 @@ ucl_parser_add_string (struct ucl_parser *parser, const char *data,
len = strlen (data);
}
- return ucl_parser_add_chunk (parser, (const unsigned char *)data, len);
+ return ucl_parser_add_chunk_priority (parser,
+ (const unsigned char *)data, len, priority);
+}
+
+bool
+ucl_parser_add_string (struct ucl_parser *parser, const char *data,
+ size_t len)
+{
+ if (parser == NULL) {
+ return false;
+ }
+
+ return ucl_parser_add_string_priority (parser,
+ (const unsigned char *)data, len, parser->default_priority);
+}
+
+bool
+ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
+{
+ if (parser == NULL || paths == NULL) {
+ return false;
+ }
+
+ if (parser->includepaths == NULL) {
+ parser->includepaths = ucl_object_copy (paths);
+ }
+ else {
+ ucl_object_unref (parser->includepaths);
+ parser->includepaths = ucl_object_copy (paths);
+ }
+
+ if (parser->includepaths == NULL) {
+ return false;
+ }
+
+ return true;
}