]> source.dussan.org Git - rspamd.git/commitdiff
Sync with libucl.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 4 Dec 2013 13:42:02 +0000 (13:42 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 4 Dec 2013 13:42:02 +0000 (13:42 +0000)
src/ucl/src/ucl_emitter.c
src/ucl/src/ucl_hash.c
src/ucl/src/ucl_internal.h
src/ucl/src/ucl_parser.c
src/ucl/src/ucl_util.c
src/ucl/src/xxhash.c

index c7d14dc8a3d76a1e06d25c437944a6a57e891874..d0e62436d72cffd367d910cd7866650499414804 100644 (file)
@@ -38,6 +38,7 @@ static void ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int t
                bool start_tabs, bool is_top, bool expand_array);
 static void ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
                bool start_tabs, bool compact, bool expand_array);
+static void ucl_elt_array_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top);
 
 /**
  * Add tabulation to the output buffer
@@ -256,6 +257,12 @@ ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
                }
                ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
                break;
+       case UCL_NULL:
+               if (start_tabs) {
+                       ucl_add_tabs (buf, tabs, compact);
+               }
+               utstring_printf (buf, "null");
+               break;
        case UCL_OBJECT:
                ucl_elt_obj_write_json (obj, buf, tabs, start_tabs, compact);
                break;
@@ -440,6 +447,12 @@ ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
                        }
                        ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
                        break;
+               case UCL_NULL:
+                       if (start_tabs) {
+                               ucl_add_tabs (buf, tabs, false);
+                       }
+                       utstring_printf (buf, "null");
+                       break;
                case UCL_OBJECT:
                        ucl_elt_obj_write_rcl (obj, buf, tabs, start_tabs, is_top);
                        break;
@@ -471,6 +484,19 @@ ucl_object_emit_rcl (ucl_object_t *obj)
 }
 
 
+static void
+ucl_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs)
+{
+       bool is_array = (obj->next != NULL);
+
+       if (is_array) {
+               ucl_elt_array_write_yaml (obj, buf, tabs, start_tabs, false);
+       }
+       else {
+               ucl_elt_write_yaml(obj, buf, tabs, start_tabs, false, true);
+       }
+}
+
 /**
  * Write a single object to the buffer
  * @param obj object to write
@@ -486,25 +512,20 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
                ucl_add_tabs (buf, tabs, is_top);
        }
        if (!is_top) {
-               utstring_append_len (buf, ": {\n", 4);
+               utstring_append_len (buf, "{\n", 2);
        }
 
        while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
                ucl_add_tabs (buf, tabs + 1, is_top);
-               if (cur->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+               if (cur->keylen > 0) {
                        ucl_elt_string_write_json (cur->key, cur->keylen, buf);
                }
                else {
-                       utstring_append_len (buf, cur->key, cur->keylen);
-               }
-               if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
-                       utstring_append_len (buf, " : ", 3);
-               }
-               else {
-                       utstring_append_c (buf, ' ');
+                       utstring_append_len (buf, "null", 4);
                }
-               ucl_elt_write_yaml (cur, buf, is_top ? tabs : tabs + 1, false, false, true);
-               if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
+               utstring_append_len(buf, ": ", 2);
+               ucl_obj_write_yaml (cur, buf, is_top ? tabs : tabs + 1, false);
+               if (ucl_hash_iter_has_next(it)) {
                        if (!is_top) {
                                utstring_append_len (buf, ",\n", 2);
                        }
@@ -586,6 +607,12 @@ ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
                        }
                        ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
                        break;
+               case UCL_NULL:
+                       if (start_tabs) {
+                               ucl_add_tabs (buf, tabs, false);
+                       }
+                       utstring_printf (buf, "null");
+                       break;
                case UCL_OBJECT:
                        ucl_elt_obj_write_yaml (obj, buf, tabs, start_tabs, is_top);
                        break;
index d644da4f49a89cfa8032805b0fadac144acf47df..a3711deb85395965a57047c5a2e376af03a023b1 100644 (file)
@@ -96,6 +96,9 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
 {
        ucl_hash_node_t *found;
 
+       if (hashlin == NULL) {
+               return NULL;
+       }
        HASH_FIND (hh, hashlin->buckets, key, keylen, found);
 
        if (found) {
index 21b1aa53e9aca9ad251eb1dcd284fc6be6d7e1a4..78b52edbd1d74ebb7e1952b1633959cb0c02fda7 100644 (file)
@@ -96,6 +96,7 @@ struct ucl_macro {
 struct ucl_stack {
        ucl_object_t *obj;
        struct ucl_stack *next;
+       int level;
 };
 
 struct ucl_chunk {
@@ -209,33 +210,33 @@ ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t l
        bool ret = false, val = false;
 
        if (len == 5) {
-               if (tolower (p[0]) == 'f' && strncasecmp (p, "false", 5) == 0) {
+               if ((p[0] == 'f' || p[0] == 'F') && strncasecmp (p, "false", 5) == 0) {
                        ret = true;
                        val = false;
                }
        }
        else if (len == 4) {
-               if (tolower (p[0]) == 't' && strncasecmp (p, "true", 4) == 0) {
+               if ((p[0] == 't' || p[0] == 'T') && strncasecmp (p, "true", 4) == 0) {
                        ret = true;
                        val = true;
                }
        }
        else if (len == 3) {
-               if (tolower (p[0]) == 'y' && strncasecmp (p, "yes", 3) == 0) {
+               if ((p[0] == 'y' || p[0] == 'Y') && strncasecmp (p, "yes", 3) == 0) {
                        ret = true;
                        val = true;
                }
-               if (tolower (p[0]) == 'o' && strncasecmp (p, "off", 3) == 0) {
+               else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "off", 3) == 0) {
                        ret = true;
                        val = false;
                }
        }
        else if (len == 2) {
-               if (tolower (p[0]) == 'n' && strncasecmp (p, "no", 2) == 0) {
+               if ((p[0] == 'n' || p[0] == 'N') && strncasecmp (p, "no", 2) == 0) {
                        ret = true;
                        val = false;
                }
-               else if (tolower (p[0]) == 'o' && strncasecmp (p, "on", 2) == 0) {
+               else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "on", 2) == 0) {
                        ret = true;
                        val = true;
                }
index 2e48168746794473d51f3d7a6f4e95240a52590e..f819edee6acf6e48312da7d6a1d8a80f88beef26 100644 (file)
@@ -90,6 +90,11 @@ ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err
                        chunk->line, chunk->column, str, *chunk->pos);
 }
 
+/**
+ * Skip all comments from the current pos resolving nested and multiline comments
+ * @param parser
+ * @return
+ */
 static bool
 ucl_skip_comments (struct ucl_parser *parser)
 {
@@ -233,6 +238,16 @@ ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
        return false;
 }
 
