From bbf9405abd6caff16f7680e2d8918c71579e2161 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 2 Nov 2013 22:12:39 +0000 Subject: [PATCH] Sync with libucl. --- src/cfg_rcl.c | 13 ++-- src/cfg_rcl.h | 1 + src/cfg_xml.c | 2 +- src/lua/lua_rcl.c | 75 +++++++++++----------- src/plugins/regexp.c | 5 +- src/plugins/surbl.c | 5 +- src/ucl/CMakeLists.txt | 4 +- src/ucl/include/ucl.h | 110 ++++++++++++++++++-------------- src/ucl/src/ucl_emitter.c | 81 +++++++++++++----------- src/ucl/src/ucl_internal.h | 25 ++++++++ src/ucl/src/ucl_parser.c | 45 ++++++++------ src/ucl/src/ucl_util.c | 124 ++++++++++++++++++++++++++++++++----- 12 files changed, 323 insertions(+), 167 deletions(-) diff --git a/src/cfg_rcl.c b/src/cfg_rcl.c index 2190f648a..0a251e7e1 100644 --- a/src/cfg_rcl.c +++ b/src/cfg_rcl.c @@ -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)) { diff --git a/src/cfg_rcl.h b/src/cfg_rcl.h index 2c1441fbb..82f9b9802 100644 --- a/src/cfg_rcl.h +++ b/src/cfg_rcl.h @@ -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 diff --git a/src/cfg_xml.c b/src/cfg_xml.c index ead80e4df..147232b5e 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -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; diff --git a/src/lua/lua_rcl.c b/src/lua/lua_rcl.c index 1c03fa62b..543e60cf2 100644 --- a/src/lua/lua_rcl.c +++ b/src/lua/lua_rcl.c @@ -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; diff --git a/src/plugins/regexp.c b/src/plugins/regexp.c index a1c4fa049..df5e322f8 100644 --- a/src/plugins/regexp.c +++ b/src/plugins/regexp.c @@ -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); } diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c index 5d49eccec..6430bf92f 100644 --- a/src/plugins/surbl.c +++ b/src/plugins/surbl.c @@ -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)); diff --git a/src/ucl/CMakeLists.txt b/src/ucl/CMakeLists.txt index 73937d199..d4254aafb 100644 --- a/src/ucl/CMakeLists.txt +++ b/src/ucl/CMakeLists.txt @@ -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}) diff --git a/src/ucl/include/ucl.h b/src/ucl/include/ucl.h index fe56a04da..aaad4a9a9 100644 --- a/src/ucl/include/ucl.h +++ b/src/ucl/include/ucl.h @@ -31,10 +31,7 @@ #include #include #include - #include "config.h" -#include "uthash.h" -#include "utlist.h" /** * @file rcl.h @@ -77,6 +74,13 @@ #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_ */ diff --git a/src/ucl/src/ucl_emitter.c b/src/ucl/src/ucl_emitter.c index 1cf7f2798..2973f1da2 100644 --- a/src/ucl/src/ucl_emitter.c +++ b/src/ucl/src/ucl_emitter.c @@ -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); } diff --git a/src/ucl/src/ucl_internal.h b/src/ucl/src/ucl_internal.h index 393ecf85a..a6d8e096b 100644 --- a/src/ucl/src/ucl_internal.h +++ b/src/ucl/src/ucl_internal.h @@ -37,7 +37,10 @@ #include "utlist.h" #include "utstring.h" +#include "uthash.h" #include "ucl.h" +#include "ucl_hash.h" +#include "xxhash.h" #ifdef HAVE_OPENSSL #include @@ -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_ */ diff --git a/src/ucl/src/ucl_parser.c b/src/ucl/src/ucl_parser.c index e125caee4..dd0ac4896 100644 --- a/src/ucl/src/ucl_parser.c +++ b/src/ucl/src/ucl_parser.c @@ -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); } diff --git a/src/ucl/src/ucl_util.c b/src/ucl/src/ucl_util.c index 09123e91e..10377e295 100644 --- a/src/ucl/src/ucl_util.c +++ b/src/ucl/src/ucl_util.c @@ -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; +} -- 2.39.5