]> source.dussan.org Git - rspamd.git/commitdiff
Sync with libucl.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 29 Jan 2014 15:39:57 +0000 (15:39 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 29 Jan 2014 15:39:57 +0000 (15:39 +0000)
src/ucl/include/ucl.h
src/ucl/src/ucl_emitter.c
src/ucl/src/ucl_internal.h
src/ucl/src/ucl_parser.c
src/ucl/src/ucl_util.c

index d1dd61fdb2797a296b47a38ebb17103d38117919..929812670e8c5b4fd769edbd6518a27064ebe5ef 100644 (file)
 #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;
index 5269acfc2a54cd89d52978bd5d5bc8cafe041149..51bb09aad7cc30593cb029b39aedde2437b85e64 100644 (file)
@@ -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;
+}
index a68403c53a1f3865a1485fee5b39c2de5f6d7c1e..8db69773627ef86af8515c2e0f4b059a89ae63f6 100644 (file)
@@ -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_ */
index 0441a121c355c3b3ece477d8548a46759e69edc9..f2e5001e6cbdfa0c573f312aff76446748efacbc 100644 (file)
@@ -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);
                                        }
                                }
index 817d02ac3ba315de3a911a9f6db1bc646fc0afe5..ba6e08c1cefa09935e8bd17110e9d5a7f5ead049 100644 (file)
@@ -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;