]> source.dussan.org Git - rspamd.git/commitdiff
Sync with libucl.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 23 Oct 2013 15:51:01 +0000 (16:51 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 23 Oct 2013 15:51:01 +0000 (16:51 +0100)
src/ucl/include/ucl.h
src/ucl/src/ucl_chartable.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
src/ucl/tests/generate.res
src/ucl/tests/test_basic.c
src/ucl/tests/test_generate.c
src/ucl/tests/test_speed.c

index 1b8fa8631fef69df50181559f6cb0c03920e83bb..0f132a37545f7ed8e5a0f87aa9b91ac05637d988 100644 (file)
@@ -35,7 +35,6 @@
 
 #include "uthash.h"
 #include "utlist.h"
-#include "utstring.h"
 
 /**
  * @file rcl.h
@@ -90,29 +89,65 @@ enum ucl_error {
        UCL_ESSL       //!< UCL_ESSL
 };
 
+/**
+ * Object types
+ */
 enum ucl_type {
-       UCL_OBJECT = 0,
-       UCL_ARRAY,
-       UCL_INT,
-       UCL_FLOAT,
-       UCL_STRING,
-       UCL_BOOLEAN,
-       UCL_TIME,
-       UCL_USERDATA
+       UCL_OBJECT = 0,//!< UCL_OBJECT
+       UCL_ARRAY,     //!< UCL_ARRAY
+       UCL_INT,       //!< UCL_INT
+       UCL_FLOAT,     //!< UCL_FLOAT
+       UCL_STRING,    //!< UCL_STRING
+       UCL_BOOLEAN,   //!< UCL_BOOLEAN
+       UCL_TIME,      //!< UCL_TIME
+       UCL_USERDATA   //!< UCL_USERDATA
 };
 
+/**
+ * Emitting types
+ */
 enum ucl_emitter {
-       UCL_EMIT_JSON = 0,
-       UCL_EMIT_JSON_COMPACT,
-       UCL_EMIT_CONFIG,
-       UCL_EMIT_YAML
+       UCL_EMIT_JSON = 0,    //!< UCL_EMIT_JSON
+       UCL_EMIT_JSON_COMPACT,//!< UCL_EMIT_JSON_COMPACT
+       UCL_EMIT_CONFIG,      //!< UCL_EMIT_CONFIG
+       UCL_EMIT_YAML         //!< UCL_EMIT_YAML
+};
+
+/**
+ * Parsing flags
+ */
+enum ucl_parser_flags {
+       UCL_PARSER_KEY_LOWERCASE = 0x1,//!< UCL_FLAG_KEY_LOWERCASE
+       UCL_PARSER_ZEROCOPY = 0x2      //!< UCL_FLAG_ZEROCOPY
+};
+
+/**
+ * String conversion flags
+ */
+enum ucl_string_flags {
+       UCL_STRING_ESCAPE = 0x1,  /**< UCL_STRING_ESCAPE perform JSON escape */
+       UCL_STRING_TRIM = 0x2,    /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
+       UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */
+       UCL_STRING_PARSE_INT = 0x8,    /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */
+       UCL_STRING_PARSE_DOUBLE = 0x10,    /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */
+       UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE ,  /**<
+                                                                       UCL_STRING_PARSE_NUMBER parse passed string and detect number */
+       UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER   /**<
+                                                                       UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
 };
 
-enum ucl_flags {
-       UCL_FLAG_KEY_LOWERCASE = 0x1,
-       UCL_FLAG_ZEROCOPY = 0x2
+/**
+ * Basic flags for an object
+ */
+enum ucl_object_flags {
+       UCL_OBJECT_ALLOCATED_KEY = 1, //!< UCL_OBJECT_ALLOCATED_KEY
+       UCL_OBJECT_ALLOCATED_VALUE = 2, //!< UCL_OBJECT_ALLOCATED_VALUE
+       UCL_OBJECT_NEED_KEY_ESCAPE = 4 //!< UCL_OBJECT_NEED_KEY_ESCAPE
 };
 
+/**
+ * UCL object
+ */
 typedef struct ucl_object_s {
        union {
                int64_t iv;                                                     /**< int value of an object */
@@ -122,7 +157,8 @@ typedef struct ucl_object_s {
                void* ud;                                                       /**< opaque user data           */
        } value;
        enum ucl_type type;                                             /**< real type                          */
-       int ref;                                                                /**< reference count            */
+       short int ref;                                                  /**< reference count            */
+       short int flags;                                                /**< object flags                       */
        size_t len;                                                             /**< size of an object          */
        struct ucl_object_s *next;                              /**< array handle                       */
        struct ucl_object_s *prev;                              /**< array handle                       */
@@ -161,21 +197,6 @@ ucl_object_new (void)
        return new;
 }
 
-/**
- * String conversion flags
- */
-enum ucl_string_flags {
-       UCL_STRING_ESCAPE = 0x1,  /**< UCL_STRING_ESCAPE perform JSON escape */
-       UCL_STRING_TRIM = 0x2,    /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
-       UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */
-       UCL_STRING_PARSE_INT = 0x8,    /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */
-       UCL_STRING_PARSE_DOUBLE = 0x10,    /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */
-       UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE ,  /**<
-                                                                       UCL_STRING_PARSE_NUMBER parse passed string and detect number */
-       UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER   /**<
-                                                                       UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
-};
-
 /**
  * Convert any string to an ucl object making the specified transformations
  * @param str fixed size or NULL terminated string
@@ -274,37 +295,8 @@ ucl_object_frombool (bool bv)
  * @param copy_key make an internal copy of key
  * @return new value of top object
  */
-static inline ucl_object_t *
-ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
-               const char *key, size_t keylen, bool copy_key)
-{
-       ucl_object_t *found;
-
-       if (elt == NULL || key == NULL) {
-               return NULL;
-       }
-
-       if (top == NULL) {
-               top = ucl_object_new ();
-               top->type = UCL_OBJECT;
-       }
-       if (keylen == 0) {
-               keylen = strlen (key);
-       }
-
-       HASH_FIND (hh, top->value.ov, key, keylen, found);
-
-       if (!found) {
-               HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt);
-       }
-       DL_APPEND (found, elt);
-
-       if (copy_key) {
-               ucl_copy_key_trash (elt);
-       }
-
-       return top;
-}
+ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
+               const char *key, size_t keylen, bool copy_key);
 
 /**
  * Append an element to the array object
@@ -625,7 +617,7 @@ ucl_object_keyl (ucl_object_t *obj, size_t *len)
  * @param err error pointer
  * @return true if macro has been parsed
  */
-typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud, UT_string **err);
+typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud);
 
 /* Opaque parser */
 struct ucl_parser;
