summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ucl/include/ucl.h27
-rw-r--r--src/ucl/src/ucl_emitter.c56
-rw-r--r--src/ucl/src/ucl_internal.h6
-rw-r--r--src/ucl/src/ucl_parser.c77
-rw-r--r--src/ucl/src/ucl_util.c5
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;