]> source.dussan.org Git - rspamd.git/commitdiff
Sync with libucl.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 2 Nov 2013 22:12:39 +0000 (22:12 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 2 Nov 2013 22:12:39 +0000 (22:12 +0000)
12 files changed:
src/cfg_rcl.c
src/cfg_rcl.h
src/cfg_xml.c
src/lua/lua_rcl.c
src/plugins/regexp.c
src/plugins/surbl.c
src/ucl/CMakeLists.txt
src/ucl/include/ucl.h
src/ucl/src/ucl_emitter.c
src/ucl/src/ucl_internal.h
src/ucl/src/ucl_parser.c
src/ucl/src/ucl_util.c

index 2190f648a91250d3fb715ee45067d6156ff50508..0a251e7e1c1e8322910661617152c64109300820 100644 (file)
@@ -300,13 +300,14 @@ static gboolean
 rspamd_rcl_metric_handler (struct config_file *cfg, ucl_object_t *obj,
                gpointer ud, struct rspamd_rcl_section *section, GError **err)
 {
-       ucl_object_t *val, *cur, *tmp;
+       ucl_object_t *val, *cur;
        const gchar *metric_name, *subject_name, *semicolon, *act_str;
        struct metric *metric;
        struct metric_action *action;
        gdouble action_score, grow_factor;
        gint action_value;
        gboolean new = TRUE, have_actions = FALSE;
+       ucl_object_iter_t it = NULL;
 
        val = ucl_object_find_key (obj, "name");
        if (val == NULL || !ucl_object_tostring_safe (val, &metric_name)) {
@@ -329,7 +330,7 @@ rspamd_rcl_metric_handler (struct config_file *cfg, ucl_object_t *obj,
                        g_set_error (err, CFG_RCL_ERROR, EINVAL, "actions must be an object");
                        return FALSE;
                }
-               HASH_ITER (hh, val, cur, tmp) {
+               while ((cur = ucl_iterate_object (val, &it, true)) != NULL) {
                        if (!check_action_str (ucl_object_key (cur), &action_value) ||
                                        !ucl_object_todouble_safe (cur, &action_score)) {
                                g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid action definition: %s", ucl_object_key (cur));
@@ -381,7 +382,8 @@ rspamd_rcl_metric_handler (struct config_file *cfg, ucl_object_t *obj,
                        g_set_error (err, CFG_RCL_ERROR, EINVAL, "symbols must be an object");
                        return FALSE;
                }
-               HASH_ITER (hh, val->value.ov, cur, tmp) {
+               it = NULL;
+               while ((cur = ucl_iterate_object (val, &it, true)) != NULL) {
                        if (!rspamd_rcl_insert_symbol (cfg, metric, cur, FALSE, err)) {
                                return FALSE;
                        }
@@ -431,7 +433,8 @@ static gboolean
 rspamd_rcl_worker_handler (struct config_file *cfg, ucl_object_t *obj,
                gpointer ud, struct rspamd_rcl_section *section, GError **err)
 {
-       ucl_object_t *val, *cur, *tmp;
+       ucl_object_t *val, *cur;
+       ucl_object_iter_t it = NULL;
        const gchar *worker_type, *worker_bind;
        GQuark qtype;
        struct worker_conf *wrk;
@@ -492,7 +495,7 @@ rspamd_rcl_worker_handler (struct config_file *cfg, ucl_object_t *obj,
        /* Parse other attributes */
        HASH_FIND_INT (cfg->wrk_parsers, (gint *)&qtype, wparser);
        if (wparser != NULL && obj->type == UCL_OBJECT) {
-               HASH_ITER (hh, obj->value.ov, cur, tmp) {
+               while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
                        HASH_FIND_STR (wparser->parsers, ucl_object_key (cur), whandler);
                        if (whandler != NULL) {
                                if (!whandler->handler (cfg, cur, &whandler->parser, section, err)) {
index 2c1441fbbe4824710fcc9b096ced2f7f464fa82e..82f9b98024bb6e4c735b8ee2ba62111e3491510a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "config.h"
 #include "ucl/include/ucl.h"
+#include "uthash.h"
 
 #define CFG_RCL_ERROR cfg_rcl_error_quark ()
 static inline GQuark
index ead80e4df8c007f3db2c1b7e68b69be2c6d7d241..147232b5ede6a100e2be8cbab332a30d3897b5d4 100644 (file)
@@ -744,7 +744,7 @@ process_attrs (const gchar **attribute_names, const gchar **attribute_values, uc
        value = attribute_values;
        while (*attr) {
                /* Copy attributes to pool */
-               ucl_object_insert_key (top, ucl_object_fromstring_common (*value, 0, UCL_STRING_PARSE), *attr, 0, TRUE);
+               top = ucl_object_insert_key (top, ucl_object_fromstring_common (*value, 0, UCL_STRING_PARSE), *attr, 0, TRUE);
                attr ++;
                value ++;
                res = TRUE;
index 1c03fa62b6fdcea42a7d4b6a09b970db3ee41e11..543e60cf23f6794383c38b37dadf6db8b0d69389 100644 (file)
@@ -29,8 +29,8 @@
 
 static gint lua_rcl_obj_push_array (lua_State *L, ucl_object_t *obj);
 static gint lua_rcl_obj_push_simple (lua_State *L, ucl_object_t *obj, gboolean allow_array);
-static void lua_rcl_table_get (lua_State *L, ucl_object_t *top, gint idx);
-static void lua_rcl_elt_get (lua_State *L, ucl_object_t *top, gint idx);
+static ucl_object_t* lua_rcl_table_get (lua_State *L, gint idx);
+static ucl_object_t* lua_rcl_elt_get (lua_State *L, gint idx);
 
 /**
  * Push a single element of an object to lua
@@ -55,7 +55,8 @@ lua_rcl_obj_push_elt (lua_State *L, const char *key, ucl_object_t *obj)
 static gint
 lua_rcl_obj_push_obj (lua_State *L, ucl_object_t *obj)
 {
-       ucl_object_t *cur, *tmp;
+       ucl_object_t *cur;
+       ucl_object_iter_t it = NULL;
 
        if (obj->next != NULL) {
                /* Actually we need to push this as an array */
@@ -63,8 +64,8 @@ lua_rcl_obj_push_obj (lua_State *L, ucl_object_t *obj)
        }
 
        lua_newtable (L);
-       HASH_ITER (hh, obj, cur, tmp) {
-               lua_rcl_obj_push_elt (L, ucl_object_key (obj), obj);
+       while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
+               lua_rcl_obj_push_elt (L, ucl_object_key (cur), cur);
        }
 
        return 1;
@@ -140,9 +141,9 @@ lua_rcl_obj_push (lua_State *L, ucl_object_t *obj, gboolean allow_array)
 {
        switch (obj->type) {
        case UCL_OBJECT:
-               return lua_rcl_obj_push_obj (L, obj->value.ov);
+               return lua_rcl_obj_push_obj (L, obj);
        case UCL_ARRAY:
-               return lua_rcl_obj_push_array (L, obj->value.ov);
+               return lua_rcl_obj_push_array (L, obj->value.av);
        default:
                return lua_rcl_obj_push_simple (L, obj, allow_array);
        }
@@ -154,10 +155,10 @@ lua_rcl_obj_push (lua_State *L, ucl_object_t *obj, gboolean allow_array)
  * @param top
  * @param idx
  */
-static void
-lua_rcl_table_get (lua_State *L, ucl_object_t *top, gint idx)
+static ucl_object_t *
+lua_rcl_table_get (lua_State *L, gint idx)
 {
-       ucl_object_t *obj;
+       ucl_object_t *obj, *top = NULL;
        gsize keylen;
        const gchar *k;
 
@@ -167,16 +168,14 @@ lua_rcl_table_get (lua_State *L, ucl_object_t *top, gint idx)
        while (lua_next (L, -2) != 0) {
                /* copy key to avoid modifications */
                lua_pushvalue (L, -2);
-               obj = ucl_object_new ();
-               if (obj != NULL) {
-                       k = lua_tolstring (L, -1, &keylen);
-                       ucl_object_insert_key (top, obj, k, keylen, true);
-                       lua_rcl_elt_get (L, obj, -2);
-               }
-
+               k = lua_tolstring (L, -1, &keylen);
+               obj = lua_rcl_elt_get (L, -2);
+               top = ucl_object_insert_key (top, obj, k, keylen, true);
                lua_pop (L, 2);
        }
        lua_pop (L, 1);
+
+       return top;
 }
 
 /**
@@ -185,36 +184,36 @@ lua_rcl_table_get (lua_State *L, ucl_object_t *top, gint idx)
  * @param obj
  * @param idx
  */
-static void
-lua_rcl_elt_get (lua_State *L, ucl_object_t *obj, gint idx)
+static ucl_object_t *
+lua_rcl_elt_get (lua_State *L, gint idx)
 {
        gint type;
+       ucl_object_t *obj;
 
        type = lua_type (L, idx);
 
        switch (type) {
        case LUA_TFUNCTION:
                lua_pushvalue (L, idx);
+               obj = ucl_object_new ();
                obj->type = UCL_USERDATA;
                obj->value.ud = GINT_TO_POINTER (luaL_ref (L, LUA_REGISTRYINDEX));
                break;
        case LUA_TSTRING:
-               obj->type = UCL_STRING;
-               obj->value.sv = g_strdup (lua_tostring (L, idx));
+               obj = ucl_object_fromstring (lua_tostring (L, idx));
                break;
        case LUA_TNUMBER:
-               obj->type = UCL_FLOAT;
-               obj->value.dv = lua_tonumber (L, idx);
+               obj = ucl_object_fromdouble (lua_tonumber (L, idx));
                break;
        case LUA_TBOOLEAN:
-               obj->type = UCL_BOOLEAN;
-               obj->value.iv = lua_toboolean (L, idx);
+               obj = ucl_object_frombool (lua_toboolean (L, idx));
                break;
        case LUA_TTABLE:
-               obj->type = UCL_OBJECT;
-               lua_rcl_table_get (L, obj, idx);
+               obj = lua_rcl_table_get (L, idx);
                break;
        }
+
+       return obj;
 }
 
 /**
@@ -228,19 +227,15 @@ lua_rcl_obj_get (lua_State *L, gint idx)
        ucl_object_t *obj;
        gint t;
 
-       obj = ucl_object_new ();
-
-       if (obj != NULL) {
-               t = lua_type (L, idx);
-               switch (t) {
-               case LUA_TTABLE:
-                       /* We assume all tables as objects, not arrays */
-                       lua_rcl_table_get (L, obj, idx);
-                       break;
-               default:
-                       lua_rcl_elt_get (L, obj, idx);
-                       break;
-               }
+       t = lua_type (L, idx);
+       switch (t) {
+       case LUA_TTABLE:
+               /* We assume all tables as objects, not arrays */
+               obj = lua_rcl_table_get (L, idx);
+               break;
+       default:
+               obj = lua_rcl_elt_get (L, idx);
+               break;
        }
 
        return obj;
index a1c4fa04965c1ba6684069cdb33609d1a112e216..df5e322f85fec3f4eb9ef193f95dc1a05a7471b3 100644 (file)
@@ -574,7 +574,8 @@ gint
 regexp_module_config (struct config_file *cfg)
 {
        struct regexp_module_item      *cur_item;
-       ucl_object_t              *sec, *value, *tmp;
+       ucl_object_t                   *sec, *value;
+       ucl_object_iter_t               it = NULL;
        gint                            res = TRUE;
        struct regexp_json_buf         *jb, **pjb;
 
@@ -589,7 +590,7 @@ regexp_module_config (struct config_file *cfg)
        regexp_module_ctx->max_threads = 0;
        regexp_module_ctx->workers = NULL;
 
-       HASH_ITER (hh, sec, value, tmp) {
+       while ((value = ucl_iterate_object (sec, &it, true)) != NULL) {
                if (g_ascii_strncasecmp (ucl_object_key (value), "autolearn", sizeof ("autolearn") - 1) == 0) {
                        parse_autolearn_param (ucl_object_key (value), ucl_obj_tostring (value), cfg);
                }
index 5d49eccec3411fdecd6cb142d173c2a58b0ea2ee..6430bf92f1fe529dc76f1b18eb386bebeb526e09 100644 (file)
@@ -303,7 +303,8 @@ surbl_module_config (struct config_file *cfg)
        struct suffix_item             *new_suffix, *cur_suffix = NULL;
        struct surbl_bit_item          *new_bit;
 
-       ucl_object_t              *value, *cur, *cur_rule, *tmp, *cur_bit;
+       ucl_object_t                   *value, *cur, *cur_rule, *cur_bit;
+       ucl_object_iter_t               it = NULL;
        const gchar                    *redir_val;
        guint32                         bit;
        gint                            i, idx;
@@ -428,7 +429,7 @@ surbl_module_config (struct config_file *cfg)
                        }
                        cur = ucl_obj_get_key (cur_rule, "bits");
                        if (cur != NULL && cur->type == UCL_OBJECT) {
-                               HASH_ITER (hh, cur->value.ov, cur_bit, tmp) {
+                               while ((cur_bit = ucl_iterate_object (cur, &it, true)) != NULL) {
                                        if (ucl_object_key (cur_bit) != NULL && cur_bit->type == UCL_INT) {
                                                bit = ucl_obj_toint (cur_bit);
                                                new_bit = memory_pool_alloc (surbl_module_ctx->surbl_pool, sizeof (struct surbl_bit_item));
index 73937d19906c1f0b18cb4b84081ac8dc63af3599..d4254aafb4f003d873b00caea4b6eddf3a9f4ac9 100644 (file)
@@ -1,6 +1,8 @@
 SET(UCLSRC            src/ucl_util.c
                       src/ucl_parser.c
-                      src/ucl_emitter.c)
+                      src/ucl_emitter.c
+                      src/ucl_hash.c
+                      src/xxhash.c)
 
 ADD_LIBRARY(rspamd-ucl ${LINK_TYPE} ${UCLSRC})
 SET_TARGET_PROPERTIES(rspamd-ucl PROPERTIES VERSION ${RSPAMD_VERSION})
index fe56a04daf58912535ad6d7b9a791b108cc495aa..aaad4a9a99cf07fa8693493038f514491ec8c5c7 100644 (file)
 #include <stdbool.h>
 #include <stdarg.h>
 #include <stdio.h>
-
 #include "config.h"
-#include "uthash.h"
-#include "utlist.h"
 
 /**
  * @file rcl.h
 #define UCL_FREE(size, ptr) free(ptr)
 #endif
 
+#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define UCL_WARN_UNUSED_RESULT               \
+  __attribute__((warn_unused_result))
+#else
+#define UCL_WARN_UNUSED_RESULT
+#endif
+
 enum ucl_error {
        UCL_EOK = 0,   //!< UCL_EOK
        UCL_ESYNTAX,   //!< UCL_ESYNTAX
@@ -153,17 +157,19 @@ typedef struct ucl_object_s {
                int64_t iv;                                                     /**< int value of an object */
                const char *sv;                                 /**< string value of an object */
                double dv;                                                      /**< double value of an object */
-               struct ucl_object_s *ov;                        /**< array or hash                      */
+               struct ucl_object_s *av;                        /**< array                                      */
+               void *ov;                                                       /**< object                                     */
                void* ud;                                                       /**< opaque user data           */
        } value;
-       enum ucl_type type;                                             /**< real type                          */
-       short int ref;                                                  /**< reference count            */
-       short int flags;                                                /**< object flags                       */
-       size_t len;                                                             /**< size of an object          */
+       const char *key;                                                /**< key of an object           */
        struct ucl_object_s *next;                              /**< array handle                       */
        struct ucl_object_s *prev;                              /**< array handle                       */
        unsigned char* trash_stack[2];                  /**< pointer to allocated chunks */
-       UT_hash_handle hh;                                              /**< hash handle                        */
+       unsigned keylen;                                                /**< lenght of a key            */
+       unsigned len;                                                   /**< size of an object          */
+       enum ucl_type type;                                             /**< real type                          */
+       uint16_t ref;                                                   /**< reference count            */
+       uint16_t flags;                                                 /**< object flags                       */
 } ucl_object_t;
 
 
@@ -185,6 +191,7 @@ char* ucl_copy_value_trash (ucl_object_t *obj);
  * Creates a new object
  * @return new object
  */
+static inline ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT;
 static inline ucl_object_t *
 ucl_object_new (void)
 {
@@ -204,7 +211,8 @@ ucl_object_new (void)
  * @param flags conversion flags
  * @return new object
  */
-ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags);
+ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len,
+               enum ucl_string_flags flags) UCL_WARN_UNUSED_RESULT;
 
 /**
  * Create a UCL object from the specified string
@@ -296,7 +304,7 @@ ucl_object_frombool (bool bv)
  * @return new value of top object
  */
 ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
-               const char *key, size_t keylen, bool copy_key);
+               const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;
 
 /**
  * Append an element to the array object
@@ -304,9 +312,13 @@ ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
  * @param eltelement to append (must NOT be NULL)
  * @return new value of top object
  */
+static inline ucl_object_t * ucl_array_append (ucl_object_t *top,
+               ucl_object_t *elt) UCL_WARN_UNUSED_RESULT;
 static inline ucl_object_t *
 ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
 {
+       ucl_object_t *head;
+
        if (elt == NULL) {
                return NULL;
        }
@@ -314,9 +326,17 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
        if (top == NULL) {
                top = ucl_object_new ();
                top->type = UCL_ARRAY;
+               top->value.av = elt;
+               elt->next = NULL;
+               elt->prev = elt;
+       }
+       else {
+               head = top->value.av;
+               elt->prev = head->prev;
+               head->prev->next = elt;
+               head->prev = elt;
+               elt->next = NULL;
        }
-
-       DL_APPEND (top->value.ov, elt);
 
        return top;
 }
@@ -327,10 +347,24 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
  * @param elt new element
  * @return new head if applicable
  */
+static inline ucl_object_t * ucl_elt_append (ucl_object_t *head,
+               ucl_object_t *elt) UCL_WARN_UNUSED_RESULT;
 static inline ucl_object_t *
 ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
 {
-       DL_APPEND (head, elt);
+
+       if (head == NULL) {
+               elt->next = NULL;
+               elt->prev = elt;
+               head = elt;
+       }
+       else {
+               elt->prev = head->prev;
+               head->prev->next = elt;
+               head->prev = elt;
+               elt->next = NULL;
+       }
+
        return head;
 }
 
@@ -497,7 +531,7 @@ ucl_obj_tostring (ucl_object_t *obj)
  * @return string value
  */
 static inline const char *
-ucl_obj_tostring_forced (ucl_object_t *obj)
+ucl_object_tostring_forced (ucl_object_t *obj)
 {
        return ucl_copy_value_trash (obj);
 }
@@ -548,21 +582,7 @@ ucl_obj_tolstring (ucl_object_t *obj, size_t *tlen)
  * @param key key to search
  * @return object matched the specified key or NULL if key is not found
  */
-static inline ucl_object_t *
-ucl_obj_get_key (ucl_object_t *obj, const char *key)
-{
-       size_t keylen;
-       ucl_object_t *ret;
-
-       if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
-               return NULL;
-       }
-
-       keylen = strlen (key);
-       HASH_FIND (hh, obj->value.ov, key, keylen, ret);
-
-       return ret;
-}
+ucl_object_t * ucl_obj_get_key (ucl_object_t *obj, const char *key);
 
 /**
  * Return object identified by a fixed size key in the specified object
@@ -571,19 +591,7 @@ ucl_obj_get_key (ucl_object_t *obj, const char *key)
  * @param klen length of a key
  * @return object matched the specified key or NULL if key is not found
  */
-static inline ucl_object_t *
-ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen)
-{
-       ucl_object_t *ret;
-
-       if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
-               return NULL;
-       }
-
-       HASH_FIND (hh, obj->value.ov, key, klen, ret);
-
-       return ret;
-}
+ucl_object_t *ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen);
 
 /**
  * Returns a key of an object as a NULL terminated string
@@ -605,8 +613,8 @@ ucl_object_key (ucl_object_t *obj)
 static inline const char *
 ucl_object_keyl (ucl_object_t *obj, size_t *len)
 {
-       *len = obj->hh.keylen;
-       return obj->hh.key;
+       *len = obj->keylen;
+       return obj->key;
 }
 
 /**
@@ -723,4 +731,16 @@ unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
  */
 bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len);
 
+typedef void* ucl_object_iter_t;
+
+/**
+ * Get next key from an object
+ * @param obj object to iterate
+ * @param iter opaque iterator, must be set to NULL on the first call:
+ * ucl_object_iter_t it = NULL;
+ * while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
+ * @return the next object or NULL
+ */
+ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values);
+
 #endif /* RCL_H_ */
index 1cf7f27989cde44b987afaa92c10fcccc04f5e31..2973f1da2a3576f1f58f50bb6880673cc19d387e 100644 (file)
@@ -141,7 +141,8 @@ ucl_print_float (UT_string *buf, double val)
 static void
 ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
 {
-       ucl_object_t *cur, *tmp;
+       ucl_object_t *cur;
+       ucl_hash_iter_t it = NULL;
 
        if (start_tabs) {
                ucl_add_tabs (buf, tabs, compact);
@@ -152,10 +153,10 @@ ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
        else {
                utstring_append_len (buf, "{\n", 2);
        }
-       HASH_ITER (hh, obj, cur, tmp) {
+       while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
                ucl_add_tabs (buf, tabs + 1, compact);
-               if (cur->hh.keylen > 0) {
-                       ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+               if (cur->keylen > 0) {
+                       ucl_elt_string_write_json (cur->key, cur->keylen, buf);
                }
                else {
                        utstring_append_len (buf, "null", 4);
@@ -167,7 +168,7 @@ ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
                        utstring_append_len (buf, ": ", 2);
                }
                ucl_obj_write_json (cur, buf, tabs + 1, false, compact);
-               if (cur->hh.next != NULL) {
+               if (ucl_hash_iter_has_next (it)) {
                        if (compact) {
                                utstring_append_c (buf, ',');
                        }
@@ -256,10 +257,10 @@ 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_OBJECT:
-               ucl_elt_obj_write_json (obj->value.ov, buf, tabs, start_tabs, compact);
+               ucl_elt_obj_write_json (obj, buf, tabs, start_tabs, compact);
                break;
        case UCL_ARRAY:
-               ucl_elt_array_write_json (obj->value.ov, buf, tabs, start_tabs, compact);
+               ucl_elt_array_write_json (obj->value.av, buf, tabs, start_tabs, compact);
                break;
        case UCL_USERDATA:
                break;
@@ -335,7 +336,8 @@ ucl_object_emit_json (ucl_object_t *obj, bool compact)
 static void
 ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
 {
-       ucl_object_t *cur, *tmp;
+       ucl_object_t *cur, *cur_obj;
+       ucl_hash_iter_t it = NULL;
 
        if (start_tabs) {
                ucl_add_tabs (buf, tabs, is_top);
@@ -344,26 +346,28 @@ ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, boo
                utstring_append_len (buf, "{\n", 2);
        }
 
-       HASH_ITER (hh, obj, cur, tmp) {
-               ucl_add_tabs (buf, tabs + 1, is_top);
-               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);
-               }
-               else {
-                       utstring_append_c (buf, ' ');
-               }
-               ucl_elt_write_rcl (cur, buf, is_top ? tabs : tabs + 1, false, false, true);
-               if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
-                       utstring_append_len (buf, ";\n", 2);
-               }
-               else {
-                       utstring_append_c (buf, '\n');
+       while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
+               LL_FOREACH (cur, cur_obj) {
+                       ucl_add_tabs (buf, tabs + 1, is_top);
+                       if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+                               ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, buf);
+                       }
+                       else {
+                               utstring_append_len (buf, cur_obj->key, cur_obj->keylen);
+                       }
+                       if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
+                               utstring_append_len (buf, " = ", 3);
+                       }
+                       else {
+                               utstring_append_c (buf, ' ');
+                       }
+                       ucl_elt_write_rcl (cur_obj, buf, is_top ? tabs : tabs + 1, false, false, false);
+                       if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
+                               utstring_append_len (buf, ";\n", 2);
+                       }
+                       else {
+                               utstring_append_c (buf, '\n');
+                       }
                }
        }
 
@@ -437,10 +441,10 @@ 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_OBJECT:
-                       ucl_elt_obj_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top);
+                       ucl_elt_obj_write_rcl (obj, buf, tabs, start_tabs, is_top);
                        break;
                case UCL_ARRAY:
-                       ucl_elt_array_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top);
+                       ucl_elt_array_write_rcl (obj->value.av, buf, tabs, start_tabs, is_top);
                        break;
                case UCL_USERDATA:
                        break;
@@ -475,7 +479,8 @@ ucl_object_emit_rcl (ucl_object_t *obj)
 static void
 ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
 {
-       ucl_object_t *cur, *tmp;
+       ucl_object_t *cur;
+       ucl_hash_iter_t it = NULL;
 
        if (start_tabs) {
                ucl_add_tabs (buf, tabs, is_top);
@@ -484,13 +489,13 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
                utstring_append_len (buf, ": {\n", 4);
        }
 
-       HASH_ITER (hh, obj, cur, tmp) {
+       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) {
-                       ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+                       ucl_elt_string_write_json (cur->key, cur->keylen, buf);
                }
                else {
-                       utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+                       utstring_append_len (buf, cur->key, cur->keylen);
                }
                if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
                        utstring_append_len (buf, " : ", 3);
@@ -582,10 +587,10 @@ 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_OBJECT:
-                       ucl_elt_obj_write_yaml (obj->value.ov, buf, tabs, start_tabs, is_top);
+                       ucl_elt_obj_write_yaml (obj, buf, tabs, start_tabs, is_top);
                        break;
                case UCL_ARRAY:
-                       ucl_elt_array_write_yaml (obj->value.ov, buf, tabs, start_tabs, is_top);
+                       ucl_elt_array_write_yaml (obj->value.av, buf, tabs, start_tabs, is_top);
                        break;
                case UCL_USERDATA:
                        break;
@@ -617,6 +622,10 @@ ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
        UT_string *buf = NULL;
        unsigned char *res = NULL;
 
+       if (obj == NULL) {
+               return NULL;
+       }
+
        if (emit_type == UCL_EMIT_JSON) {
                buf = ucl_object_emit_json (obj, false);
        }
index 393ecf85a0a95c62e4461af0e2cafc9e8d52371d..a6d8e096bb861b20d1ef320298d710bfcd63ae37 100644 (file)
 
 #include "utlist.h"
 #include "utstring.h"
+#include "uthash.h"
 #include "ucl.h"
+#include "ucl_hash.h"
+#include "xxhash.h"
 
 #ifdef HAVE_OPENSSL
 #include <openssl/evp.h>
@@ -249,4 +252,26 @@ ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t l
 int ucl_maybe_parse_number (ucl_object_t *obj,
                const char *start, const char *end, const char **pos, bool allow_double);
 
+
+static inline ucl_object_t *
+ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
+{
+       return (ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
+}
+
+static inline ucl_hash_t *
+ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
+
+static inline ucl_hash_t *
+ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj)
+{
+       if (hashlin == NULL) {
+               hashlin = ucl_hash_create ();
+       }
+       ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);
+
+       return hashlin;
+}
+
+
 #endif /* UCL_INTERNAL_H_ */
index e125caee4d8b37aed8789aa2b1da34ec1cc25147..dd0ac48963b9409c2143a96e929d5ef8ce6ed2b2 100644 (file)
@@ -233,13 +233,13 @@ ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
        return false;
 }
 
-static inline size_t
+static inline ssize_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)
 {
-       size_t ret = 0;
+       ssize_t ret = -1;
 
        if (need_unescape || need_lowercase || !(parser->flags & UCL_PARSER_ZEROCOPY)) {
                /* Copy string */
@@ -275,8 +275,8 @@ ucl_maybe_parse_number (ucl_object_t *obj,
        const char *p = start, *c = start;
        char *endptr;
        bool got_dot = false, got_exp = false, need_double = false, is_date = false, valid_start = false;
-       double dv;
-       int64_t lv;
+       double dv = 0;
+       int64_t lv = 0;
 
        if (*p == '-') {
                p ++;
@@ -604,8 +604,9 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
        const char *key;
        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;
+       ucl_object_t *nobj, *tobj;
+       ucl_hash_t *container;
+       ssize_t keylen;
 
        p = chunk->pos;
 
@@ -724,15 +725,22 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
        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_PARSER_KEY_LOWERCASE);
-       if (keylen == 0) {
+       if (keylen == -1) {
+               return false;
+       }
+       else if (keylen == 0) {
+               ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
                return false;
        }
 
        container = parser->stack->obj->value.ov;
-       HASH_FIND (hh, container, key, keylen, tobj);
+       nobj->key = key;
+       nobj->keylen = keylen;
+       tobj = ucl_hash_search_obj (container, nobj);
        if (tobj == NULL) {
-               DL_APPEND (tobj, nobj);
-               HASH_ADD_KEYPTR (hh, container, key, keylen, nobj);
+               container = ucl_hash_insert_object (container, nobj);
+               nobj->prev = nobj;
+               nobj->next = NULL;
        }
        else {
                DL_APPEND (tobj, nobj);
@@ -879,10 +887,10 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                        if (parser->stack->obj->type == UCL_ARRAY) {
                                /* Object must be allocated */
                                obj = ucl_object_new ();
-                               t = parser->stack->obj->value.ov;
+                               t = parser->stack->obj->value.av;
                                DL_APPEND (t, obj);
                                parser->cur_obj = obj;
-                               parser->stack->obj->value.ov = t;
+                               parser->stack->obj->value.av = t;
                        }
                        else {
                                /* Object has been already allocated */
@@ -899,7 +907,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                        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)) == 0) {
+                                       &obj->value.sv, str_len, need_unescape, false)) == -1) {
                                return false;
                        }
                        obj->len = str_len;
@@ -910,7 +918,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                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;
@@ -957,7 +965,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                                                }
                                                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)) == 0) {
+                                                       &obj->value.sv, str_len - 1, false, false)) == -1) {
                                                        return false;
                                                }
                                                obj->len = str_len;
@@ -1003,7 +1011,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                                                }
                                                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)) == 0) {
+                                                               &obj->value.sv, str_len, false, false)) == -1) {
                                                        return false;
                                                }
                                                obj->len = str_len;