+/**
+ * Check variable found
+ * @param parser
+ * @param ptr
+ * @param remain
+ * @param out_len
+ * @param strict
+ * @param found
+ * @return
+ */
 static inline const char *
 ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
                size_t *out_len, bool strict, bool *found)
@@ -263,6 +278,15 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
        return ptr;
 }
 
+/**
+ * Check for a variable in a given string
+ * @param parser
+ * @param ptr
+ * @param remain
+ * @param out_len
+ * @param vars_found
+ * @return
+ */
 static const char *
 ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
 {
@@ -309,6 +333,14 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, s
        return ret;
 }
 
+/**
+ * Expand a single variable
+ * @param parser
+ * @param ptr
+ * @param remain
+ * @param dest
+ * @return
+ */
 static const char *
 ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
                size_t remain, unsigned char **dest)
@@ -353,6 +385,14 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
        return ret;
 }
 
+/**
+ * Expand variables in string
+ * @param parser
+ * @param dst
+ * @param src
+ * @param in_len
+ * @return
+ */
 static ssize_t
 ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
                const char *src, size_t in_len)
@@ -400,6 +440,18 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
        return out_len;
 }
 
+/**
+ * Store or copy pointer to the trash stack
+ * @param parser parser object
+ * @param src src string
+ * @param dst destination buffer (trash stack pointer)
+ * @param dst_const const destination pointer (e.g. value of object)
+ * @param in_len input length
+ * @param need_unescape need to unescape source (and copy it)
+ * @param need_lowercase need to lowercase value (and copy)
+ * @param need_expand need to expand variables (and copy as well)
+ * @return output length (excluding \0 symbol)
+ */
 static inline ssize_t
 ucl_copy_or_store_ptr (struct ucl_parser *parser,
                const unsigned char *src, unsigned char **dst,
@@ -448,6 +500,47 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
        return ret;
 }
 