@@ -655,8 +647,7 @@ void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
  * @param err if *err is NULL it is set to parser error
  * @return true if chunk has been added and false in case of error
  */
-bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
-               size_t len, UT_string **err);
+bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, size_t len);
 
 /**
  * Load and add data from a file
@@ -665,8 +656,7 @@ bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
  * @param err if *err is NULL it is set to parser error
  * @return true if chunk has been added and false in case of error
  */
-bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename,
-               UT_string **err);
+bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename);
 
 /**
  * Get a top object for a parser
@@ -674,8 +664,13 @@ bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename,
  * @param err if *err is NULL it is set to parser error
  * @return top parser object or NULL
  */
-ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser, UT_string **err);
+ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
 
+/**
+ * Get the error string if failing
+ * @param parser parser object
+ */
+const char *ucl_parser_get_error(struct ucl_parser *parser);
 /**
  * Free cl parser object
  * @param parser parser object
@@ -726,6 +721,6 @@ unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
  * @param err if *err is NULL it is set to parser error
  * @return true if a key has been successfully added
  */
-bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err);
+bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len);
 
 #endif /* RCL_H_ */
index 232043c1b74b99264e26be39e068796d2222e9b0..5248e117c63ddb3246837662cc077f9176f56535 100644 (file)
 static const unsigned int ucl_chartable[255] = {
 UCL_CHARACTER_VALUE_END, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
-UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_JSON_UNSAFE,
-UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE,
-UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE,
+UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
 UCL_CHARACTER_WHITESPACE_UNSAFE,
-UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE,
-UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE,
+UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
-UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /*   */,
+UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /*   */,
 UCL_CHARACTER_VALUE_STR /* ! */,
-UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* " */,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* " */,
 UCL_CHARACTER_VALUE_END /* # */, UCL_CHARACTER_VALUE_STR /* $ */,
 UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */,
 UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */,
@@ -63,9 +64,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 7 */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 8 */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 9 */,
-UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* : */,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* : */,
 UCL_CHARACTER_VALUE_END /* ; */, UCL_CHARACTER_VALUE_STR /* < */,
-UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* = */,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* = */,
 UCL_CHARACTER_VALUE_STR /* > */, UCL_CHARACTER_VALUE_STR /* ? */,
 UCL_CHARACTER_VALUE_STR /* @ */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* A */,
@@ -94,8 +95,8 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* X */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Y */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Z */,
-UCL_CHARACTER_VALUE_STR /* [ */,
-UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* \ */,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* [ */,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* \ */,
 UCL_CHARACTER_VALUE_END /* ] */, UCL_CHARACTER_VALUE_STR /* ^ */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR /* _ */,
 UCL_CHARACTER_VALUE_STR /* ` */,
@@ -125,9 +126,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* x */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* y */,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* z */,
-UCL_CHARACTER_VALUE_STR /* { */, UCL_CHARACTER_VALUE_STR /* | */,
-UCL_CHARACTER_VALUE_END /* } */, UCL_CHARACTER_VALUE_STR /* ~ */,
-UCL_CHARACTER_DENIED,
+UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* { */,
+UCL_CHARACTER_VALUE_STR /* | */, UCL_CHARACTER_VALUE_END /* } */,
+UCL_CHARACTER_VALUE_STR /* ~ */, UCL_CHARACTER_DENIED,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
 UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
index 78e321c535fa66de0ecb3e5dfd15e799be95c014..38d4b3d18b312cccc4210899d8059577c91ab7e4 100644 (file)
@@ -346,7 +346,12 @@ ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, boo
 
        HASH_ITER (hh, obj, cur, tmp) {
                ucl_add_tabs (buf, tabs + 1, is_top);
-               utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+               if (cur->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+                       ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+               }
+               else {
+                       utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+               }
                if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
                        utstring_append_len (buf, " = ", 3);
                }
@@ -481,7 +486,12 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
 
        HASH_ITER (hh, obj, cur, tmp) {
                ucl_add_tabs (buf, tabs + 1, is_top);
-               utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+               if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+                       ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+               }
+               else {
+                       utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+               }
                if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
                        utstring_append_len (buf, " : ", 3);
                }
index 97613c8247958368dfd7a4debe6b57c2a184e59d..393ecf85a0a95c62e4461af0e2cafc9e8d52371d 100644 (file)
@@ -36,6 +36,7 @@
 #include <ctype.h>
 
 #include "utlist.h"
+#include "utstring.h"
 #include "ucl.h"
 
 #ifdef HAVE_OPENSSL
@@ -78,7 +79,8 @@ enum ucl_character_type {
        UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7,
        UCL_CHARACTER_ESCAPE = 1 << 8,
        UCL_CHARACTER_KEY_SEP = 1 << 9,
-       UCL_CHARACTER_JSON_UNSAFE = 1 << 10
+       UCL_CHARACTER_JSON_UNSAFE = 1 << 10,
+       UCL_CHARACTER_UCL_UNSAFE = 1 << 11
 };
 
 struct ucl_macro {
@@ -125,6 +127,7 @@ struct ucl_parser {
        struct ucl_stack *stack;
        struct ucl_chunk *chunks;
        struct ucl_pubkey *keys;
+       UT_string *err;
 };
 
 /**
@@ -141,7 +144,7 @@ size_t ucl_unescape_json_string (char *str, size_t len);
  * @param err error ptr
  * @return
  */
-bool ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err);
+bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
 
 /**
  * Handle includes macro
@@ -151,7 +154,7 @@ bool ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_st
  * @param err error ptr
  * @return
  */
-bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err);
+bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
 
 size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
 size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
index 30106ebd3a0d7877c709f670ab95834c6077b400..e125caee4d8b37aed8789aa2b1da34ec1cc25147 100644 (file)
@@ -91,7 +91,7 @@ ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err
 }
 
 static bool