@@ -1035,7 +1043,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
                                        }
                                        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)) == 0) {
+                                                       &obj->value.sv, str_len, false, false)) == -1) {
                                                return false;
                                        }
                                        obj->len = str_len;
@@ -1217,7 +1225,7 @@ 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, *macro_start = NULL;
+       const unsigned char *p, *c = NULL, *macro_start = NULL;
        size_t macro_len = 0;
        struct ucl_macro *macro = NULL;
 
@@ -1246,6 +1254,7 @@ ucl_state_machine (struct ucl_parser *parser)
                                else {
                                        parser->state = UCL_STATE_KEY;
                                        obj->type = UCL_OBJECT;
+                                       obj->value.ov = ucl_hash_create ();
                                        if (*p == '{') {
                                                ucl_chunk_skipc (chunk, p);
                                        }
index 09123e91e4f0a19a8b1fff5ea007c3219fb7aced..10377e295c2cdf30deba546c8d1eb98eac1193a0 100644 (file)
@@ -53,7 +53,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
                }
 
                if (obj->type == UCL_ARRAY) {
-                       sub = obj->value.ov;
+                       sub = obj->value.av;
                        while (sub != NULL) {
                                tmp = sub->next;
                                ucl_object_free_internal (sub, false);
@@ -61,10 +61,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
                        }
                }
                else if (obj->type == UCL_OBJECT) {
-                       HASH_ITER (hh, obj->value.ov, sub, tmp) {
-                               HASH_DELETE (hh, obj->value.ov, sub);
-                               ucl_object_free_internal (sub, true);
-                       }
+                       ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_obj_free);
                }
                tmp = obj->next;
                UCL_FREE (sizeof (ucl_object_t), obj);
