#define MSGPACK_FLAG_EXT (1 << 3)
#define MSGPACK_FLAG_ASSOC (1 << 4)
#define MSGPACK_FLAG_KEY (1 << 5)
-#define MSGPACK_CONTAINER_BIT (1ULL << 62)
/*
* Search tree packed in array
assert (obj_parser != NULL);
if (obj_parser->flags & MSGPACK_FLAG_CONTAINER) {
- assert ((len & MSGPACK_CONTAINER_BIT) == 0);
/*
* Insert new container to the stack
*/
ucl_create_err (&parser->err, "no memory");
return NULL;
}
+
+ parser->stack->chunk = parser->chunks;
}
else {
stack = calloc (1, sizeof (struct ucl_stack));
return NULL;
}
+ stack->chunk = parser->chunks;
stack->next = parser->stack;
parser->stack = stack;
}
- parser->stack->level = len | MSGPACK_CONTAINER_BIT;
+ parser->stack->e.len = len;
#ifdef MSGPACK_DEBUG_PARSER
stack = parser->stack;
static bool
ucl_msgpack_is_container_finished (struct ucl_stack *container)
{
- uint64_t level;
-
assert (container != NULL);
- if (container->level & MSGPACK_CONTAINER_BIT) {
- level = container->level & ~MSGPACK_CONTAINER_BIT;
- if (level == 0) {
- return true;
- }
+ if (container->e.len == 0) {
+ return true;
}
return false;
const unsigned char *key,
size_t keylen, ucl_object_t *obj)
{
- uint64_t level;
struct ucl_stack *container;
container = parser->stack;
assert (container != NULL);
- assert (container->level > 0);
+ assert (container->e.len > 0);
assert (obj != NULL);
assert (container->obj != NULL);
return false;
}
- if (container->level & MSGPACK_CONTAINER_BIT) {
- level = container->level & ~MSGPACK_CONTAINER_BIT;
- container->level = (level - 1) | MSGPACK_CONTAINER_BIT;
- }
+ container->e.len--;
return true;
}
ucl_msgpack_get_next_container (struct ucl_parser *parser)
{
struct ucl_stack *cur = NULL;
- uint64_t level;
+ uint64_t len;
cur = parser->stack;
return NULL;
}
- if (cur->level & MSGPACK_CONTAINER_BIT) {
- level = cur->level & ~MSGPACK_CONTAINER_BIT;
+ len = cur->e.len;
- if (level == 0) {
- /* We need to switch to the previous container */
- parser->stack = cur->next;
- parser->cur_obj = cur->obj;
- free (cur);
+ if (len == 0) {
+ /* We need to switch to the previous container */
+ parser->stack = cur->next;
+ parser->cur_obj = cur->obj;
+ free (cur);
#ifdef MSGPACK_DEBUG_PARSER
- cur = parser->stack;
+ cur = parser->stack;
while (cur) {
fprintf(stderr, "-");
cur = cur->next;
fprintf(stderr, "-%s -> %d\n", parser->cur_obj->type == UCL_OBJECT ? "object" : "array", (int)parser->cur_obj->len);
#endif
- return ucl_msgpack_get_next_container (parser);
- }
+ return ucl_msgpack_get_next_container (parser);
}
/*
/* Rewind to the top level container */
ucl_msgpack_get_next_container (parser);
- assert (parser->stack == NULL ||
- (parser->stack->level & MSGPACK_CONTAINER_BIT) == 0);
+ assert (parser->stack == NULL);
return true;
}
*/
static inline ucl_object_t *
ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
- bool is_array, int level)
+ bool is_array, uint32_t level, bool has_obrace)
{
struct ucl_stack *st;
}
st->obj = obj;
- st->level = level;
+
+ if (level >= UINT16_MAX) {
+ ucl_set_err (parser, UCL_ENESTED,
+ "objects are nesting too deep (over 65535 limit)",
+ &parser->err);
+ ucl_object_unref (obj);
+ return NULL;
+ }
+
+
+ st->e.params.level = level;
+ st->e.params.line = parser->chunks->line;
+ st->chunk = parser->chunks;
+
+ if (has_obrace) {
+ st->e.params.flags = UCL_STACK_HAS_OBRACE;
+ }
+ else {
+ st->e.params.flags = 0;
+ }
+
LL_PREPEND (parser->stack, st);
parser->cur_obj = obj;
ucl_chunk_skipc (chunk, p);
}
if (p >= chunk->end) {
- ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "unfinished escape character",
&parser->err);
return false;
}
ucl_chunk_skipc (chunk, p);
}
- ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "no quote at the end of json string",
&parser->err);
return false;
}
ucl_chunk_skipc (chunk, p);
if (p >= chunk->end) {
- ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "unfinished escape character",
&parser->err);
return false;
}
ucl_chunk_skipc (chunk, p);
}
- ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of single quoted string",
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "no quote at the end of single quoted string",
&parser->err);
return false;
}
/* We have a new object */
if (parser->stack) {
obj = ucl_parser_add_container (obj, parser, false,
- parser->stack->level);
+ parser->stack->e.params.level, true);
}
else {
return false;
/* We have a new array */
if (parser->stack) {
obj = ucl_parser_add_container (obj, parser, true,
- parser->stack->level);
+ parser->stack->e.params.level, true);
}
else {
return false;
/* Pop all nested objects from a stack */
st = parser->stack;
+
+ if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) {
+ parser->err_code = UCL_EUNPAIRED;
+ ucl_create_err (&parser->err,
+ "%s:%d object closed with } is not opened with { at line %d",
+ chunk->fname ? chunk->fname : "memory",
+ parser->chunks->line, st->e.params.line);
+
+ return false;
+ }
+
parser->stack = st->next;
UCL_FREE (sizeof (struct ucl_stack), st);
while (parser->stack != NULL) {
st = parser->stack;
- if (st->next == NULL || st->next->level == st->level) {
+ if (st->next == NULL) {
break;
}
+ else if (st->next->e.params.level == st->e.params.level) {
+ break;
+ }
+
parser->stack = st->next;
parser->cur_obj = st->obj;
return false;
}
else {
+ bool seen_obrace = false;
+
/* Skip any spaces */
while (p < chunk->end && ucl_test_character (*p,
UCL_CHARACTER_WHITESPACE_UNSAFE)) {
if (*p == '[') {
parser->state = UCL_STATE_VALUE;
ucl_chunk_skipc (chunk, p);
+ seen_obrace = true;
}
else {
- parser->state = UCL_STATE_KEY;
+
if (*p == '{') {
ucl_chunk_skipc (chunk, p);
+ parser->state = UCL_STATE_KEY_OBRACE;
+ seen_obrace = true;
+ }
+ else {
+ parser->state = UCL_STATE_KEY;
}
}
if (parser->top_obj == NULL) {
if (parser->state == UCL_STATE_VALUE) {
- obj = ucl_parser_add_container (NULL, parser, true, 0);
+ obj = ucl_parser_add_container (NULL, parser, true, 0,
+ seen_obrace);
}
else {
- obj = ucl_parser_add_container (NULL, parser, false, 0);
+ obj = ucl_parser_add_container (NULL, parser, false, 0,
+ seen_obrace);
}
if (obj == NULL) {
}
break;
case UCL_STATE_KEY:
+ case UCL_STATE_KEY_OBRACE:
/* Skip any spaces */
while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
ucl_chunk_skipc (chunk, p);
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_parser_add_container (parser->cur_obj, parser, false,
- parser->stack->level + 1);
+ obj = ucl_parser_add_container (parser->cur_obj,
+ parser,
+ false,
+ parser->stack->e.params.level + 1,
+ parser->state == UCL_STATE_KEY_OBRACE);
if (obj == NULL) {
return false;
}
if (!ucl_skip_macro_as_comment (parser, chunk)) {
/* We have invalid macro */
ucl_create_err (&parser->err,
- "error on line %d at column %d: invalid macro",
+ "error at %s:%d at column %d: invalid macro",
+ chunk->fname ? chunk->fname : "memory",
chunk->line,
chunk->column);
parser->state = UCL_STATE_ERROR;
HASH_FIND (hh, parser->macroes, c, macro_len, macro);
if (macro == NULL) {
ucl_create_err (&parser->err,
- "error on line %d at column %d: "
+ "error at %s:%d at column %d: "
"unknown macro: '%.*s', character: '%c'",
+ chunk->fname ? chunk->fname : "memory",
chunk->line,
chunk->column,
(int) (p - c),
else {
/* We have invalid macro name */
ucl_create_err (&parser->err,
- "error on line %d at column %d: invalid macro name",
+ "error at %s:%d at column %d: invalid macro name",
+ chunk->fname ? chunk->fname : "memory",
chunk->line,
chunk->column);
parser->state = UCL_STATE_ERROR;
}
}
+ if (parser->stack != NULL) {
+ struct ucl_stack *st;
+ bool has_error = false;
+
+ LL_FOREACH (parser->stack, st) {
+ if (st->chunk != parser->chunks) {
+ break; /* Not our chunk, give up */
+ }
+ if (st->e.params.flags & UCL_STACK_HAS_OBRACE) {
+ if (parser->err == NULL) {
+ utstring_new (parser->err);
+ }
+
+ utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ",
+ chunk->fname ? chunk->fname : "memory",
+ parser->chunks->line,
+ st->e.params.line);
+
+ has_error = true;
+ }
+ }
+
+ if (has_error) {
+ parser->err_code = UCL_EUNPAIRED;
+
+ return false;
+ }
+ }
+
return true;
}
chunk->priority = priority;
chunk->strategy = strat;
chunk->parse_type = parse_type;
+
+ if (parser->cur_file) {
+ chunk->fname = strdup (parser->cur_file);
+ }
+
LL_PREPEND (parser->chunks, chunk);
parser->recursion ++;
parser->state = UCL_STATE_INIT;
/* Prevent inserted chunks from unintentionally closing the current object */
- if (parser->stack != NULL && parser->stack->next != NULL) parser->stack->level = parser->stack->next->level;
+ if (parser->stack != NULL && parser->stack->next != NULL) {
+ parser->stack->e.params.level = parser->stack->next->e.params.level;
+ }
res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority,
parser->chunks->strategy, parser->chunks->parse_type);