+/**
+ * Create and append an object at the specified level
+ * @param parser
+ * @param is_array
+ * @param level
+ * @return
+ */
+static inline ucl_object_t *
+ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level)
+{
+       struct ucl_stack *st;
+
+       if (!is_array) {
+               if (obj == NULL) {
+                       obj = ucl_object_typed_new (UCL_OBJECT);
+               }
+               else {
+                       obj->type = UCL_OBJECT;
+               }
+               obj->value.ov = ucl_hash_create ();
+               parser->state = UCL_STATE_KEY;
+       }
+       else {
+               if (obj == NULL) {
+                       obj = ucl_object_typed_new (UCL_ARRAY);
+               }
+               else {
+                       obj->type = UCL_ARRAY;
+               }
+               parser->state = UCL_STATE_VALUE;
+       }
+
+       st = UCL_ALLOC (sizeof (struct ucl_stack));
+       st->obj = obj;
+       st->level = level;
+       LL_PREPEND (parser->stack, st);
+       parser->cur_obj = obj;
+
+       return obj;
+}
+
 int
 ucl_maybe_parse_number (ucl_object_t *obj,
                const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes)
@@ -781,12 +874,13 @@ ucl_lex_json_string (struct ucl_parser *parser,
  * @return true if a key has been parsed
  */
 static bool
-ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
+ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object)
 {
-       const unsigned char *p, *c = NULL, *end;
+       const unsigned char *p, *c = NULL, *end, *t;
        const char *key;
        bool got_quote = false, got_eq = false, got_semicolon = false,
-                       need_unescape = false, ucl_escape = false, var_expand = false;
+                       need_unescape = false, ucl_escape = false, var_expand = false,
+                       got_content = false, got_sep = false;
        ucl_object_t *nobj, *tobj;
        ucl_hash_t *container;
        ssize_t keylen;
@@ -811,17 +905,27 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
                                }
                                p = chunk->pos;
                        }
+                       else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+                               ucl_chunk_skipc (chunk, p);
+                       }
                        else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
                                /* The first symbol */
                                c = p;
                                ucl_chunk_skipc (chunk, p);
+                               got_content = true;
                        }
                        else if (*p == '"') {
                                /* JSON style key */
                                c = p + 1;
                                got_quote = true;
+                               got_content = true;
                                ucl_chunk_skipc (chunk, p);
                        }
+                       else if (*p == '}') {
+                               /* We have actually end of an object */
+                               *end_of_object = true;
+                               return true;
+                       }
                        else {
                                /* Invalid identifier */
                                ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
@@ -832,6 +936,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
                        /* Parse the body of a key */
                        if (!got_quote) {
                                if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
+                                       got_content = true;
                                        ucl_chunk_skipc (chunk, p);
                                }
                                else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
@@ -856,11 +961,14 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
                }
        }
 
-       if (p >= chunk->end) {
+       if (p >= chunk->end && got_content) {
                ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
                return false;
        }
-
+       else if (!got_content) {
+               return true;
+       }
+       *end_of_object = false;
        /* We are now at the end of the key, need to parse the rest */
        while (p < chunk->end) {
                if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
@@ -899,11 +1007,41 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
                }
        }
 
-       if (p >= chunk->end) {
+       if (p >= chunk->end && got_content) {
                ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
                return false;
        }
 
+       got_sep = got_semicolon || got_eq;
+
+       if (!got_sep) {
+               /*
+                * Maybe we have more keys nested, so search for termination character.
+                * Possible choices:
+                * 1) key1 key2 ... keyN [:=] value <- we treat that as error
+                * 2) key1 ... keyN {} or [] <- we treat that as nested objects
+                * 3) key1 value[;,\n] <- we treat that as linear object
+                */
+               t = p;
+               *next_key = false;
+               while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
+                       t ++;
+               }
+               /* Check first non-space character after a key */
+               if (*t != '{' && *t != '[') {
+                       while (t < chunk->end) {
+                               if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
+                                       break;
+                               }
+                               else if (*t == '{' || *t == '[') {
+                                       *next_key = true;
+                                       break;
+                               }
+                               t ++;
+                       }
+               }
+       }
+
        /* Create a new object */
        nobj = ucl_object_new ();
        keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
@@ -1064,7 +1202,6 @@ static bool
 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;
@@ -1107,27 +1244,14 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                        break;
                case '{':
                        /* We have a new object */
-                       obj->type = UCL_OBJECT;
-                       obj->value.ov = ucl_hash_create ();
-                       parser->state = UCL_STATE_KEY;
-                       st = UCL_ALLOC (sizeof (struct ucl_stack));
-                       st->obj = obj;
-                       LL_PREPEND (parser->stack, st);
-                       parser->cur_obj = obj;
+                       obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
 
                        ucl_chunk_skipc (chunk, p);
                        return true;
                        break;
                case '[':
                        /* We have a new array */
