diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ucl/include/ucl.h | 27 | ||||
-rw-r--r-- | src/ucl/src/ucl_emitter.c | 56 | ||||
-rw-r--r-- | src/ucl/src/ucl_internal.h | 6 | ||||
-rw-r--r-- | src/ucl/src/ucl_parser.c | 77 | ||||
-rw-r--r-- | src/ucl/src/ucl_util.c | 5 |
5 files changed, 136 insertions, 35 deletions
diff --git a/src/ucl/include/ucl.h b/src/ucl/include/ucl.h index d1dd61fdb..929812670 100644 --- a/src/ucl/include/ucl.h +++ b/src/ucl/include/ucl.h @@ -24,8 +24,14 @@ #ifndef UCL_H_ #define UCL_H_ -#include "config.h" +#include <string.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdint.h> #include <stdbool.h> +#include <stdarg.h> +#include <stdio.h> +#include "config.h" /** * @mainpage @@ -372,7 +378,7 @@ ucl_object_t* ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt /** * Append an element to the array object * @param top destination object (will be created automatically if top is NULL) - * @param eltelement to append (must NOT be NULL) + * @param elt element to append (must NOT be NULL) * @return new value of top object */ static inline ucl_object_t * ucl_array_append (ucl_object_t *top, @@ -387,18 +393,25 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt) } if (top == NULL) { - top = ucl_object_new (); - top->type = UCL_ARRAY; + top = ucl_object_typed_new (UCL_ARRAY); top->value.av = elt; elt->next = NULL; elt->prev = elt; + top->len = 1; } else { head = top->value.av; - elt->prev = head->prev; - head->prev->next = elt; - head->prev = elt; + if (head == NULL) { + top->value.av = elt; + elt->prev = elt; + } + else { + elt->prev = head->prev; + head->prev->next = elt; + head->prev = elt; + } elt->next = NULL; + top->len ++; } return top; diff --git a/src/ucl/src/ucl_emitter.c b/src/ucl/src/ucl_emitter.c index 5269acfc2..51bb09aad 100644 --- a/src/ucl/src/ucl_emitter.c +++ b/src/ucl/src/ucl_emitter.c @@ -754,7 +754,8 @@ ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type) return res; } -bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, +bool +ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, struct ucl_emitter_functions *emitter) { if (emit_type == UCL_EMIT_JSON) { @@ -773,3 +774,56 @@ bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, /* XXX: need some error checks here */ return true; } + + +unsigned char * +ucl_object_emit_single_json (ucl_object_t *obj) +{ + UT_string *buf = NULL; + unsigned char *res = NULL; + + if (obj == NULL) { + return NULL; + } + + utstring_new (buf); + + if (buf != NULL) { + switch (obj->type) { + case UCL_OBJECT: + ucl_utstring_append_len ("object", 6, buf); + break; + case UCL_ARRAY: + ucl_utstring_append_len ("array", 5, buf); + break; + case UCL_INT: + ucl_utstring_append_int (obj->value.iv, buf); + break; + case UCL_FLOAT: + case UCL_TIME: + ucl_utstring_append_double (obj->value.dv, buf); + break; + case UCL_NULL: + ucl_utstring_append_len ("null", 4, buf); + break; + case UCL_BOOLEAN: + if (obj->value.iv) { + ucl_utstring_append_len ("true", 4, buf); + } + else { + ucl_utstring_append_len ("false", 5, buf); + } + break; + case UCL_STRING: + ucl_utstring_append_len (obj->value.sv, obj->len, buf); + break; + case UCL_USERDATA: + ucl_utstring_append_len ("userdata", 8, buf); + break; + } + res = utstring_body (buf); + free (buf); + } + + return res; +} diff --git a/src/ucl/src/ucl_internal.h b/src/ucl/src/ucl_internal.h index a68403c53..8db697736 100644 --- a/src/ucl/src/ucl_internal.h +++ b/src/ucl/src/ucl_internal.h @@ -280,5 +280,11 @@ ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) return hashlin; } +/** + * Emit a single object to string + * @param obj + * @return + */ +unsigned char * ucl_object_emit_single_json (ucl_object_t *obj); #endif /* UCL_INTERNAL_H_ */ diff --git a/src/ucl/src/ucl_parser.c b/src/ucl/src/ucl_parser.c index 0441a121c..f2e5001e6 100644 --- a/src/ucl/src/ucl_parser.c +++ b/src/ucl/src/ucl_parser.c @@ -86,13 +86,18 @@ ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state static inline void ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err) { - 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); + 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); + } + else { + ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", + chunk->line, chunk->column, str, (int)*chunk->pos); + } } else { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", - chunk->line, chunk->column, str, (int)*chunk->pos); + ucl_create_err (err, "error at the end of chunk: %s", str); } } @@ -150,7 +155,7 @@ start: ucl_chunk_skipc (chunk, p); } if (comments_nested != 0) { - ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", &parser->err); + ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err); return false; } } @@ -553,18 +558,30 @@ ucl_maybe_parse_number (ucl_object_t *obj, { const char *p = start, *c = start; char *endptr; - bool got_dot = false, got_exp = false, need_double = false, is_date = false, valid_start = false; + bool got_dot = false, got_exp = false, need_double = false, + is_date = false, valid_start = false, is_hex = false, + is_neg = false; double dv = 0; int64_t lv = 0; if (*p == '-') { + is_neg = true; + c ++; p ++; } while (p < end) { - if (isdigit (*p)) { + if (is_hex && isxdigit (*p)) { + p ++; + } + else if (isdigit (*p)) { valid_start = true; p ++; } + else if (!is_hex && (*p == 'x' || *p == 'X')) { + is_hex = true; + allow_double = false; + c = p + 1; + } else if (allow_double) { if (p == c) { /* Empty digits sequence, not a number */ @@ -627,7 +644,12 @@ ucl_maybe_parse_number (ucl_object_t *obj, dv = strtod (c, &endptr); } else { - lv = strtoimax (c, &endptr, 10); + if (is_hex) { + lv = strtoimax (c, &endptr, 16); + } + else { + lv = strtoimax (c, &endptr, 10); + } } if (errno == ERANGE) { *pos = start; @@ -758,11 +780,11 @@ ucl_maybe_parse_number (ucl_object_t *obj, else { obj->type = UCL_TIME; } - obj->value.dv = dv; + obj->value.dv = is_neg ? (-dv) : dv; } else { obj->type = UCL_INT; - obj->value.iv = lv; + obj->value.iv = is_neg ? (-lv) : lv; } *pos = p; return 0; @@ -848,10 +870,6 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); } } - else { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", &parser->err); - return false; - } *need_unescape = true; *ucl_escape = true; continue; @@ -1074,6 +1092,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke container = ucl_hash_insert_object (container, nobj); nobj->prev = nobj; nobj->next = NULL; + parser->stack->obj->len ++; } else { DL_APPEND (tobj, nobj); @@ -1097,7 +1116,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke */ static bool ucl_parse_string_value (struct ucl_parser *parser, - struct ucl_chunk *chunk, bool *var_expand) + struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape) { const unsigned char *p; enum { @@ -1117,7 +1136,7 @@ ucl_parse_string_value (struct ucl_parser *parser, } else if (*p == '}') { braces[UCL_BRACE_FIGURE][1] ++; - if (braces[UCL_BRACE_FIGURE][1] == braces[UCL_BRACE_FIGURE][0]) { + if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) { /* This is not a termination symbol, continue */ ucl_chunk_skipc (chunk, p); continue; @@ -1129,7 +1148,7 @@ ucl_parse_string_value (struct ucl_parser *parser, } else if (*p == ']') { braces[UCL_BRACE_SQUARE][1] ++; - if (braces[UCL_BRACE_SQUARE][1] == braces[UCL_BRACE_SQUARE][0]) { + if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) { /* This is not a termination symbol, continue */ ucl_chunk_skipc (chunk, p); continue; @@ -1138,6 +1157,14 @@ ucl_parse_string_value (struct ucl_parser *parser, else if (*p == '$') { *var_expand = true; } + else if (*p == '\\') { + *need_unescape = true; + ucl_chunk_skipc (chunk, p); + if (p < chunk->end) { + ucl_chunk_skipc (chunk, p); + } + continue; + } if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { break; @@ -1230,6 +1257,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) DL_APPEND (t, obj); parser->cur_obj = obj; parser->stack->obj->value.av = t; + parser->stack->obj->len ++; } else { /* Object has been already allocated */ @@ -1328,7 +1356,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) /* Fallback to normal string */ } - if (!ucl_parse_string_value (parser, chunk, &var_expand)) { + if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) { return false; } /* Cut trailing spaces */ @@ -1349,7 +1377,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 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], - &obj->value.sv, str_len, false, false, var_expand)) == -1) { + &obj->value.sv, str_len, need_unescape, + false, var_expand)) == -1) { return false; } obj->len = str_len; @@ -1377,7 +1406,6 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) const unsigned char *p; bool got_sep = false; struct ucl_stack *st; - int last_level; p = chunk->pos; @@ -1406,14 +1434,15 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) /* Pop all nested objects from a stack */ st = parser->stack; - last_level = st->level; parser->stack = st->next; UCL_FREE (sizeof (struct ucl_stack), st); - while (parser->stack != NULL && last_level > 0 && parser->stack->level == last_level) { + while (parser->stack != NULL) { st = parser->stack; + if (st->next == NULL || st->next->level == st->level) { + break; + } parser->stack = st->next; - last_level = st->level; UCL_FREE (sizeof (struct ucl_stack), st); } } diff --git a/src/ucl/src/ucl_util.c b/src/ucl/src/ucl_util.c index 817d02ac3..ba6e08c1c 100644 --- a/src/ucl/src/ucl_util.c +++ b/src/ucl/src/ucl_util.c @@ -161,7 +161,7 @@ ucl_unescape_json_string (char *str, size_t len) } break; default: - *t++ = '?'; + *t++ = *h; break; } h ++; @@ -208,8 +208,7 @@ ucl_copy_value_trash (ucl_object_t *obj) } else { /* Just emit value in json notation */ - obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit (obj, - UCL_EMIT_JSON_COMPACT); + obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); } obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; |