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) {
/* 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;
+}
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);
}
}
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;
}
}
{
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 */
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;
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;
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;
container = ucl_hash_insert_object (container, nobj);
nobj->prev = nobj;
nobj->next = NULL;
+ parser->stack->obj->len ++;
}
else {
DL_APPEND (tobj, nobj);
*/
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 {
}
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;
}
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;
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;
DL_APPEND (t, obj);
parser->cur_obj = obj;
parser->stack->obj->value.av = t;
+ parser->stack->obj->len ++;
}
else {
/* Object has been already allocated */
/* 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 */
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;
const unsigned char *p;
bool got_sep = false;
struct ucl_stack *st;
- int last_level;
p = chunk->pos;
/* 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);
}
}