@@ -179,13 +176,13 @@ ucl_unescape_json_string (char *str, size_t len)
 char *
 ucl_copy_key_trash (ucl_object_t *obj)
 {
-       if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->hh.key != NULL) {
-               obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->hh.keylen + 1);
+       if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
+               obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
                if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
-                       memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->hh.key, obj->hh.keylen);
-                       obj->trash_stack[UCL_TRASH_KEY][obj->hh.keylen] = '\0';
+                       memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
+                       obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
                }
-               obj->hh.key = obj->trash_stack[UCL_TRASH_KEY];
+               obj->key = obj->trash_stack[UCL_TRASH_KEY];
                obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
        }
 
@@ -278,7 +275,6 @@ ucl_parser_get_error(struct ucl_parser *parser)
 bool
 ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
 {
-       struct ucl_pubkey *nkey;
 #ifndef HAVE_OPENSSL
        ucl_create_err (&parser->err, "cannot check signatures without openssl");
        return false;
@@ -287,6 +283,7 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
        ucl_create_err (err, "cannot check signatures, openssl version is unsupported");
        return EXIT_FAILURE;
 # else
+       struct ucl_pubkey *nkey;
        BIO *mem;
 
        mem = BIO_new_mem_buf ((void *)key, len);
@@ -519,8 +516,8 @@ ucl_include_url (const unsigned char *data, size_t len,
 {
 
        bool res;
-       unsigned char *buf = NULL, *sigbuf = NULL;
-       size_t buflen = 0, siglen = 0;
+       unsigned char *buf = NULL;
+       size_t buflen = 0;
        struct ucl_chunk *chunk;
        char urlbuf[PATH_MAX];
 
@@ -532,6 +529,8 @@ ucl_include_url (const unsigned char *data, size_t len,
 
        if (check_signature) {
 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
+               unsigned char *sigbuf = NULL;
+               size_t siglen = 0;
                /* We need to check signature first */
                snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
                if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, &parser->err)) {
@@ -576,8 +575,8 @@ ucl_include_file (const unsigned char *data, size_t len,
 {
        bool res;
        struct ucl_chunk *chunk;
-       unsigned char *buf = NULL, *sigbuf = NULL;
-       size_t buflen, siglen;
+       unsigned char *buf = NULL;
+       size_t buflen;
        char filebuf[PATH_MAX], realbuf[PATH_MAX];
 
        snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
@@ -594,6 +593,8 @@ ucl_include_file (const unsigned char *data, size_t len,
 
        if (check_signature) {
 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
+               unsigned char *sigbuf = NULL;
+               size_t siglen = 0;
                /* We need to check signature first */
                snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
                if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err)) {
@@ -870,6 +871,11 @@ ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
                top = ucl_object_new ();
                top->type = UCL_OBJECT;
        }
+
+       if (top->value.ov == NULL) {
+               top->value.ov = ucl_hash_create ();
+       }
+
        if (keylen == 0) {
                keylen = strlen (key);
        }
@@ -881,11 +887,15 @@ ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
                }
        }
 
-       HASH_FIND (hh, top->value.ov, key, keylen, found);
+       elt->key = key;
+       elt->keylen = keylen;
+
+       found = ucl_hash_search_obj (top->value.ov, elt);
 
        if (!found) {
-               HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt);
+               top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
        }
+
        DL_APPEND (found, elt);
 
        if (copy_key) {
@@ -894,3 +904,83 @@ ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
 
        return top;
 }
+
+ucl_object_t *
+ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen)
+{
+       ucl_object_t *ret, srch;
+
+       if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
+               return NULL;
+       }
+
+       srch.key = key;
+       srch.keylen = klen;
+       ret = ucl_hash_search_obj (obj->value.ov, &srch);
+
+       return ret;
+}
+
+ucl_object_t *
+ucl_obj_get_key (ucl_object_t *obj, const char *key)
+{
+       size_t klen;
+       ucl_object_t *ret, srch;
+
+       if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
+               return NULL;
+       }
+
+       klen = strlen (key);
+       srch.key = key;
+       srch.keylen = klen;
+       ret = ucl_hash_search_obj (obj->value.ov, &srch);
+
+       return ret;
+}
+
+ucl_object_t*
+ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
+{
+       ucl_object_t *elt;
+
+       if (expand_values) {
+               switch (obj->type) {
+               case UCL_OBJECT:
+                       return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
+                       break;
+               case UCL_ARRAY:
+                       elt = *iter;
+                       if (elt == NULL) {
+                               elt = obj->value.av;
+                               if (elt == NULL) {
+                                       return NULL;
+                               }
+                       }
+                       else if (elt == obj->value.av) {
+                               return NULL;
+                       }
+                       *iter = elt->next ? elt->next : obj->value.av;
+                       return elt;
+               default:
+                       /* Go to linear iteration */
+                       break;
+               }
+       }
+       /* Treat everything as a linear list */
+       elt = *iter;
+       if (elt == NULL) {
+               elt = obj;
+               if (elt == NULL) {
+                       return NULL;
+               }
+       }
+       else if (elt == obj) {
+               return NULL;
+       }
+       *iter = elt->next ? elt->next : obj;
+       return elt;
+
+       /* Not reached */
+       return NULL;
+}