-                       obj = parser->cur_obj;
-                       obj->type = UCL_ARRAY;
-
-                       parser->state = UCL_STATE_VALUE;
-                       st = UCL_ALLOC (sizeof (struct ucl_stack));
-                       st->obj = obj;
-                       LL_PREPEND (parser->stack, st);
-                       parser->cur_obj = obj;
+                       obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
 
                        ucl_chunk_skipc (chunk, p);
                        return true;
@@ -1206,8 +1330,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                                ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
                                return false;
                        }
-
-                       if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
+                       else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
+                               obj->len = 0;
+                               obj->type = UCL_NULL;
+                       }
+                       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) {
@@ -1238,6 +1365,7 @@ 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;
 
@@ -1258,16 +1386,24 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                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", &parser->err);
+                                       ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
                                        return false;
                                }
                                if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
                                                (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
-                                       /* Pop object from a stack */
 
+                                       /* 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) {
+                                               st = parser->stack;
+                                               parser->stack = st->next;
+                                               last_level = st->level;
+                                               UCL_FREE (sizeof (struct ucl_stack), st);
+                                       }
                                }
                                else {
                                        ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
@@ -1391,11 +1527,17 @@ ucl_state_machine (struct ucl_parser *parser)
 {
        ucl_object_t *obj;
        struct ucl_chunk *chunk = parser->chunks;
-       struct ucl_stack *st;
        const unsigned char *p, *c = NULL, *macro_start = NULL;
        unsigned char *macro_escaped;
        size_t macro_len = 0;
        struct ucl_macro *macro = NULL;
+       bool next_key = false, end_of_object = false;
+
+       if (parser->top_obj == NULL) {
+               obj = ucl_add_parser_stack (NULL, parser, false, 0);
+               parser->top_obj = obj;
+               parser->state = UCL_STATE_INIT;
+       }
 
        p = chunk->pos;
        while (chunk->pos < chunk->end) {
@@ -1406,6 +1548,7 @@ ucl_state_machine (struct ucl_parser *parser)
                         * if we got [ or { correspondingly or can just treat new data as
                         * a key of newly created object
                         */
+                       obj = parser->top_obj;
                        if (!ucl_skip_comments (parser)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
@@ -1413,25 +1556,20 @@ ucl_state_machine (struct ucl_parser *parser)
                        }
                        else {
                                p = chunk->pos;
-                               obj = ucl_object_new ();
                                if (*p == '[') {
                                        parser->state = UCL_STATE_VALUE;
                                        obj->type = UCL_ARRAY;
+                                       ucl_hash_destroy (obj->value.ov, NULL);
+                                       obj->value.av = NULL;
                                        ucl_chunk_skipc (chunk, p);
                                }
                                else {
                                        parser->state = UCL_STATE_KEY;
                                        obj->type = UCL_OBJECT;
-                                       obj->value.ov = ucl_hash_create ();
                                        if (*p == '{') {
                                                ucl_chunk_skipc (chunk, p);
                                        }
-                               };
-                               parser->cur_obj = obj;
-                               parser->top_obj = obj;
-                               st = UCL_ALLOC (sizeof (struct ucl_stack));
-                               st->obj = obj;
-                               LL_PREPEND (parser->stack, st);
+                               }
                        }
                        break;
                case UCL_STATE_KEY:
@@ -1444,13 +1582,24 @@ ucl_state_machine (struct ucl_parser *parser)
                                parser->state = UCL_STATE_AFTER_VALUE;
                                continue;
                        }
-                       if (!ucl_parse_key (parser, chunk)) {
+                       if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
                                parser->prev_state = parser->state;
                                parser->state = UCL_STATE_ERROR;
                                return false;
                        }
-                       if (parser->state != UCL_STATE_MACRO_NAME) {
-                               parser->state = UCL_STATE_VALUE;
+                       if (end_of_object) {
+                               p = chunk->pos;
+                               parser->state = UCL_STATE_AFTER_VALUE;
+                               continue;
+                       }
+                       else if (parser->state != UCL_STATE_MACRO_NAME) {
+                               if (next_key && parser->stack->obj->type == UCL_OBJECT) {
+                                       /* Parse more keys and nest objects accordingly */
+                                       obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1);
+                               }
+                               else {
+                                       parser->state = UCL_STATE_VALUE;
+                               }
                        }
                        else {
                                c = chunk->pos;
index 0df6119618aa29ac4309d14a594e63dec8798632..cf9cf99b0b755f6b3c3f6cc714383267ef807648 100644 (file)
@@ -224,7 +224,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
 ucl_object_t*
 ucl_parser_get_object (struct ucl_parser *parser)
 {
-       if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) {
+       if (parser->state != UCL_STATE_ERROR) {
                return ucl_object_ref (parser->top_obj);
        }
 
@@ -288,7 +288,7 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
        return false;
 #else
 # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
-       ucl_create_err (err, "cannot check signatures, openssl version is unsupported");
+       ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
        return EXIT_FAILURE;
 # else
        struct ucl_pubkey *nkey;
@@ -444,19 +444,26 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
                                filename, strerror (errno));
                return false;
        }