-ucl_skip_comments (struct ucl_parser *parser, UT_string **err)
+ucl_skip_comments (struct ucl_parser *parser)
 {
        struct ucl_chunk *chunk = parser->chunks;
        const unsigned char *p;
@@ -139,7 +139,7 @@ start:
                                ucl_chunk_skipc (chunk, p);
                        }
                        if (comments_nested != 0) {
-                               ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", err);
+                               ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", &parser->err);
                                return false;
                        }
                }
@@ -237,15 +237,15 @@ static inline size_t
 ucl_copy_or_store_ptr (struct ucl_parser *parser,
                const unsigned char *src, unsigned char **dst,
                const char **dst_const, size_t in_len,
-               bool need_unescape, bool need_lowercase, UT_string **err)
+               bool need_unescape, bool need_lowercase)
 {
        size_t ret = 0;
 
-       if (need_unescape || need_lowercase || !(parser->flags & UCL_FLAG_ZEROCOPY)) {
+       if (need_unescape || need_lowercase || !(parser->flags & UCL_PARSER_ZEROCOPY)) {
                /* Copy string */
                *dst = UCL_ALLOC (in_len + 1);
                if (*dst == NULL) {
-                       ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", err);
+                       ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err);
                        return false;
                }
                if (need_lowercase) {
@@ -274,7 +274,7 @@ 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;
+       bool got_dot = false, got_exp = false, need_double = false, is_date = false, valid_start = false;
        double dv;
        int64_t lv;
 
@@ -283,6 +283,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
        }
        while (p < end) {
                if (isdigit (*p)) {
+                       valid_start = true;
                        p ++;
                }
                else if (allow_double) {
@@ -337,6 +338,11 @@ ucl_maybe_parse_number (ucl_object_t *obj,
                }
        }
 
+       if (!valid_start) {
+               *pos = start;
+               return EINVAL;
+       }
+
        errno = 0;
        if (need_double) {
                dv = strtod (c, &endptr);
@@ -355,7 +361,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
                goto set_obj;
        }
 
-       if (endptr < end) {
+       if (endptr < end && endptr != start) {
                p = endptr;
                switch (*p) {
                case 'm':
@@ -487,12 +493,11 @@ ucl_maybe_parse_number (ucl_object_t *obj,
  * Parse possible number
  * @param parser
  * @param chunk
- * @param err
  * @return true if a number has been parsed
  */
 static bool
 ucl_lex_number (struct ucl_parser *parser,
-               struct ucl_chunk *chunk, ucl_object_t *obj, UT_string **err)
+               struct ucl_chunk *chunk, ucl_object_t *obj)
 {
        const unsigned char *pos;
        int ret;
@@ -506,7 +511,7 @@ ucl_lex_number (struct ucl_parser *parser,
                return true;
        }
        else if (ret == ERANGE) {
-               ucl_set_err (chunk, ERANGE, "numeric value out of range", err);
+               ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
        }
 
        return false;
@@ -516,12 +521,11 @@ ucl_lex_number (struct ucl_parser *parser,
  * Parse quoted string with possible escapes
  * @param parser
  * @param chunk
- * @param err
  * @return true if a string has been parsed
  */
 static bool
 ucl_lex_json_string (struct ucl_parser *parser,
-               struct ucl_chunk *chunk, bool *need_unescape, UT_string **err)
+               struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape)
 {
        const unsigned char *p = chunk->pos;
        unsigned char c;
@@ -532,10 +536,10 @@ ucl_lex_json_string (struct ucl_parser *parser,
                if (c < 0x1F) {
                        /* Unmasked control character */
                        if (c == '\n') {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
                        }
                        else {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
                        }
                        return false;
                }
@@ -543,7 +547,7 @@ ucl_lex_json_string (struct ucl_parser *parser,
                        ucl_chunk_skipc (chunk, p);
                        c = *p;
                        if (p >= chunk->end) {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
                                return false;
                        }
                        else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
@@ -551,13 +555,13 @@ ucl_lex_json_string (struct ucl_parser *parser,
                                        ucl_chunk_skipc (chunk, p);
                                        for (i = 0; i < 4 && p < chunk->end; i ++) {
                                                if (!isxdigit (*p)) {
-                                                       ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", err);
+                                                       ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
                                                        return false;
                                                }
                                                ucl_chunk_skipc (chunk, p);
                                        }
                                        if (p >= chunk->end) {
-                                               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err);
+                                               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
                                                return false;
                                        }
                                }
@@ -566,20 +570,24 @@ ucl_lex_json_string (struct ucl_parser *parser,
                                }
                        }
                        else {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", &parser->err);
                                return false;
                        }
                        *need_unescape = true;
+                       *ucl_escape = true;
                        continue;
                }
                else if (c == '"') {
                        ucl_chunk_skipc (chunk, p);
                        return true;
                }
+               else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
+                       *ucl_escape = true;
+               }
                ucl_chunk_skipc (chunk, p);
        }
 
-       ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", err);
+       ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
        return false;
 }
 
@@ -587,16 +595,15 @@ ucl_lex_json_string (struct ucl_parser *parser,
  * Parse a key in an object
  * @param parser
  * @param chunk
- * @param err
  * @return true if a key has been parsed
  */
 static bool
-ucl_parse_key (struct ucl_parser *parser,
-               struct ucl_chunk *chunk, UT_string **err)
+ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
 {
        const unsigned char *p, *c = NULL, *end;
        const char *key;
-       bool got_quote = false, got_eq = false, got_semicolon = false, need_unescape = false;
+       bool got_quote = false, got_eq = false, got_semicolon = false,
+                       need_unescape = false, ucl_escape = false;
        ucl_object_t *nobj, *tobj, *container;
        size_t keylen;
 
@@ -615,7 +622,7 @@ ucl_parse_key (struct ucl_parser *parser,
                 */
                if (c == NULL) {
                        if (ucl_lex_is_comment (p[0], p[1])) {
-                               if (!ucl_skip_comments (parser, err)) {
+                               if (!ucl_skip_comments (parser)) {
                                        return false;
                                }
                                p = chunk->pos;
@@ -633,7 +640,7 @@ ucl_parse_key (struct ucl_parser *parser,
                        }
                        else {
                                /* Invalid identifier */
-                               ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
                                return false;
                        }
                }
@@ -648,15 +655,16 @@ ucl_parse_key (struct ucl_parser *parser,
                                        break;
                                }
                                else {
-                                       ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", err);
+                                       ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
                                        return false;
                                }
                        }
                        else {
                                /* We need to parse json like quoted string */
-                               if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) {
+                               if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
                                        return false;
                                }
+                               /* Always escape keys obtained via json */
                                end = chunk->pos - 1;
                                p = chunk->pos;
                                break;
@@ -665,7 +673,7 @@ ucl_parse_key (struct ucl_parser *parser,
        }
 
        if (p >= chunk->end) {
-               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err);
+               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
                return false;
        }
 
@@ -680,7 +688,7 @@ ucl_parse_key (struct ucl_parser *parser,
                                got_eq = true;
                        }
                        else {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
                                return false;
                        }
                }
@@ -690,13 +698,13 @@ ucl_parse_key (struct ucl_parser *parser,
                                got_semicolon = true;
                        }
                        else {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
                                return false;
                        }
                }
                else if (ucl_lex_is_comment (p[0], p[1])) {
                        /* Check for comment */
-                       if (!ucl_skip_comments (parser, err)) {
+                       if (!ucl_skip_comments (parser)) {
                                return false;
                        }
                        p = chunk->pos;
@@ -708,14 +716,14 @@ ucl_parse_key (struct ucl_parser *parser,
        }
 
        if (p >= chunk->end) {
-               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err);
+               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
                return false;
        }
 
        /* Create a new object */
        nobj = ucl_object_new ();
        keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
-                       &key, end - c, need_unescape, parser->flags & UCL_FLAG_KEY_LOWERCASE, err);
+                       &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE);
        if (keylen == 0) {
                return false;
        }
@@ -730,6 +738,9 @@ ucl_parse_key (struct ucl_parser *parser,
                DL_APPEND (tobj, nobj);
        }
 
+       if (ucl_escape) {
+               nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
+       }
        parser->stack->obj->value.ov = container;
 
        parser->cur_obj = nobj;
@@ -741,12 +752,11 @@ ucl_parse_key (struct ucl_parser *parser,
  * Parse a cl string
  * @param parser
  * @param chunk
- * @param err
  * @return true if a key has been parsed
  */
 static bool
 ucl_parse_string_value (struct ucl_parser *parser,
-               struct ucl_chunk *chunk, UT_string **err)
+               struct ucl_chunk *chunk)
 {
        const unsigned char *p;
        enum {
@@ -792,7 +802,7 @@ ucl_parse_string_value (struct ucl_parser *parser,
        }
 
        if (p >= chunk->end) {
-               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", err);
+               ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
                return false;
        }
 
@@ -805,13 +815,12 @@ ucl_parse_string_value (struct ucl_parser *parser,
  * @param chunk
  * @param term
  * @param term_len
- * @param err
  * @return size of multiline string or 0 in case of error
  */
 static int
 ucl_parse_multiline_string (struct ucl_parser *parser,
                struct ucl_chunk *chunk, const unsigned char *term,
-               int term_len, unsigned char const **beg, UT_string **err)
+               int term_len, unsigned char const **beg)
 {
        const unsigned char *p, *c;
        bool newline = false;
@@ -851,18 +860,17 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
  * Handle value data
  * @param parser
  * @param chunk
- * @param err
  * @return
  */
 static bool
-ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err)
+ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
 {
        const unsigned char *p, *c;
        struct ucl_stack *st;
        ucl_object_t *obj = NULL, *t;
        unsigned int stripped_spaces;
        int str_len;
-       bool need_unescape = false;
+       bool need_unescape = false, ucl_escape = false;
 
        p = chunk->pos;
 
@@ -885,13 +893,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                switch (*p) {
                case '"':
                        ucl_chunk_skipc (chunk, p);
-                       if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) {
+                       if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
                                return false;
                        }
                        str_len = chunk->pos - c - 2;
                        obj->type = UCL_STRING;
                        if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE],
-                                       &obj->value.sv, str_len, need_unescape, false, err)) == 0) {
+                                       &obj->value.sv, str_len, need_unescape, false)) == 0) {
                                return false;
                        }
                        obj->len = str_len;
@@ -943,13 +951,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                                                chunk->column = 0;
                                                chunk->line ++;
                                                if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
-                                                               p - c, &c, err)) == 0) {
-                                                       ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", err);
+                                                               p - c, &c)) == 0) {
+                                                       ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
                                                        return false;
                                                }
                                                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 - 1, false, false, err)) == 0) {
+                                                       &obj->value.sv, str_len - 1, false, false)) == 0) {
                                                        return false;
                                                }
                                                obj->len = str_len;
