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)) {
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));
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;
}
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;
/* 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)) {
#include "config.h"
#include "ucl/include/ucl.h"
+#include "uthash.h"
#define CFG_RCL_ERROR cfg_rcl_error_quark ()
static inline GQuark
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;
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
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 */
}
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;
{
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);
}
* @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;
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;
}
/**
* @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;
}
/**
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;
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;
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);
}
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;
}
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));
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})
#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
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;
* 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)
{
* @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
* @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
* @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;
}
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;
}
* @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;
}
* @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);
}
* @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
* @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
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;
}
/**
*/
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_ */
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);
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);
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, ',');
}
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;
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);
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');
+ }
}
}
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;
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);
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);
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;
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);
}
#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>
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_ */
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 */
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 ++;
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;
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);
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 */
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;
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;
}
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;
}
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;
}
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;
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;
else {
parser->state = UCL_STATE_KEY;
obj->type = UCL_OBJECT;
+ obj->value.ov = ucl_hash_create ();
if (*p == '{') {
ucl_chunk_skipc (chunk, p);
}
}
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);
}
}
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);
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;
}
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;
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);
{
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];
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)) {
{
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);
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)) {
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);
}
}
}
- 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) {
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;
+}