-       if ((fd = open (filename, O_RDONLY)) == -1) {
-               ucl_create_err (err, "cannot open file %s: %s",
-                               filename, strerror (errno));
-               return false;
+       if (st.st_size == 0) {
+               /* Do not map empty files */
+               *buf = "";
+               *buflen = 0;
        }
-       if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+       else {
+               if ((fd = open (filename, O_RDONLY)) == -1) {
+                       ucl_create_err (err, "cannot open file %s: %s",
+                                       filename, strerror (errno));
+                       return false;
+               }
+               if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+                       close (fd);
+                       ucl_create_err (err, "cannot mmap file %s: %s",
+                                       filename, strerror (errno));
+                       return false;
+               }
+               *buflen = st.st_size;
                close (fd);
-               ucl_create_err (err, "cannot mmap file %s: %s",
-                               filename, strerror (errno));
-               return false;
        }
-       *buflen = st.st_size;
-       close (fd);
 
        return true;
 }
@@ -548,10 +555,14 @@ ucl_include_url (const unsigned char *data, size_t len,
                        ucl_create_err (&parser->err, "cannot verify url %s: %s",
                                                        urlbuf,
                                                        ERR_error_string (ERR_get_error (), NULL));
-                       munmap (sigbuf, siglen);
+                       if (siglen > 0) {
+                               munmap (sigbuf, siglen);
+                       }
                        return false;
                }
-               munmap (sigbuf, siglen);
+               if (siglen > 0) {
+                       munmap (sigbuf, siglen);
+               }
 #endif
        }
 
@@ -612,10 +623,14 @@ ucl_include_file (const unsigned char *data, size_t len,
                        ucl_create_err (&parser->err, "cannot verify file %s: %s",
                                                        filebuf,
                                                        ERR_error_string (ERR_get_error (), NULL));
-                       munmap (sigbuf, siglen);
+                       if (siglen > 0) {
+                               munmap (sigbuf, siglen);
+                       }
                        return false;
                }
-               munmap (sigbuf, siglen);
+               if (siglen > 0) {
+                       munmap (sigbuf, siglen);
+               }
 #endif
        }
 
@@ -628,7 +643,9 @@ ucl_include_file (const unsigned char *data, size_t len,
                        UCL_FREE (sizeof (struct ucl_chunk), chunk);
                }
        }
-       munmap (buf, buflen);
+       if (buflen > 0) {
+               munmap (buf, buflen);
+       }
 
        return res;
 }
@@ -688,7 +705,9 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
 
        ret = ucl_parser_add_chunk (parser, buf, len);
 
-       munmap (buf, len);
+       if (len > 0) {
+               munmap (buf, len);
+       }
 
        return ret;
 }
@@ -883,6 +902,17 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
                top->type = UCL_OBJECT;
        }
 
+       if (top->type != UCL_OBJECT) {
+               /* It is possible to convert NULL type to an object */
+               if (top->type == UCL_NULL) {
+                       top->type = UCL_OBJECT;
+               }
+               else {
+                       /* Refuse converting of other object types */
+                       return top;
+               }
+       }
+
        if (top->value.ov == NULL) {
                top->value.ov = ucl_hash_create ();
        }
index bb4c639aa36e7f49ecaa3b979d4faee2005d8c66..5869503be0108f56e7b88def4d5b09912f051038 100644 (file)
@@ -273,7 +273,7 @@ U32 XXH32(const void* input, int len, U32 seed)
     XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\r
 \r
 #  if !defined(XXH_USE_UNALIGNED_ACCESS)\r
-    if ((((size_t)input) & 3))   // Input is aligned, let's leverage the speed advantage\r
+    if (!(((size_t)input) & 3))   // Input is aligned, let's leverage the speed advantage\r
     {\r
         if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\r
             return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);\r