@@ -966,7 +974,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                                while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
                                        ucl_chunk_skipc (chunk, p);
                                }
-                               if (!ucl_skip_comments (parser, err)) {
+                               if (!ucl_skip_comments (parser)) {
                                        return false;
                                }
                                p = chunk->pos;
@@ -974,11 +982,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                        }
                        /* Parse atom */
                        if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
-                               if (!ucl_lex_number (parser, chunk, obj, err)) {
+                               if (!ucl_lex_number (parser, chunk, obj)) {
                                        if (parser->state == UCL_STATE_ERROR) {
                                                return false;
                                        }
-                                       if (!ucl_parse_string_value (parser, chunk, err)) {
+                                       if (!ucl_parse_string_value (parser, chunk)) {
                                                return false;
                                        }
                                        if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) {
@@ -990,12 +998,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                                                }
                                                str_len = chunk->pos - c - stripped_spaces;
                                                if (str_len <= 0) {
-                                                       ucl_set_err (chunk, 0, "string value must not be empty", err);
+                                                       ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
                                                        return false;
                                                }
                                                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, err)) == 0) {
+                                                               &obj->value.sv, str_len, false, false)) == 0) {
                                                        return false;
                                                }
                                                obj->len = str_len;
@@ -1009,7 +1017,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                                }
                        }
                        else {
-                               if (!ucl_parse_string_value (parser, chunk, err)) {
+                               if (!ucl_parse_string_value (parser, chunk)) {
                                        return false;
                                }
                                if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) {
@@ -1022,12 +1030,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
                                        }
                                        str_len = chunk->pos - c - stripped_spaces;
                                        if (str_len <= 0) {
-                                               ucl_set_err (chunk, 0, "string value must not be empty", err);
+                                               ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
                                                return false;
                                        }
                                        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, err)) == 0) {
+                                                       &obj->value.sv, str_len, false, false)) == 0) {
                                                return false;
                                        }
                                        obj->len = str_len;
@@ -1047,11 +1055,10 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
  * Handle after value data
  * @param parser
  * @param chunk
- * @param err
  * @return
  */
 static bool
-ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err)
+ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
 {
        const unsigned char *p;
        bool got_sep = false;
@@ -1066,7 +1073,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st
                }
                else if (ucl_lex_is_comment (p[0], p[1])) {
                        /* Skip comment */
-                       if (!ucl_skip_comments (parser, err)) {
+                       if (!ucl_skip_comments (parser)) {
                                return false;
                        }
                        /* Treat comment as a separator */
@@ -1076,7 +1083,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st
                else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
                        if (*p == '}' || *p == ']') {
                                if (parser->stack == NULL) {
-                                       ucl_set_err (chunk, UCL_ESYNTAX, "unexpected } detected", err);
+                                       ucl_set_err (chunk, UCL_ESYNTAX, "unexpected } detected", &parser->err);
                                        return false;
                                }
                                if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
@@ -1088,7 +1095,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st
                                        UCL_FREE (sizeof (struct ucl_stack), st);
                                }
                                else {
-                                       ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", err);
+                                       ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
                                        return false;
                                }
 
@@ -1110,7 +1117,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st
                else {
                        /* Anything else */
                        if (!got_sep) {
-                               ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", err);
+                               ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
                                return false;
                        }
                        return true;
@@ -1124,16 +1131,15 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st
  * Handle macro data
  * @param parser
  * @param chunk
- * @param err
  * @return
  */
 static bool
 ucl_parse_macro_value (struct ucl_parser *parser,
                struct ucl_chunk *chunk, struct ucl_macro *macro,
-               unsigned char const **macro_start, size_t *macro_len, UT_string **err)
+               unsigned char const **macro_start, size_t *macro_len)
 {
        const unsigned char *p, *c;
-       bool need_unescape = false;
+       bool need_unescape = false, ucl_escape = false;
 
        p = chunk->pos;
 
@@ -1142,7 +1148,7 @@ ucl_parse_macro_value (struct ucl_parser *parser,
                /* We have macro value encoded in quotes */
                c = p;
                ucl_chunk_skipc (chunk, p);
-               if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) {
+               if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
                        return false;
                }
 
@@ -1203,11 +1209,10 @@ ucl_parse_macro_value (struct ucl_parser *parser,
  * @param parser parser structure
  * @param data the pointer to the beginning of a chunk
  * @param len the length of a chunk
- * @param err if *err is NULL it is set to parser error
  * @return true if chunk has been parsed and false in case of error
  */
 static bool
-ucl_state_machine (struct ucl_parser *parser, UT_string **err)
+ucl_state_machine (struct ucl_parser *parser)
 {
        ucl_object_t *obj;
        struct ucl_chunk *chunk = parser->chunks;
@@ -1225,7 +1230,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                         * if we got [ or { correspondingly or can just treat new data as
                         * a key of newly created object
                         */
-                       if (!ucl_skip_comments (parser, err)) {
+                       if (!ucl_skip_comments (parser)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
@@ -1262,7 +1267,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                                parser->state = UCL_STATE_AFTER_VALUE;
                                continue;
                        }
-                       if (!ucl_parse_key (parser, chunk, err)) {
+                       if (!ucl_parse_key (parser, chunk)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
@@ -1277,7 +1282,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                        break;
                case UCL_STATE_VALUE:
                        /* We need to check what we do have */
-                       if (!ucl_parse_value (parser, chunk, err)) {
+                       if (!ucl_parse_value (parser, chunk)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
@@ -1286,7 +1291,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                        p = chunk->pos;
                        break;
                case UCL_STATE_AFTER_VALUE:
-                       if (!ucl_parse_after_value (parser, chunk, err)) {
+                       if (!ucl_parse_after_value (parser, chunk)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
@@ -1314,7 +1319,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                                /* We got macro name */
                                HASH_FIND (hh, parser->macroes, c, (p - c), macro);
                                if (macro == NULL) {
-                                       ucl_set_err (chunk, UCL_EMACRO, "unknown macro", err);
+                                       ucl_set_err (chunk, UCL_EMACRO, "unknown macro", &parser->err);
                                        parser->state = UCL_STATE_ERROR;
                                        return false;
                                }
@@ -1323,7 +1328,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                                        if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
                                                if (ucl_lex_is_comment (p[0], p[1])) {
                                                        /* Skip comment */
-                                                       if (!ucl_skip_comments (parser, err)) {
+                                                       if (!ucl_skip_comments (parser)) {
                                                                return false;
                                                        }
                                                        p = chunk->pos;
@@ -1337,20 +1342,20 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
                        break;
                case UCL_STATE_MACRO:
                        if (!ucl_parse_macro_value (parser, chunk, macro,
-                                       &macro_start, &macro_len, err)) {
+                                       &macro_start, &macro_len)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
                        }
                        parser->state = parser->prev_state;
-                       if (!macro->handler (macro_start, macro_len, macro->ud, err)) {
+                       if (!macro->handler (macro_start, macro_len, macro->ud)) {
                                return false;
                        }
                        p = chunk->pos;
                        break;
                default:
                        /* TODO: add all states */
-                       ucl_set_err (chunk, UCL_EMACRO, "internal error: parser is in an unknown state", err);
+                       ucl_set_err (chunk, UCL_EMACRO, "internal error: parser is in an unknown state", &parser->err);
                        parser->state = UCL_STATE_ERROR;
                        return false;
                }
@@ -1392,7 +1397,7 @@ ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
 
 bool
 ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
-               size_t len, UT_string **err)
+               size_t len)
 {
        struct ucl_chunk *chunk;
 
@@ -1407,14 +1412,14 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
                LL_PREPEND (parser->chunks, chunk);
                parser->recursion ++;
                if (parser->recursion > UCL_MAX_RECURSION) {
-                       ucl_create_err (err, "maximum include nesting limit is reached: %d",
+                       ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
                                        parser->recursion);
                        return false;
                }
-               return ucl_state_machine (parser, err);
+               return ucl_state_machine (parser);
        }
 
-       ucl_create_err (err, "a parser is in an invalid state");
+       ucl_create_err (&parser->err, "a parser is in an invalid state");
 
        return false;
 }
index 510035c557bba9d19715686edc81dfb8ed369684..09123e91e4f0a19a8b1fff5ea007c3219fb7aced 100644 (file)
@@ -186,6 +186,7 @@ ucl_copy_key_trash (ucl_object_t *obj)
                        obj->trash_stack[UCL_TRASH_KEY][obj->hh.keylen] = '\0';
                }
                obj->hh.key = obj->trash_stack[UCL_TRASH_KEY];
+               obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
        }
 
        return obj->trash_stack[UCL_TRASH_KEY];
@@ -202,6 +203,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
                        if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
                                memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
                                obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
+                               obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
                        }
                }
                else {
@@ -215,12 +217,13 @@ ucl_copy_value_trash (ucl_object_t *obj)
                                free (emitted);
                        }
                }
+               obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
        }
        return obj->trash_stack[UCL_TRASH_VALUE];
 }
 
 ucl_object_t*
-ucl_parser_get_object (struct ucl_parser *parser, UT_string **err)
+ucl_parser_get_object (struct ucl_parser *parser)
 {
        if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) {
                return ucl_object_ref (parser->top_obj);
@@ -256,15 +259,28 @@ ucl_parser_free (struct ucl_parser *parser)
                UCL_FREE (sizeof (struct ucl_pubkey), key);
        }
 
+       if (parser->err != NULL) {
+               utstring_free(parser->err);
+       }
+
        UCL_FREE (sizeof (struct ucl_parser), parser);
 }
 
+const char *
+ucl_parser_get_error(struct ucl_parser *parser)
+{
+       if (parser->err == NULL)
+               return NULL;
+
+       return utstring_body(parser->err);
+}
+
 bool
-ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err)
+ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
 {
        struct ucl_pubkey *nkey;
 #ifndef HAVE_OPENSSL
-       ucl_create_err (err, "cannot check signatures without openssl");
+       ucl_create_err (&parser->err, "cannot check signatures without openssl");
        return false;
 #else
 # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
@@ -279,7 +295,7 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len,
        BIO_free (mem);
        if (nkey->key == NULL) {
                UCL_FREE (sizeof (struct ucl_pubkey), nkey);
-               ucl_create_err (err, "%s",
+               ucl_create_err (&parser->err, "%s",
                                ERR_error_string (ERR_get_error (), NULL));
                return false;
        }
@@ -345,7 +361,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, UT
        }
 
        *buflen = us.size;
-       *buf = g_malloc (*buflen);
+       *buf = malloc (*buflen);
        if (*buf == NULL) {
                ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
                                url, strerror (errno));
@@ -499,7 +515,7 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
  */
 static bool
 ucl_include_url (const unsigned char *data, size_t len,
-               struct ucl_parser *parser, bool check_signature, UT_string **err)
+               struct ucl_parser *parser, bool check_signature)
 {
 
        bool res;
@@ -510,7 +526,7 @@ ucl_include_url (const unsigned char *data, size_t len,
 
        snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
 
-       if (!ucl_fetch_url (urlbuf, &buf, &buflen, err)) {
+       if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err)) {
                return false;
        }
 
@@ -518,11 +534,11 @@ ucl_include_url (const unsigned char *data, size_t len,
 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
                /* We need to check signature first */
                snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
-               if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, err)) {
+               if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, &parser->err)) {
                        return false;
                }
                if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
-                       ucl_create_err (err, "cannot verify url %s: %s",
+                       ucl_create_err (&parser->err, "cannot verify url %s: %s",
                                                        urlbuf,
                                                        ERR_error_string (ERR_get_error (), NULL));
                        munmap (sigbuf, siglen);
@@ -532,7 +548,7 @@ ucl_include_url (const unsigned char *data, size_t len,
 #endif
        }
 
-       res = ucl_parser_add_chunk (parser, buf, buflen, err);
+       res = ucl_parser_add_chunk (parser, buf, buflen);
        if (res == true) {
                /* Remove chunk from the stack */
                chunk = parser->chunks;
@@ -556,7 +572,7 @@ ucl_include_url (const unsigned char *data, size_t len,
  */
 static bool
 ucl_include_file (const unsigned char *data, size_t len,
-               struct ucl_parser *parser, bool check_signature, UT_string **err)
+               struct ucl_parser *parser, bool check_signature)
 {
        bool res;
        struct ucl_chunk *chunk;
@@ -566,13 +582,13 @@ ucl_include_file (const unsigned char *data, size_t len,
 
        snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
        if (realpath (filebuf, realbuf) == NULL) {
-               ucl_create_err (err, "cannot open file %s: %s",
+               ucl_create_err (&parser->err, "cannot open file %s: %s",
                                                                        filebuf,
                                                                        strerror (errno));
                return false;
        }
 
-       if (!ucl_fetch_file (realbuf, &buf, &buflen, err)) {
+       if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err)) {
                return false;
        }
 
@@ -580,11 +596,11 @@ ucl_include_file (const unsigned char *data, size_t len,
 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
                /* We need to check signature first */
                snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
-               if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, err)) {
+               if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err)) {
                        return false;
                }
                if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
-                       ucl_create_err (err, "cannot verify file %s: %s",
+                       ucl_create_err (&parser->err, "cannot verify file %s: %s",
                                                        filebuf,
                                                        ERR_error_string (ERR_get_error (), NULL));
                        munmap (sigbuf, siglen);
@@ -594,7 +610,7 @@ ucl_include_file (const unsigned char *data, size_t len,
 #endif
        }
 
-       res = ucl_parser_add_chunk (parser, buf, buflen, err);
+       res = ucl_parser_add_chunk (parser, buf, buflen);
        if (res == true) {
                /* Remove chunk from the stack */
                chunk = parser->chunks;
@@ -617,16 +633,16 @@ ucl_include_file (const unsigned char *data, size_t len,
  * @return
  */
 bool
-ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err)
+ucl_include_handler (const unsigned char *data, size_t len, void* ud)
 {
        struct ucl_parser *parser = ud;
 
        if (*data == '/' || *data == '.') {
                /* Try to load a file */
-               return ucl_include_file (data, len, parser, false, err);
+               return ucl_include_file (data, len, parser, false);
        }
 
-       return ucl_include_url (data, len, parser, false, err);
+       return ucl_include_url (data, len, parser, false);
 }
 
 /**
@@ -638,31 +654,30 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string
  * @return
  */
 bool
-ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err)
+ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
 {
        struct ucl_parser *parser = ud;
 
        if (*data == '/' || *data == '.') {
                /* Try to load a file */
-               return ucl_include_file (data, len, parser, true, err);
+               return ucl_include_file (data, len, parser, true);
        }
 
-       return ucl_include_url (data, len, parser, true, err);
+       return ucl_include_url (data, len, parser, true);
 }
 
 bool
-ucl_parser_add_file (struct ucl_parser *parser, const char *filename,
-               UT_string **err)
+ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
 {
        unsigned char *buf;
        size_t len;
        bool ret;
 
-       if (!ucl_fetch_file (filename, &buf, &len, err)) {
+       if (!ucl_fetch_file (filename, &buf, &len, &parser->err)) {
                return false;
        }
 
-       ret = ucl_parser_add_chunk (parser, buf, len, err);
+       ret = ucl_parser_add_chunk (parser, buf, len);
 
        munmap (buf, len);
 
@@ -839,3 +854,43 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags
 
        return obj;
 }
+
+ucl_object_t *
+ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
+               const char *key, size_t keylen, bool copy_key)
+{
+       ucl_object_t *found;
+       const char *p;
+
+       if (elt == NULL || key == NULL) {
+               return NULL;
+       }
+
+       if (top == NULL) {
+               top = ucl_object_new ();
+               top->type = UCL_OBJECT;
+       }
+       if (keylen == 0) {
+               keylen = strlen (key);
+       }
+
+       for (p = key; p < key + keylen; p ++) {
+               if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
+                       elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
+                       break;
+               }
+       }
+
+       HASH_FIND (hh, top->value.ov, key, keylen, found);
+
+       if (!found) {
+               HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt);
+       }
+       DL_APPEND (found, elt);
+
+       if (copy_key) {
+               ucl_copy_key_trash (elt);
+       }
+
+       return top;
+}
index e7659ec3a9dc1d72a7a13df207ffe1ada21614de..63857aac5e4446674bc2e28192d0deafd9d4406f 100644 (file)
@@ -15,4 +15,7 @@ key8 = 1048576;
 key9 = 3.140000;
 key10 = true;
 key11 = false;
+key12 = "gslin@gslin.org";
+key13 = "#test";
+"k=3" = true;
 
index d4d4786d658d221de74876066fc28e7c00d9fb4e..7444d901b4c2dc0cd53e9fce945162f2192f7795 100644 (file)
@@ -32,7 +32,6 @@ main (int argc, char **argv)
        struct ucl_parser *parser, *parser2;
        ucl_object_t *obj;
        FILE *in, *out;
-       UT_string *err = NULL;
        unsigned char *emitted;
        const char *fname_in = NULL, *fname_out = NULL;
        int ret = 0;
@@ -56,11 +55,11 @@ main (int argc, char **argv)
        else {
                in = stdin;
        }
-       parser = ucl_parser_new (UCL_FLAG_KEY_LOWERCASE);
+       parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
 
        while (!feof (in)) {
                fread (inbuf, sizeof (inbuf), 1, in);
-               ucl_parser_add_chunk (parser, inbuf, strlen (inbuf), &err);
+               ucl_parser_add_chunk (parser, inbuf, strlen (inbuf));
        }
        fclose (in);
 
@@ -73,20 +72,20 @@ main (int argc, char **argv)
        else {
                out = stdout;
        }
-       if (err != NULL) {
-               fprintf (out, "Error occurred: %s\n", err->d);
+       if (ucl_parser_get_error(parser) != NULL) {
+               fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser));
                ret = 1;
                goto end;
        }
-       obj = ucl_parser_get_object (parser, &err);
+       obj = ucl_parser_get_object (parser);
        emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
        ucl_parser_free (parser);
        ucl_object_unref (obj);
-       parser2 = ucl_parser_new (UCL_FLAG_KEY_LOWERCASE);
-       ucl_parser_add_chunk (parser2, emitted, strlen (emitted), &err);
+       parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
+       ucl_parser_add_chunk (parser2, emitted, strlen (emitted));
 
-       if (err != NULL) {
-               fprintf (out, "Error occurred: %s\n", err->d);
+       if (ucl_parser_get_error(parser2) != NULL) {
+               fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser2));
                fprintf (out, "%s\n", emitted);
                ret = 1;
                goto end;
@@ -94,7 +93,7 @@ main (int argc, char **argv)
        if (emitted != NULL) {
                free (emitted);
        }
-       obj = ucl_parser_get_object (parser2, &err);
+       obj = ucl_parser_get_object (parser2);
        emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
 
        fprintf (out, "%s\n", emitted);
@@ -107,6 +106,7 @@ end:
        if (parser2 != NULL) {
                ucl_parser_free (parser2);
        }
+
        fclose (out);
 
        return ret;
index a61b353963dac2ef2546bfa3131b307f49214cae..f269e00dc6918a58d35fdc74f35f6423f4bfc7fc 100644 (file)
@@ -83,6 +83,13 @@ main (int argc, char **argv)
        obj = ucl_object_insert_key (obj, cur, "key10", 0, false);
        cur = ucl_object_fromstring_common ("  off  ", 0, UCL_STRING_PARSE | UCL_STRING_TRIM);
        obj = ucl_object_insert_key (obj, cur, "key11", 0, false);
+       cur = ucl_object_fromstring_common ("gslin@gslin.org", 0, UCL_STRING_PARSE_INT);
+       obj = ucl_object_insert_key (obj, cur, "key12", 0, false);
+       cur = ucl_object_fromstring_common ("#test", 0, UCL_STRING_PARSE_INT);
+       obj = ucl_object_insert_key (obj, cur, "key13", 0, false);
+       cur = ucl_object_frombool (true);
+       obj = ucl_object_insert_key (obj, cur, "k=3", 0, false);
+
 
        emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
 
index 92a972aa5511ea11e5ffed98e74c5a02a1ec2fa5..39229becba0ddce38f4443982f76a7fd4f24c951 100644 (file)
@@ -40,7 +40,6 @@ main (int argc, char **argv)
        struct ucl_parser *parser;
        ucl_object_t *obj;
        int fin;
-       UT_string *err = NULL;
        unsigned char *emitted;
        struct stat st;
        const char *fname_in = NULL;
@@ -59,7 +58,7 @@ main (int argc, char **argv)
                perror ("open failed");
                exit (EXIT_FAILURE);
        }
-       parser = ucl_parser_new (UCL_FLAG_ZEROCOPY);
+       parser = ucl_parser_new (UCL_PARSER_ZEROCOPY);
 
        (void)fstat (fin, &st);
        map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fin, 0);
@@ -71,15 +70,15 @@ main (int argc, char **argv)
        close (fin);
 
        clock_gettime (CLOCK_MONOTONIC, &start);
-       ucl_parser_add_chunk (parser, map, st.st_size, &err);
+       ucl_parser_add_chunk (parser, map, st.st_size);
 
-       obj = ucl_parser_get_object (parser, &err);
+       obj = ucl_parser_get_object (parser);
        clock_gettime (CLOCK_MONOTONIC, &end);
 
        seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.;
        printf ("ucl: parsed input in %.4f seconds\n", seconds);
-       if (err != NULL) {
-               printf ("Error occurred: %s\n", err->d);
+       if (ucl_parser_get_error(parser)) {
+               printf ("Error occurred: %s\n", ucl_parser_get_error(parser));
                ret = 1;
        }