Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Import from libucl
Baptiste Daroussin committed 12 years ago
commit 5dc36026fc60c64763d82a69ef2921b3cd78e913
parent a2f64bd
19 files changed +3247 -354
modified external/libucl/Makefile
@@ -4,8 +4,10 @@ INTERNALLIB=
SRCS=	src/ucl_emitter.c \
	src/ucl_parser.c \
	src/ucl_util.c \
+
	src/ucl_hash.c \
+
	src/xxhash.c

-
CFLAGS=	-I${.CURDIR}/../uthash \
+
CFLAGS=	-I${.CURDIR}/uthash \
	-I${.CURDIR}/include \
	-I${.CURDIR}/src \
	-fPIC
modified external/libucl/include/ucl.h
@@ -32,9 +32,6 @@
#include <stdarg.h>
#include <stdio.h>

-
#include "uthash.h"
-
#include "utlist.h"
-

/**
 * @file rcl.h
 * RCL is an rspamd configuration language, which is a form of
@@ -76,6 +73,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
@@ -152,17 +156,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;


@@ -184,6 +190,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)
{
@@ -203,7 +210,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
@@ -295,7 +303,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
@@ -303,9 +311,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;
	}
@@ -313,9 +325,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;
}
@@ -326,10 +346,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;
}

@@ -496,7 +530,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);
}
@@ -547,21 +581,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
@@ -570,19 +590,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
@@ -604,8 +612,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;
}

/**
@@ -722,4 +730,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_ */
modified external/libucl/src/ucl_emitter.c
@@ -142,6 +142,7 @@ 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_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;
@@ -476,6 +480,7 @@ 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_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);
	}
added external/libucl/src/ucl_hash.c
@@ -0,0 +1,105 @@
+
/* Copyright (c) 2013, Vsevolod Stakhov
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 *       * Redistributions of source code must retain the above copyright
+
 *         notice, this list of conditions and the following disclaimer.
+
 *       * Redistributions in binary form must reproduce the above copyright
+
 *         notice, this list of conditions and the following disclaimer in the
+
 *         documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include "ucl_hash.h"
+
#include "utlist.h"
+

+
ucl_hash_t*
+
ucl_hash_create (void)
+
{
+
	ucl_hash_t *new;
+

+
	new = UCL_ALLOC (sizeof (ucl_hash_t));
+
	if (new != NULL) {
+
		new->buckets = NULL;
+
	}
+
	return new;
+
}
+

+
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
+
{
+
	ucl_hash_node_t *elt, *tmp;
+

+
	HASH_ITER (hh, hashlin->buckets, elt, tmp) {
+
		HASH_DELETE (hh, hashlin->buckets, elt);
+
		if (func) {
+
			func (elt->data);
+
		}
+
		UCL_FREE (sizeof (ucl_hash_node_t), elt);
+
	}
+
	UCL_FREE (sizeof (ucl_hash_t), hashlin);
+
}
+

+
void
+
ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen)
+
{
+
	ucl_hash_node_t *node;
+

+
	node = UCL_ALLOC (sizeof (ucl_hash_node_t));
+
	node->data = obj;
+
	HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
+
}
+

+
void*
+
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
+
{
+
	ucl_hash_node_t *elt = *iter;
+

+
	if (elt == NULL) {
+
		if (hashlin->buckets == NULL) {
+
			return NULL;
+
		}
+
		elt = hashlin->buckets;
+
		if (elt == NULL) {
+
			return NULL;
+
		}
+
	}
+
	else if (elt == hashlin->buckets) {
+
		return NULL;
+
	}
+

+
	*iter = elt->hh.next ? elt->hh.next : hashlin->buckets;
+
	return elt->data;
+
}
+

+
bool
+
ucl_hash_iter_has_next (ucl_hash_iter_t iter)
+
{
+
	ucl_hash_node_t *elt = iter;
+

+
	return (elt != NULL && elt->hh.next != NULL);
+
}
+

+

+
ucl_object_t*
+
ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
+
{
+
	ucl_hash_node_t *found;
+

+
	HASH_FIND (hh, hashlin->buckets, key, keylen, found);
+

+
	if (found) {
+
		return found->data;
+
	}
+
	return NULL;
+
}
added external/libucl/src/ucl_hash.h
@@ -0,0 +1,86 @@
+
/* Copyright (c) 2013, Vsevolod Stakhov
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 *       * Redistributions of source code must retain the above copyright
+
 *         notice, this list of conditions and the following disclaimer.
+
 *       * Redistributions in binary form must reproduce the above copyright
+
 *         notice, this list of conditions and the following disclaimer in the
+
 *         documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#ifndef __UCL_HASH_H
+
#define __UCL_HASH_H
+

+
#include "ucl.h"
+
#include "uthash.h"
+

+
/******************************************************************************/
+

+
typedef struct ucl_hash_node_s
+
{
+
	ucl_object_t *data;
+
	UT_hash_handle hh;
+
} ucl_hash_node_t;
+

+
typedef int ucl_hash_cmp_func (const void* void_a, const void* void_b);
+
typedef void ucl_hash_free_func (void *ptr);
+
typedef void* ucl_hash_iter_t;
+

+

+
/**
+
 * Linear chained hashtable.
+
 */
+
typedef struct ucl_hash_struct
+
{
+
	ucl_hash_node_t *buckets; /**< array of hash buckets. One list for each hash modulus. */
+
} ucl_hash_t;
+

+

+
/**
+
 * Initializes the hashtable.
+
 */
+
ucl_hash_t* ucl_hash_create (void);
+

+
/**
+
 * Deinitializes the hashtable.
+
 */
+
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
+

+
/**
+
 * Inserts an element in the the hashtable.
+
 */
+
void ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen);
+

+
/**
+
 * Searches an element in the hashtable.
+
 */
+
ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen);
+

+

+
/**
+
 * Iterate over hash table
+
 * @param hashlin hash
+
 * @param iter iterator (must be NULL on first iteration)
+
 * @return the next object
+
 */
+
void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
+

+
/**
+
 * Check whether an iterator has next element
+
 */
+
bool ucl_hash_iter_has_next (ucl_hash_iter_t iter);
+

+
#endif
modified external/libucl/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 <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_ */
modified external/libucl/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);
					}
modified external/libucl/src/ucl_util.c
@@ -43,6 +43,7 @@ static void
ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
{
	ucl_object_t *sub, *tmp;
+
	ucl_hash_iter_t it = NULL;

	while (obj != NULL) {
		if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
@@ -53,7 +54,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 +62,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 +177,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;
	}

@@ -534,7 +532,7 @@ ucl_include_url (const unsigned char *data, size_t len,
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
		/* We need to check signature first */
		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
-
		if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, err)) {
+
		if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, &parser->err)) {
			return false;
		}
		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
@@ -596,11 +594,11 @@ ucl_include_file (const unsigned char *data, size_t len,
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
		/* We need to check signature first */
		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
-
		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, err)) {
+
		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err)) {
			return false;
		}
		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
-
			ucl_create_err (err, "cannot verify file %s: %s",
+
			ucl_create_err (&parser->err, "cannot verify file %s: %s",
							filebuf,
							ERR_error_string (ERR_get_error (), NULL));
			munmap (sigbuf, siglen);
@@ -870,6 +868,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 +884,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 +901,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;
+
}
added external/libucl/src/xxhash.c
@@ -0,0 +1,475 @@
+
/*
+
xxHash - Fast Hash algorithm
+
Copyright (C) 2012-2013, Yann Collet.
+
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are
+
met:
+

+
* Redistributions of source code must retain the above copyright
+
notice, this list of conditions and the following disclaimer.
+
* Redistributions in binary form must reproduce the above
+
copyright notice, this list of conditions and the following disclaimer
+
in the documentation and/or other materials provided with the
+
distribution.
+

+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

+
You can contact the author at :
+
- xxHash source repository : http://code.google.com/p/xxhash/
+
*/
+

+

+
//**************************************
+
// Tuning parameters
+
//**************************************
+
// Unaligned memory access is automatically enabled for "common" CPU, such as x86.
+
// For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.
+
// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.
+
// You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).
+
#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+
#  define XXH_USE_UNALIGNED_ACCESS 1
+
#endif
+

+
// XXH_ACCEPT_NULL_INPUT_POINTER :
+
// If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
+
// When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
+
// This option has a very small performance cost (only measurable on small inputs).
+
// By default, this option is disabled. To enable it, uncomment below define :
+
//#define XXH_ACCEPT_NULL_INPUT_POINTER 1
+

+
// XXH_FORCE_NATIVE_FORMAT :
+
// By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
+
// Results are therefore identical for little-endian and big-endian CPU.
+
// This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+
// Should endian-independance be of no importance for your application, you may set the #define below to 1.
+
// It will improve speed for Big-endian CPU.
+
// This option has no impact on Little_Endian CPU.
+
#define XXH_FORCE_NATIVE_FORMAT 0
+

+

+
//**************************************
+
// Compiler Specific Options
+
//**************************************
+
// Disable some Visual warning messages
+
#ifdef _MSC_VER  // Visual Studio
+
#  pragma warning(disable : 4127)      // disable: C4127: conditional expression is constant
+
#endif
+

+
#ifdef _MSC_VER    // Visual Studio
+
#  define forceinline static __forceinline
+
#else 
+
#  ifdef __GNUC__
+
#    define forceinline static inline __attribute__((always_inline))
+
#  else
+
#    define forceinline static inline
+
#  endif
+
#endif
+

+

+
//**************************************
+
// Includes & Memory related functions
+
//**************************************
+
#include "xxhash.h"
+
// Modify the local functions below should you wish to use some other memory related routines
+
// for malloc(), free()
+
#include <stdlib.h>
+
forceinline void* XXH_malloc(size_t s) { return malloc(s); }
+
forceinline void  XXH_free  (void* p)  { free(p); }
+
// for memcpy()
+
#include <string.h>
+
forceinline void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+

+

+
//**************************************
+
// Basic Types
+
//**************************************
+
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   // C99
+
# include <stdint.h>
+
  typedef uint8_t  BYTE;
+
  typedef uint16_t U16;
+
  typedef uint32_t U32;
+
  typedef  int32_t S32;
+
  typedef uint64_t U64;
+
#else
+
  typedef unsigned char      BYTE;
+
  typedef unsigned short     U16;
+
  typedef unsigned int       U32;
+
  typedef   signed int       S32;
+
  typedef unsigned long long U64;
+
#endif
+

+
#if defined(__GNUC__)  && !defined(XXH_USE_UNALIGNED_ACCESS)
+
#  define _PACKED __attribute__ ((packed))
+
#else
+
#  define _PACKED
+
#endif
+

+
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+
#  ifdef __IBMC__
+
#    pragma pack(1)
+
#  else
+
#    pragma pack(push, 1)
+
#  endif
+
#endif
+

+
typedef struct _U32_S { U32 v; } _PACKED U32_S;
+

+
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+
#  pragma pack(pop)
+
#endif
+

+
#define A32(x) (((U32_S *)(x))->v)
+

+

+
//***************************************
+
// Compiler-specific Functions and Macros
+
//***************************************
+
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+

+
// Note : although _rotl exists for minGW (GCC under windows), performance seems poor
+
#if defined(_MSC_VER)
+
#  define XXH_rotl32(x,r) _rotl(x,r)
+
#else
+
#  define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+
#endif
+

+
#if defined(_MSC_VER)     // Visual Studio
+
#  define XXH_swap32 _byteswap_ulong
+
#elif GCC_VERSION >= 403
+
#  define XXH_swap32 __builtin_bswap32
+
#else
+
static inline U32 XXH_swap32 (U32 x) {
+
    return  ((x << 24) & 0xff000000 ) |
+
        ((x <<  8) & 0x00ff0000 ) |
+
        ((x >>  8) & 0x0000ff00 ) |
+
        ((x >> 24) & 0x000000ff );}
+
#endif
+

+

+
//**************************************
+
// Constants
+
//**************************************
+
#define PRIME32_1   2654435761U
+
#define PRIME32_2   2246822519U
+
#define PRIME32_3   3266489917U
+
#define PRIME32_4    668265263U
+
#define PRIME32_5    374761393U
+

+

+
//**************************************
+
// Architecture Macros
+
//**************************************
+
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
#ifndef XXH_CPU_LITTLE_ENDIAN   // It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch
+
    static const int one = 1;
+
#   define XXH_CPU_LITTLE_ENDIAN   (*(char*)(&one))
+
#endif
+

+

+
//**************************************
+
// Macros
+
//**************************************
+
#define XXH_STATIC_ASSERT(c)   { enum { XXH_static_assert = 1/(!!(c)) }; }    // use only *after* variable declarations
+

+

+
//****************************
+
// Memory reads
+
//****************************
+
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+

+
forceinline U32 XXH_readLE32_align(const U32* ptr, XXH_endianess endian, XXH_alignment align)
+
{ 
+
    if (align==XXH_unaligned)
+
        return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr)); 
+
    else
+
        return endian==XXH_littleEndian ? *ptr : XXH_swap32(*ptr); 
+
}
+

+
forceinline U32 XXH_readLE32(const U32* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); }
+

+

+
//****************************
+
// Simple Hash Functions
+
//****************************
+
forceinline U32 XXH32_endian_align(const void* input, int len, U32 seed, XXH_endianess endian, XXH_alignment align)
+
{
+
    const BYTE* p = (const BYTE*)input;
+
    const BYTE* const bEnd = p + len;
+
    U32 h32;
+

+
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+
    if (p==NULL) { len=0; p=(const BYTE*)(size_t)16; }
+
#endif
+

+
    if (len>=16)
+
    {
+
        const BYTE* const limit = bEnd - 16;
+
        U32 v1 = seed + PRIME32_1 + PRIME32_2;
+
        U32 v2 = seed + PRIME32_2;
+
        U32 v3 = seed + 0;
+
        U32 v4 = seed - PRIME32_1;
+

+
        do
+
        {
+
            v1 += XXH_readLE32_align((const U32*)p, endian, align) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;
+
            v2 += XXH_readLE32_align((const U32*)p, endian, align) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;
+
            v3 += XXH_readLE32_align((const U32*)p, endian, align) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;
+
            v4 += XXH_readLE32_align((const U32*)p, endian, align) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;
+
        } while (p<=limit);
+

+
        h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+
    }
+
    else
+
    {
+
        h32  = seed + PRIME32_5;
+
    }
+

+
    h32 += (U32) len;
+

+
    while (p<=bEnd-4)
+
    {
+
        h32 += XXH_readLE32_align((const U32*)p, endian, align) * PRIME32_3;
+
        h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;
+
        p+=4;
+
    }
+

+
    while (p<bEnd)
+
    {
+
        h32 += (*p) * PRIME32_5;
+
        h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+
        p++;
+
    }
+

+
    h32 ^= h32 >> 15;
+
    h32 *= PRIME32_2;
+
    h32 ^= h32 >> 13;
+
    h32 *= PRIME32_3;
+
    h32 ^= h32 >> 16;
+

+
    return h32;
+
}
+

+

+
U32 XXH32(const void* input, int len, U32 seed)
+
{
+
#if 0
+
    // Simple version, good for code maintenance, but unfortunately slow for small inputs
+
    void* state = XXH32_init(seed);
+
    XXH32_update(state, input, len);
+
    return XXH32_digest(state);
+
#else
+
    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+

+
#  if !defined(XXH_USE_UNALIGNED_ACCESS)
+
    if ((((size_t)input) & 3))   // Input is aligned, let's leverage the speed advantage
+
    {
+
        if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+
            return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+
        else
+
            return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+
    }
+
#  endif
+

+
    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+
        return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+
    else
+
        return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+
#endif
+
}
+

+

+
//****************************
+
// Advanced Hash Functions
+
//****************************
+

+
struct XXH_state32_t
+
{
+
    U64 total_len;
+
    U32 seed;
+
    U32 v1;
+
    U32 v2;
+
    U32 v3;
+
    U32 v4;
+
    int memsize;
+
    char memory[16];
+
};
+

+

+
int XXH32_sizeofState() 
+
{
+
    XXH_STATIC_ASSERT(XXH32_SIZEOFSTATE >= sizeof(struct XXH_state32_t));   // A compilation error here means XXH32_SIZEOFSTATE is not large enough
+
    return sizeof(struct XXH_state32_t); 
+
}
+

+

+
XXH_errorcode XXH32_resetState(void* state_in, U32 seed)
+
{ 
+
    struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+
    state->seed = seed;
+
    state->v1 = seed + PRIME32_1 + PRIME32_2;
+
    state->v2 = seed + PRIME32_2;
+
    state->v3 = seed + 0;
+
    state->v4 = seed - PRIME32_1;
+
    state->total_len = 0;
+
    state->memsize = 0;
+
    return XXH_OK;
+
}
+

+

+
void* XXH32_init (U32 seed)
+
{
+
    void* state = XXH_malloc (sizeof(struct XXH_state32_t));
+
    XXH32_resetState(state, seed);
+
    return state;
+
}
+

+

+
forceinline XXH_errorcode XXH32_update_endian (void* state_in, const void* input, int len, XXH_endianess endian)
+
{
+
    struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+
    const BYTE* p = (const BYTE*)input;
+
    const BYTE* const bEnd = p + len;
+

+
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+
    if (input==NULL) return XXH_ERROR;
+
#endif
+

+
    state->total_len += len;
+

+
    if (state->memsize + len < 16)   // fill in tmp buffer
+
    {
+
        XXH_memcpy(state->memory + state->memsize, input, len);
+
        state->memsize +=  len;
+
        return XXH_OK;
+
    }
+

+
    if (state->memsize)   // some data left from previous update
+
    {
+
        XXH_memcpy(state->memory + state->memsize, input, 16-state->memsize);
+
        {
+
            const U32* p32 = (const U32*)state->memory;
+
            state->v1 += XXH_readLE32(p32, endian) * PRIME32_2; state->v1 = XXH_rotl32(state->v1, 13); state->v1 *= PRIME32_1; p32++;
+
            state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; state->v2 = XXH_rotl32(state->v2, 13); state->v2 *= PRIME32_1; p32++; 
+
            state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; state->v3 = XXH_rotl32(state->v3, 13); state->v3 *= PRIME32_1; p32++;
+
            state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; state->v4 = XXH_rotl32(state->v4, 13); state->v4 *= PRIME32_1; p32++;
+
        }
+
        p += 16-state->memsize;
+
        state->memsize = 0;
+
    }
+

+
    if (p <= bEnd-16)
+
    {
+
        const BYTE* const limit = bEnd - 16;
+
        U32 v1 = state->v1;
+
        U32 v2 = state->v2;
+
        U32 v3 = state->v3;
+
        U32 v4 = state->v4;
+

+
        do
+
        {
+
            v1 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;
+
            v2 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;
+
            v3 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;
+
            v4 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;
+
        } while (p<=limit);
+

+
        state->v1 = v1;
+
        state->v2 = v2;
+
        state->v3 = v3;
+
        state->v4 = v4;
+
    }
+

+
    if (p < bEnd)
+
    {
+
        XXH_memcpy(state->memory, p, bEnd-p);
+
        state->memsize = (int)(bEnd-p);
+
    }
+

+
    return XXH_OK;
+
}
+

+
XXH_errorcode XXH32_update (void* state_in, const void* input, int len)
+
{
+
    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
    
+
    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+
        return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+
    else
+
        return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+
}
+

+

+

+
forceinline U32 XXH32_intermediateDigest_endian (void* state_in, XXH_endianess endian)
+
{
+
    struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+
    const BYTE * p = (const BYTE*)state->memory;
+
    BYTE* bEnd = (BYTE*)state->memory + state->memsize;
+
    U32 h32;
+

+
    if (state->total_len >= 16)
+
    {
+
        h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+
    }
+
    else
+
    {
+
        h32  = state->seed + PRIME32_5;
+
    }
+

+
    h32 += (U32) state->total_len;
+

+
    while (p<=bEnd-4)
+
    {
+
        h32 += XXH_readLE32((const U32*)p, endian) * PRIME32_3;
+
        h32  = XXH_rotl32(h32, 17) * PRIME32_4;
+
        p+=4;
+
    }
+

+
    while (p<bEnd)
+
    {
+
        h32 += (*p) * PRIME32_5;
+
        h32 = XXH_rotl32(h32, 11) * PRIME32_1;
+
        p++;
+
    }
+

+
    h32 ^= h32 >> 15;
+
    h32 *= PRIME32_2;
+
    h32 ^= h32 >> 13;
+
    h32 *= PRIME32_3;
+
    h32 ^= h32 >> 16;
+

+
    return h32;
+
}
+

+

+
U32 XXH32_intermediateDigest (void* state_in)
+
{
+
    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
    
+
    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+
        return XXH32_intermediateDigest_endian(state_in, XXH_littleEndian);
+
    else
+
        return XXH32_intermediateDigest_endian(state_in, XXH_bigEndian);
+
}
+

+

+
U32 XXH32_digest (void* state_in)
+
{
+
    U32 h32 = XXH32_intermediateDigest(state_in);
+

+
    XXH_free(state_in);
+

+
    return h32;
+
}
added external/libucl/src/xxhash.h
@@ -0,0 +1,164 @@
+
/*
+
   xxHash - Fast Hash algorithm
+
   Header File
+
   Copyright (C) 2012-2013, Yann Collet.
+
   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+

+
   Redistribution and use in source and binary forms, with or without
+
   modification, are permitted provided that the following conditions are
+
   met:
+
  
+
       * Redistributions of source code must retain the above copyright
+
   notice, this list of conditions and the following disclaimer.
+
       * Redistributions in binary form must reproduce the above
+
   copyright notice, this list of conditions and the following disclaimer
+
   in the documentation and/or other materials provided with the
+
   distribution.
+
  
+
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

+
   You can contact the author at :
+
   - xxHash source repository : http://code.google.com/p/xxhash/
+
*/
+

+
/* Notice extracted from xxHash homepage :
+

+
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
+
It also successfully passes all tests from the SMHasher suite.
+

+
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+

+
Name            Speed       Q.Score   Author
+
xxHash          5.4 GB/s     10
+
CrapWow         3.2 GB/s      2       Andrew
+
MumurHash 3a    2.7 GB/s     10       Austin Appleby
+
SpookyHash      2.0 GB/s     10       Bob Jenkins
+
SBox            1.4 GB/s      9       Bret Mulvey
+
Lookup3         1.2 GB/s      9       Bob Jenkins
+
SuperFastHash   1.2 GB/s      1       Paul Hsieh
+
CityHash64      1.05 GB/s    10       Pike & Alakuijala
+
FNV             0.55 GB/s     5       Fowler, Noll, Vo
+
CRC32           0.43 GB/s     9
+
MD5-32          0.33 GB/s    10       Ronald L. Rivest
+
SHA1-32         0.28 GB/s    10
+

+
Q.Score is a measure of quality of the hash function. 
+
It depends on successfully passing SMHasher test set. 
+
10 is a perfect score.
+
*/
+

+
#pragma once
+

+
#if defined (__cplusplus)
+
extern "C" {
+
#endif
+

+

+
//****************************
+
// Type
+
//****************************
+
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+

+

+

+
//****************************
+
// Simple Hash Functions
+
//****************************
+

+
unsigned int XXH32 (const void* input, int len, unsigned int seed);
+

+
/*
+
XXH32() :
+
    Calculate the 32-bits hash of sequence of length "len" stored at memory address "input".
+
    The memory between input & input+len must be valid (allocated and read-accessible).
+
    "seed" can be used to alter the result predictably.
+
    This function successfully passes all SMHasher tests.
+
    Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
+
    Note that "len" is type "int", which means it is limited to 2^31-1.
+
    If your data is larger, use the advanced functions below.
+
*/
+

+

+

+
//****************************
+
// Advanced Hash Functions
+
//****************************
+

+
void*         XXH32_init   (unsigned int seed);
+
XXH_errorcode XXH32_update (void* state, const void* input, int len);
+
unsigned int  XXH32_digest (void* state);
+

+
/*
+
These functions calculate the xxhash of an input provided in several small packets,
+
as opposed to an input provided as a single block.
+

+
It must be started with :
+
void* XXH32_init()
+
The function returns a pointer which holds the state of calculation.
+

+
This pointer must be provided as "void* state" parameter for XXH32_update().
+
XXH32_update() can be called as many times as necessary.
+
The user must provide a valid (allocated) input.
+
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
+
Note that "len" is type "int", which means it is limited to 2^31-1. 
+
If your data is larger, it is recommended to chunk your data into blocks 
+
of size for example 2^30 (1GB) to avoid any "int" overflow issue.
+

+
Finally, you can end the calculation anytime, by using XXH32_digest().
+
This function returns the final 32-bits hash.
+
You must provide the same "void* state" parameter created by XXH32_init().
+
Memory will be freed by XXH32_digest().
+
*/
+

+

+
int           XXH32_sizeofState();
+
XXH_errorcode XXH32_resetState(void* state, unsigned int seed);
+

+
#define       XXH32_SIZEOFSTATE 48
+
typedef struct { long long ll[(XXH32_SIZEOFSTATE+(sizeof(long long)-1))/sizeof(long long)]; } XXH32_stateSpace_t;
+
/*
+
These functions allow user application to make its own allocation for state.
+

+
XXH32_sizeofState() is used to know how much space must be allocated for the xxHash 32-bits state.
+
Note that the state must be aligned to access 'long long' fields. Memory must be allocated and referenced by a pointer.
+
This pointer must then be provided as 'state' into XXH32_resetState(), which initializes the state.
+

+
For static allocation purposes (such as allocation on stack, or freestanding systems without malloc()),
+
use the structure XXH32_stateSpace_t, which will ensure that memory space is large enough and correctly aligned to access 'long long' fields.
+
*/
+

+

+
unsigned int XXH32_intermediateDigest (void* state);
+
/*
+
This function does the same as XXH32_digest(), generating a 32-bit hash,
+
but preserve memory context.
+
This way, it becomes possible to generate intermediate hashes, and then continue feeding data with XXH32_update().
+
To free memory context, use XXH32_digest(), or free().
+
*/
+

+

+

+
//****************************
+
// Deprecated function names
+
//****************************
+
// The following translations are provided to ease code transition
+
// You are encouraged to no longer this function names
+
#define XXH32_feed   XXH32_update
+
#define XXH32_result XXH32_digest
+
#define XXH32_getIntermediateResult XXH32_intermediateDigest
+

+

+

+
#if defined (__cplusplus)
+
}
+
#endif
added external/libucl/uthash/uthash.h
@@ -0,0 +1,720 @@
+
/*
+
Copyright (c) 2003-2013, Troy D. Hanson     http://troydhanson.github.com/uthash/
+
All rights reserved.
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are met:
+

+
    * Redistributions of source code must retain the above copyright
+
      notice, this list of conditions and the following disclaimer.
+

+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
*/
+

+
#ifndef UTHASH_H
+
#define UTHASH_H 
+

+
#include <string.h>   /* memcmp,strlen */
+
#include <stddef.h>   /* ptrdiff_t */
+
#include <stdlib.h>   /* exit() */
+
#include "xxhash.h"
+

+
/* These macros use decltype or the earlier __typeof GNU extension.
+
   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+
   when compiling c++ source) this code uses whatever method is needed
+
   or, for VS2008 where neither is available, uses casting workarounds. */
+
#ifdef _MSC_VER         /* MS compiler */
+
#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+
#define DECLTYPE(x) (decltype(x))
+
#else                   /* VS2008 or older (or VS2010 in C mode) */
+
#define NO_DECLTYPE
+
#define DECLTYPE(x)
+
#endif
+
#else                   /* GNU, Sun and other compilers */
+
#define DECLTYPE(x) (__typeof(x))
+
#endif
+

+
#ifdef NO_DECLTYPE
+
#define DECLTYPE_ASSIGN(dst,src)                                                 \
+
do {                                                                             \
+
  char **_da_dst = (char**)(&(dst));                                             \
+
  *_da_dst = (char*)(src);                                                       \
+
} while(0)
+
#else 
+
#define DECLTYPE_ASSIGN(dst,src)                                                 \
+
do {                                                                             \
+
  (dst) = DECLTYPE(dst)(src);                                                    \
+
} while(0)
+
#endif
+

+
/* a number of the hash function use uint32_t which isn't defined on win32 */
+
#ifdef _MSC_VER
+
typedef unsigned int uint32_t;
+
typedef unsigned char uint8_t;
+
#else
+
#include <inttypes.h>   /* uint32_t */
+
#endif
+

+
#define UTHASH_VERSION 1.9.8
+

+
#ifndef uthash_fatal
+
#define uthash_fatal(msg) exit(-1)        /* fatal error (out of memory,etc) */
+
#endif
+
#ifndef uthash_malloc
+
#define uthash_malloc(sz) malloc(sz)      /* malloc fcn                      */
+
#endif
+
#ifndef uthash_free
+
#define uthash_free(ptr,sz) free(ptr)     /* free fcn                        */
+
#endif
+

+
#ifndef uthash_noexpand_fyi
+
#define uthash_noexpand_fyi(tbl)          /* can be defined to log noexpand  */
+
#endif
+
#ifndef uthash_expand_fyi
+
#define uthash_expand_fyi(tbl)            /* can be defined to log expands   */
+
#endif
+

+
/* initial number of buckets */
+
#define HASH_INITIAL_NUM_BUCKETS 32      /* initial number of buckets        */
+
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5  /* lg2 of initial number of buckets */
+
#define HASH_BKT_CAPACITY_THRESH 10      /* expand when bucket count reaches */
+

+
/* calculate the element whose hash handle address is hhe */
+
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+

+
#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+
do {                                                                             \
+
  unsigned _hf_bkt,_hf_hashv;                                                    \
+
  out=NULL;                                                                      \
+
  if (head) {                                                                    \
+
     HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt);   \
+
     if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) {                           \
+
       HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
+
                        keyptr,keylen,out);                                      \
+
     }                                                                           \
+
  }                                                                              \
+
} while (0)
+

+
#ifdef HASH_BLOOM
+
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+
#define HASH_BLOOM_MAKE(tbl)                                                     \
+
do {                                                                             \
+
  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+
  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+
  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+
  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+
  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+
} while (0) 
+

+
#define HASH_BLOOM_FREE(tbl)                                                     \
+
do {                                                                             \
+
  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+
} while (0) 
+

+
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+

+
#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+
  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+

+
#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+
  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+

+
#else
+
#define HASH_BLOOM_MAKE(tbl) 
+
#define HASH_BLOOM_FREE(tbl) 
+
#define HASH_BLOOM_ADD(tbl,hashv) 
+
#define HASH_BLOOM_TEST(tbl,hashv) (1)
+
#define HASH_BLOOM_BYTELEN 0
+
#endif
+

+
#define HASH_MAKE_TABLE(hh,head)                                                 \
+
do {                                                                             \
+
  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+
                  sizeof(UT_hash_table));                                        \
+
  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+
  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+
  (head)->hh.tbl->tail = &((head)->hh);                                          \
+
  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+
  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+
  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+
  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+
          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+
  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+
  memset((head)->hh.tbl->buckets, 0,                                             \
+
          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+
  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+
  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+
} while(0)
+

+
#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+
        HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+

+
#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+
do {                                                                             \
+
  replaced=NULL;                                                                 \
+
  HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced);                     \
+
  if (replaced!=NULL) {                                                          \
+
     HASH_DELETE(hh,head,replaced);                                              \
+
  };                                                                             \
+
  HASH_ADD(hh,head,fieldname,keylen_in,add);                                     \
+
} while(0)
+
 
+
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+
do {                                                                             \
+
 unsigned _ha_bkt;                                                               \
+
 (add)->hh.next = NULL;                                                          \
+
 (add)->hh.key = (const char*)keyptr;                                                  \
+
 (add)->hh.keylen = (unsigned)keylen_in;                                                   \
+
 if (!(head)) {                                                                  \
+
    head = (add);                                                                \
+
    (head)->hh.prev = NULL;                                                      \
+
    HASH_MAKE_TABLE(hh,head);                                                    \
+
 } else {                                                                        \
+
    (head)->hh.tbl->tail->next = (add);                                          \
+
    (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);         \
+
    (head)->hh.tbl->tail = &((add)->hh);                                         \
+
 }                                                                               \
+
 (head)->hh.tbl->num_items++;                                                    \
+
 (add)->hh.tbl = (head)->hh.tbl;                                                 \
+
 HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets,                         \
+
         (add)->hh.hashv, _ha_bkt);                                              \
+
 HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
+
 HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
+
 HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
+
 HASH_FSCK(hh,head);                                                             \
+
} while(0)
+

+
#define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
+
do {                                                                             \
+
  bkt = ((hashv) & ((num_bkts) - 1));                                            \
+
} while(0)
+

+
/* delete "delptr" from the hash table.
+
 * "the usual" patch-up process for the app-order doubly-linked-list.
+
 * The use of _hd_hh_del below deserves special explanation.
+
 * These used to be expressed using (delptr) but that led to a bug
+
 * if someone used the same symbol for the head and deletee, like
+
 *  HASH_DELETE(hh,users,users);
+
 * We want that to work, but by changing the head (users) below
+
 * we were forfeiting our ability to further refer to the deletee (users)
+
 * in the patch-up process. Solution: use scratch space to
+
 * copy the deletee pointer, then the latter references are via that
+
 * scratch pointer rather than through the repointed (users) symbol.
+
 */
+
#define HASH_DELETE(hh,head,delptr)                                              \
+
do {                                                                             \
+
    unsigned _hd_bkt;                                                            \
+
    struct UT_hash_handle *_hd_hh_del;                                           \
+
    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+
        uthash_free((head)->hh.tbl->buckets,                                     \
+
                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+
        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+
        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+
        head = NULL;                                                             \
+
    } else {                                                                     \
+
        _hd_hh_del = &((delptr)->hh);                                            \
+
        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+
            (head)->hh.tbl->tail =                                               \
+
                (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +               \
+
                (head)->hh.tbl->hho);                                            \
+
        }                                                                        \
+
        if ((delptr)->hh.prev) {                                                 \
+
            ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +                  \
+
                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+
        } else {                                                                 \
+
            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+
        }                                                                        \
+
        if (_hd_hh_del->next) {                                                  \
+
            ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next +                     \
+
                    (head)->hh.tbl->hho))->prev =                                \
+
                    _hd_hh_del->prev;                                            \
+
        }                                                                        \
+
        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+
        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+
        (head)->hh.tbl->num_items--;                                             \
+
    }                                                                            \
+
    HASH_FSCK(hh,head);                                                          \
+
} while (0)
+

+

+
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+
#define HASH_FIND_STR(head,findstr,out)                                          \
+
    HASH_FIND(hh,head,findstr,strlen(findstr),out)
+
#define HASH_ADD_STR(head,strfield,add)                                          \
+
    HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+
#define HASH_REPLACE_STR(head,strfield,add,replaced)                             \
+
  HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced)
+
#define HASH_FIND_INT(head,findint,out)                                          \
+
    HASH_FIND(hh,head,findint,sizeof(int),out)
+
#define HASH_ADD_INT(head,intfield,add)                                          \
+
    HASH_ADD(hh,head,intfield,sizeof(int),add)
+
#define HASH_REPLACE_INT(head,intfield,add,replaced)                             \
+
    HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+
#define HASH_FIND_PTR(head,findptr,out)                                          \
+
    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+
#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+
    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+
#define HASH_REPLACE_PTR(head,ptrfield,add)                                      \
+
    HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+
#define HASH_DEL(head,delptr)                                                    \
+
    HASH_DELETE(hh,head,delptr)
+

+
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+
 * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+
 */
+
#ifdef HASH_DEBUG
+
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+
#define HASH_FSCK(hh,head)                                                       \
+
do {                                                                             \
+
    unsigned _bkt_i;                                                             \
+
    unsigned _count, _bkt_count;                                                 \
+
    char *_prev;                                                                 \
+
    struct UT_hash_handle *_thh;                                                 \
+
    if (head) {                                                                  \
+
        _count = 0;                                                              \
+
        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+
            _bkt_count = 0;                                                      \
+
            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+
            _prev = NULL;                                                        \
+
            while (_thh) {                                                       \
+
               if (_prev != (char*)(_thh->hh_prev)) {                            \
+
                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+
                    _thh->hh_prev, _prev );                                      \
+
               }                                                                 \
+
               _bkt_count++;                                                     \
+
               _prev = (char*)(_thh);                                            \
+
               _thh = _thh->hh_next;                                             \
+
            }                                                                    \
+
            _count += _bkt_count;                                                \
+
            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+
               HASH_OOPS("invalid bucket count %d, actual %d\n",                 \
+
                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+
            }                                                                    \
+
        }                                                                        \
+
        if (_count != (head)->hh.tbl->num_items) {                               \
+
            HASH_OOPS("invalid hh item count %d, actual %d\n",                   \
+
                (head)->hh.tbl->num_items, _count );                             \
+
        }                                                                        \
+
        /* traverse hh in app order; check next/prev integrity, count */         \
+
        _count = 0;                                                              \
+
        _prev = NULL;                                                            \
+
        _thh =  &(head)->hh;                                                     \
+
        while (_thh) {                                                           \
+
           _count++;                                                             \
+
           if (_prev !=(char*)(_thh->prev)) {                                    \
+
              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+
                    _thh->prev, _prev );                                         \
+
           }                                                                     \
+
           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+
           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+
                                  (head)->hh.tbl->hho) : NULL );                 \
+
        }                                                                        \
+
        if (_count != (head)->hh.tbl->num_items) {                               \
+
            HASH_OOPS("invalid app item count %d, actual %d\n",                  \
+
                (head)->hh.tbl->num_items, _count );                             \
+
        }                                                                        \
+
    }                                                                            \
+
} while (0)
+
#else
+
#define HASH_FSCK(hh,head) 
+
#endif
+

+
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to 
+
 * the descriptor to which this macro is defined for tuning the hash function.
+
 * The app can #include <unistd.h> to get the prototype for write(2). */
+
#ifdef HASH_EMIT_KEYS
+
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+
do {                                                                             \
+
    unsigned _klen = fieldlen;                                                   \
+
    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+
    write(HASH_EMIT_KEYS, keyptr, fieldlen);                                     \
+
} while (0)
+
#else 
+
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                    
+
#endif
+

+
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+
#ifdef HASH_FUNCTION 
+
#define HASH_FCN HASH_FUNCTION
+
#else
+
#define HASH_FCN HASH_XX
+
#endif
+

+
#define XX_HASH_PRIME 2654435761U
+

+
#define HASH_XX(key,keylen,num_bkts,hashv,bkt)                                  \
+
do {                                                                             \
+
  hashv = XXH32 (key, keylen, XX_HASH_PRIME);                                    \
+
  bkt = (hashv) & (num_bkts-1);                                                  \
+
} while (0)
+

+

+

+
/* key comparison function; return 0 if keys equal */
+
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) 
+

+
/* iterate over items in a known bucket to find desired item */
+
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out)                       \
+
do {                                                                             \
+
 if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head));          \
+
 else out=NULL;                                                                  \
+
 while (out) {                                                                   \
+
    if ((out)->hh.keylen == keylen_in) {                                           \
+
        if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break;             \
+
    }                                                                            \
+
    if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
+
    else out = NULL;                                                             \
+
 }                                                                               \
+
} while(0)
+

+
/* add an item to a bucket  */
+
#define HASH_ADD_TO_BKT(head,addhh)                                              \
+
do {                                                                             \
+
 head.count++;                                                                   \
+
 (addhh)->hh_next = head.hh_head;                                                \
+
 (addhh)->hh_prev = NULL;                                                        \
+
 if (head.hh_head) { (head).hh_head->hh_prev = (addhh); }                        \
+
 (head).hh_head=addhh;                                                           \
+
 if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH)             \
+
     && (addhh)->tbl->noexpand != 1) {                                           \
+
       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+
 }                                                                               \
+
} while(0)
+

+
/* remove an item from a given bucket */
+
#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+
    (head).count--;                                                              \
+
    if ((head).hh_head == hh_del) {                                              \
+
      (head).hh_head = hh_del->hh_next;                                          \
+
    }                                                                            \
+
    if (hh_del->hh_prev) {                                                       \
+
        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+
    }                                                                            \
+
    if (hh_del->hh_next) {                                                       \
+
        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+
    }                                                                
+

+
/* Bucket expansion has the effect of doubling the number of buckets
+
 * and redistributing the items into the new buckets. Ideally the
+
 * items will distribute more or less evenly into the new buckets
+
 * (the extent to which this is true is a measure of the quality of
+
 * the hash function as it applies to the key domain). 
+
 * 
+
 * With the items distributed into more buckets, the chain length
+
 * (item count) in each bucket is reduced. Thus by expanding buckets
+
 * the hash keeps a bound on the chain length. This bounded chain 
+
 * length is the essence of how a hash provides constant time lookup.
+
 * 
+
 * The calculation of tbl->ideal_chain_maxlen below deserves some
+
 * explanation. First, keep in mind that we're calculating the ideal
+
 * maximum chain length based on the *new* (doubled) bucket count.
+
 * In fractions this is just n/b (n=number of items,b=new num buckets).
+
 * Since the ideal chain length is an integer, we want to calculate 
+
 * ceil(n/b). We don't depend on floating point arithmetic in this
+
 * hash, so to calculate ceil(n/b) with integers we could write
+
 * 
+
 *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+
 * 
+
 * and in fact a previous version of this hash did just that.
+
 * But now we have improved things a bit by recognizing that b is
+
 * always a power of two. We keep its base 2 log handy (call it lb),
+
 * so now we can write this with a bit shift and logical AND:
+
 * 
+
 *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+
 * 
+
 */
+
#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+
do {                                                                             \
+
    unsigned _he_bkt;                                                            \
+
    unsigned _he_bkt_i;                                                          \
+
    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+
    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+
    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+
             2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));              \
+
    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+
    memset(_he_new_buckets, 0,                                                   \
+
            2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));               \
+
    tbl->ideal_chain_maxlen =                                                    \
+
       (tbl->num_items >> (tbl->log2_num_buckets+1)) +                           \
+
       ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0);                    \
+
    tbl->nonideal_items = 0;                                                     \
+
    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+
    {                                                                            \
+
        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+
        while (_he_thh) {                                                        \
+
           _he_hh_nxt = _he_thh->hh_next;                                        \
+
           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt);            \
+
           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+
           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+
             tbl->nonideal_items++;                                              \
+
             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+
                                        tbl->ideal_chain_maxlen;                 \
+
           }                                                                     \
+
           _he_thh->hh_prev = NULL;                                              \
+
           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+
           if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev =               \
+
                _he_thh;                                                         \
+
           _he_newbkt->hh_head = _he_thh;                                        \
+
           _he_thh = _he_hh_nxt;                                                 \
+
        }                                                                        \
+
    }                                                                            \
+
    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+
    tbl->num_buckets *= 2;                                                       \
+
    tbl->log2_num_buckets++;                                                     \
+
    tbl->buckets = _he_new_buckets;                                              \
+
    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+
        (tbl->ineff_expands+1) : 0;                                              \
+
    if (tbl->ineff_expands > 1) {                                                \
+
        tbl->noexpand=1;                                                         \
+
        uthash_noexpand_fyi(tbl);                                                \
+
    }                                                                            \
+
    uthash_expand_fyi(tbl);                                                      \
+
} while(0)
+

+

+
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+
/* Note that HASH_SORT assumes the hash handle name to be hh. 
+
 * HASH_SRT was added to allow the hash handle name to be passed in. */
+
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+
#define HASH_SRT(hh,head,cmpfcn)                                                 \
+
do {                                                                             \
+
  unsigned _hs_i;                                                                \
+
  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+
  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+
  if (head) {                                                                    \
+
      _hs_insize = 1;                                                            \
+
      _hs_looping = 1;                                                           \
+
      _hs_list = &((head)->hh);                                                  \
+
      while (_hs_looping) {                                                      \
+
          _hs_p = _hs_list;                                                      \
+
          _hs_list = NULL;                                                       \
+
          _hs_tail = NULL;                                                       \
+
          _hs_nmerges = 0;                                                       \
+
          while (_hs_p) {                                                        \
+
              _hs_nmerges++;                                                     \
+
              _hs_q = _hs_p;                                                     \
+
              _hs_psize = 0;                                                     \
+
              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+
                  _hs_psize++;                                                   \
+
                  _hs_q = (UT_hash_handle*)((_hs_q->next) ?                      \
+
                          ((void*)((char*)(_hs_q->next) +                        \
+
                          (head)->hh.tbl->hho)) : NULL);                         \
+
                  if (! (_hs_q) ) break;                                         \
+
              }                                                                  \
+
              _hs_qsize = _hs_insize;                                            \
+
              while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) {           \
+
                  if (_hs_psize == 0) {                                          \
+
                      _hs_e = _hs_q;                                             \
+
                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+
                              ((void*)((char*)(_hs_q->next) +                    \
+
                              (head)->hh.tbl->hho)) : NULL);                     \
+
                      _hs_qsize--;                                               \
+
                  } else if ( (_hs_qsize == 0) || !(_hs_q) ) {                   \
+
                      _hs_e = _hs_p;                                             \
+
                      if (_hs_p){                                                \
+
                        _hs_p = (UT_hash_handle*)((_hs_p->next) ?                \
+
                                ((void*)((char*)(_hs_p->next) +                  \
+
                                (head)->hh.tbl->hho)) : NULL);                   \
+
                       }                                                         \
+
                      _hs_psize--;                                               \
+
                  } else if ((                                                   \
+
                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+
                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+
                             ) <= 0) {                                           \
+
                      _hs_e = _hs_p;                                             \
+
                      if (_hs_p){                                                \
+
                        _hs_p = (UT_hash_handle*)((_hs_p->next) ?                \
+
                               ((void*)((char*)(_hs_p->next) +                   \
+
                               (head)->hh.tbl->hho)) : NULL);                    \
+
                       }                                                         \
+
                      _hs_psize--;                                               \
+
                  } else {                                                       \
+
                      _hs_e = _hs_q;                                             \
+
                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+
                              ((void*)((char*)(_hs_q->next) +                    \
+
                              (head)->hh.tbl->hho)) : NULL);                     \
+
                      _hs_qsize--;                                               \
+
                  }                                                              \
+
                  if ( _hs_tail ) {                                              \
+
                      _hs_tail->next = ((_hs_e) ?                                \
+
                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+
                  } else {                                                       \
+
                      _hs_list = _hs_e;                                          \
+
                  }                                                              \
+
                  if (_hs_e) {                                                   \
+
                  _hs_e->prev = ((_hs_tail) ?                                    \
+
                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+
                  }                                                              \
+
                  _hs_tail = _hs_e;                                              \
+
              }                                                                  \
+
              _hs_p = _hs_q;                                                     \
+
          }                                                                      \
+
          if (_hs_tail){                                                         \
+
            _hs_tail->next = NULL;                                               \
+
          }                                                                      \
+
          if ( _hs_nmerges <= 1 ) {                                              \
+
              _hs_looping=0;                                                     \
+
              (head)->hh.tbl->tail = _hs_tail;                                   \
+
              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+
          }                                                                      \
+
          _hs_insize *= 2;                                                       \
+
      }                                                                          \
+
      HASH_FSCK(hh,head);                                                        \
+
 }                                                                               \
+
} while (0)
+

+
/* This function selects items from one hash into another hash. 
+
 * The end result is that the selected items have dual presence 
+
 * in both hashes. There is no copy of the items made; rather 
+
 * they are added into the new hash through a secondary hash 
+
 * hash handle that must be present in the structure. */
+
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+
do {                                                                             \
+
  unsigned _src_bkt, _dst_bkt;                                                   \
+
  void *_last_elt=NULL, *_elt;                                                   \
+
  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+
  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+
  if (src) {                                                                     \
+
    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+
      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+
          _src_hh;                                                               \
+
          _src_hh = _src_hh->hh_next) {                                          \
+
          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+
          if (cond(_elt)) {                                                      \
+
            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+
            _dst_hh->key = _src_hh->key;                                         \
+
            _dst_hh->keylen = _src_hh->keylen;                                   \
+
            _dst_hh->hashv = _src_hh->hashv;                                     \
+
            _dst_hh->prev = _last_elt;                                           \
+
            _dst_hh->next = NULL;                                                \
+
            if (_last_elt_hh) { _last_elt_hh->next = _elt; }                     \
+
            if (!dst) {                                                          \
+
              DECLTYPE_ASSIGN(dst,_elt);                                         \
+
              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+
            } else {                                                             \
+
              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+
            }                                                                    \
+
            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+
            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+
            (dst)->hh_dst.tbl->num_items++;                                      \
+
            _last_elt = _elt;                                                    \
+
            _last_elt_hh = _dst_hh;                                              \
+
          }                                                                      \
+
      }                                                                          \
+
    }                                                                            \
+
  }                                                                              \
+
  HASH_FSCK(hh_dst,dst);                                                         \
+
} while (0)
+

+
#define HASH_CLEAR(hh,head)                                                      \
+
do {                                                                             \
+
  if (head) {                                                                    \
+
    uthash_free((head)->hh.tbl->buckets,                                         \
+
                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+
    HASH_BLOOM_FREE((head)->hh.tbl);                                             \
+
    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+
    (head)=NULL;                                                                 \
+
  }                                                                              \
+
} while(0)
+

+
#define HASH_OVERHEAD(hh,head)                                                   \
+
 (size_t)((((head)->hh.tbl->num_items   * sizeof(UT_hash_handle))   +            \
+
           ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket))   +            \
+
            (sizeof(UT_hash_table))                                 +            \
+
            (HASH_BLOOM_BYTELEN)))
+

+
#ifdef NO_DECLTYPE
+
#define HASH_ITER(hh,head,el,tmp)                                                \
+
for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL);       \
+
  el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 
+
#else
+
#define HASH_ITER(hh,head,el,tmp)                                                \
+
for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL);                 \
+
  el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+
#endif
+

+
/* obtain a count of items in the hash */
+
#define HASH_COUNT(head) HASH_CNT(hh,head) 
+
#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+

+
typedef struct UT_hash_bucket {
+
   struct UT_hash_handle *hh_head;
+
   unsigned count;
+

+
   /* expand_mult is normally set to 0. In this situation, the max chain length
+
    * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+
    * the bucket's chain exceeds this length, bucket expansion is triggered). 
+
    * However, setting expand_mult to a non-zero value delays bucket expansion
+
    * (that would be triggered by additions to this particular bucket)
+
    * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+
    * (The multiplier is simply expand_mult+1). The whole idea of this
+
    * multiplier is to reduce bucket expansions, since they are expensive, in
+
    * situations where we know that a particular bucket tends to be overused.
+
    * It is better to let its chain length grow to a longer yet-still-bounded
+
    * value, than to do an O(n) bucket expansion too often. 
+
    */
+
   unsigned expand_mult;
+

+
} UT_hash_bucket;
+

+
/* random signature used only to find hash tables in external analysis */
+
#define HASH_SIGNATURE 0xa0111fe1
+
#define HASH_BLOOM_SIGNATURE 0xb12220f2
+

+
typedef struct UT_hash_table {
+
   UT_hash_bucket *buckets;
+
   unsigned num_buckets, log2_num_buckets;
+
   unsigned num_items;
+
   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
+
   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+

+
   /* in an ideal situation (all buckets used equally), no bucket would have
+
    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+
   unsigned ideal_chain_maxlen;
+

+
   /* nonideal_items is the number of items in the hash whose chain position
+
    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+
    * hash distribution; reaching them in a chain traversal takes >ideal steps */
+
   unsigned nonideal_items;
+

+
   /* ineffective expands occur when a bucket doubling was performed, but 
+
    * afterward, more than half the items in the hash had nonideal chain
+
    * positions. If this happens on two consecutive expansions we inhibit any
+
    * further expansion, as it's not helping; this happens when the hash
+
    * function isn't a good fit for the key domain. When expansion is inhibited
+
    * the hash will still work, albeit no longer in constant time. */
+
   unsigned ineff_expands, noexpand;
+

+
   uint32_t signature; /* used only to find hash tables in external analysis */
+
#ifdef HASH_BLOOM
+
   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+
   uint8_t *bloom_bv;
+
   char bloom_nbits;
+
#endif
+

+
} UT_hash_table;
+

+
typedef struct UT_hash_handle {
+
   struct UT_hash_table *tbl;
+
   void *prev;                       /* prev element in app order      */
+
   void *next;                       /* next element in app order      */
+
   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
+
   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
+
   const void *key;                  /* ptr to enclosing struct's key  */
+
   unsigned keylen;                  /* enclosing struct's key len     */
+
   unsigned hashv;                   /* result of hash-fcn(key)        */
+
} UT_hash_handle;
+

+
#endif /* UTHASH_H */
added external/libucl/uthash/utlist.h
@@ -0,0 +1,757 @@
+
/*
+
Copyright (c) 2007-2013, Troy D. Hanson   http://troydhanson.github.com/uthash/
+
All rights reserved.
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are met:
+

+
    * Redistributions of source code must retain the above copyright
+
      notice, this list of conditions and the following disclaimer.
+

+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
*/
+

+
#ifndef UTLIST_H
+
#define UTLIST_H
+

+
#define UTLIST_VERSION 1.9.8
+

+
#include <assert.h>
+

+
/* 
+
 * This file contains macros to manipulate singly and doubly-linked lists.
+
 *
+
 * 1. LL_ macros:  singly-linked lists.
+
 * 2. DL_ macros:  doubly-linked lists.
+
 * 3. CDL_ macros: circular doubly-linked lists.
+
 *
+
 * To use singly-linked lists, your structure must have a "next" pointer.
+
 * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+
 * Either way, the pointer to the head of the list must be initialized to NULL.
+
 * 
+
 * ----------------.EXAMPLE -------------------------
+
 * struct item {
+
 *      int id;
+
 *      struct item *prev, *next;
+
 * }
+
 *
+
 * struct item *list = NULL:
+
 *
+
 * int main() {
+
 *      struct item *item;
+
 *      ... allocate and populate item ...
+
 *      DL_APPEND(list, item);
+
 * }
+
 * --------------------------------------------------
+
 *
+
 * For doubly-linked lists, the append and delete macros are O(1)
+
 * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+
 * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+
 */
+

+
/* These macros use decltype or the earlier __typeof GNU extension.
+
   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+
   when compiling c++ code), this code uses whatever method is needed
+
   or, for VS2008 where neither is available, uses casting workarounds. */
+
#ifdef _MSC_VER            /* MS compiler */
+
#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+
#define LDECLTYPE(x) decltype(x)
+
#else                     /* VS2008 or older (or VS2010 in C mode) */
+
#define NO_DECLTYPE
+
#define LDECLTYPE(x) char*
+
#endif
+
#elif defined(__ICCARM__)
+
#define NO_DECLTYPE
+
#define LDECLTYPE(x) char*
+
#else                      /* GNU, Sun and other compilers */
+
#define LDECLTYPE(x) __typeof(x)
+
#endif
+

+
/* for VS2008 we use some workarounds to get around the lack of decltype,
+
 * namely, we always reassign our tmp variable to the list head if we need
+
 * to dereference its prev/next pointers, and save/restore the real head.*/
+
#ifdef NO_DECLTYPE
+
#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+
#define _NEXT(elt,list,next) ((char*)((list)->next))
+
#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+
/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
+
#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+
#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+
#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+
#else 
+
#define _SV(elt,list)
+
#define _NEXT(elt,list,next) ((elt)->next)
+
#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
+
/* #define _PREV(elt,list,prev) ((elt)->prev) */
+
#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
+
#define _RS(list)
+
#define _CASTASGN(a,b) (a)=(b)
+
#endif
+

+
/******************************************************************************
+
 * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    *
+
 * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
+
 *****************************************************************************/
+
#define LL_SORT(list, cmp)                                                                     \
+
    LL_SORT2(list, cmp, next)
+

+
#define LL_SORT2(list, cmp, next)                                                              \
+
do {                                                                                           \
+
  LDECLTYPE(list) _ls_p;                                                                       \
+
  LDECLTYPE(list) _ls_q;                                                                       \
+
  LDECLTYPE(list) _ls_e;                                                                       \
+
  LDECLTYPE(list) _ls_tail;                                                                    \
+
  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+
  if (list) {                                                                                  \
+
    _ls_insize = 1;                                                                            \
+
    _ls_looping = 1;                                                                           \
+
    while (_ls_looping) {                                                                      \
+
      _CASTASGN(_ls_p,list);                                                                   \
+
      list = NULL;                                                                             \
+
      _ls_tail = NULL;                                                                         \
+
      _ls_nmerges = 0;                                                                         \
+
      while (_ls_p) {                                                                          \
+
        _ls_nmerges++;                                                                         \
+
        _ls_q = _ls_p;                                                                         \
+
        _ls_psize = 0;                                                                         \
+
        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+
          _ls_psize++;                                                                         \
+
          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+
          if (!_ls_q) break;                                                                   \
+
        }                                                                                      \
+
        _ls_qsize = _ls_insize;                                                                \
+
        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+
          if (_ls_psize == 0) {                                                                \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
          } else {                                                                             \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
          }                                                                                    \
+
          if (_ls_tail) {                                                                      \
+
            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+
          } else {                                                                             \
+
            _CASTASGN(list,_ls_e);                                                             \
+
          }                                                                                    \
+
          _ls_tail = _ls_e;                                                                    \
+
        }                                                                                      \
+
        _ls_p = _ls_q;                                                                         \
+
      }                                                                                        \
+
      if (_ls_tail) {                                                                          \
+
        _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                     \
+
      }                                                                                        \
+
      if (_ls_nmerges <= 1) {                                                                  \
+
        _ls_looping=0;                                                                         \
+
      }                                                                                        \
+
      _ls_insize *= 2;                                                                         \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0)
+

+

+
#define DL_SORT(list, cmp)                                                                     \
+
    DL_SORT2(list, cmp, prev, next)
+

+
#define DL_SORT2(list, cmp, prev, next)                                                        \
+
do {                                                                                           \
+
  LDECLTYPE(list) _ls_p;                                                                       \
+
  LDECLTYPE(list) _ls_q;                                                                       \
+
  LDECLTYPE(list) _ls_e;                                                                       \
+
  LDECLTYPE(list) _ls_tail;                                                                    \
+
  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+
  if (list) {                                                                                  \
+
    _ls_insize = 1;                                                                            \
+
    _ls_looping = 1;                                                                           \
+
    while (_ls_looping) {                                                                      \
+
      _CASTASGN(_ls_p,list);                                                                   \
+
      list = NULL;                                                                             \
+
      _ls_tail = NULL;                                                                         \
+
      _ls_nmerges = 0;                                                                         \
+
      while (_ls_p) {                                                                          \
+
        _ls_nmerges++;                                                                         \
+
        _ls_q = _ls_p;                                                                         \
+
        _ls_psize = 0;                                                                         \
+
        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+
          _ls_psize++;                                                                         \
+
          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+
          if (!_ls_q) break;                                                                   \
+
        }                                                                                      \
+
        _ls_qsize = _ls_insize;                                                                \
+
        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+
          if (_ls_psize == 0) {                                                                \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
          } else {                                                                             \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
          }                                                                                    \
+
          if (_ls_tail) {                                                                      \
+
            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+
          } else {                                                                             \
+
            _CASTASGN(list,_ls_e);                                                             \
+
          }                                                                                    \
+
          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+
          _ls_tail = _ls_e;                                                                    \
+
        }                                                                                      \
+
        _ls_p = _ls_q;                                                                         \
+
      }                                                                                        \
+
      _CASTASGN(list->prev, _ls_tail);                                                         \
+
      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                       \
+
      if (_ls_nmerges <= 1) {                                                                  \
+
        _ls_looping=0;                                                                         \
+
      }                                                                                        \
+
      _ls_insize *= 2;                                                                         \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0)
+

+
#define CDL_SORT(list, cmp)                                                                    \
+
    CDL_SORT2(list, cmp, prev, next)
+

+
#define CDL_SORT2(list, cmp, prev, next)                                                       \
+
do {                                                                                           \
+
  LDECLTYPE(list) _ls_p;                                                                       \
+
  LDECLTYPE(list) _ls_q;                                                                       \
+
  LDECLTYPE(list) _ls_e;                                                                       \
+
  LDECLTYPE(list) _ls_tail;                                                                    \
+
  LDECLTYPE(list) _ls_oldhead;                                                                 \
+
  LDECLTYPE(list) _tmp;                                                                        \
+
  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+
  if (list) {                                                                                  \
+
    _ls_insize = 1;                                                                            \
+
    _ls_looping = 1;                                                                           \
+
    while (_ls_looping) {                                                                      \
+
      _CASTASGN(_ls_p,list);                                                                   \
+
      _CASTASGN(_ls_oldhead,list);                                                             \
+
      list = NULL;                                                                             \
+
      _ls_tail = NULL;                                                                         \
+
      _ls_nmerges = 0;                                                                         \
+
      while (_ls_p) {                                                                          \
+
        _ls_nmerges++;                                                                         \
+
        _ls_q = _ls_p;                                                                         \
+
        _ls_psize = 0;                                                                         \
+
        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+
          _ls_psize++;                                                                         \
+
          _SV(_ls_q,list);                                                                     \
+
          if (_NEXT(_ls_q,list,next) == _ls_oldhead) {                                         \
+
            _ls_q = NULL;                                                                      \
+
          } else {                                                                             \
+
            _ls_q = _NEXT(_ls_q,list,next);                                                    \
+
          }                                                                                    \
+
          _RS(list);                                                                           \
+
          if (!_ls_q) break;                                                                   \
+
        }                                                                                      \
+
        _ls_qsize = _ls_insize;                                                                \
+
        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+
          if (_ls_psize == 0) {                                                                \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+
          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+
          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+
            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+
              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+
            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+
          } else {                                                                             \
+
            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+
              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+
            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+
          }                                                                                    \
+
          if (_ls_tail) {                                                                      \
+
            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+
          } else {                                                                             \
+
            _CASTASGN(list,_ls_e);                                                             \
+
          }                                                                                    \
+
          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+
          _ls_tail = _ls_e;                                                                    \
+
        }                                                                                      \
+
        _ls_p = _ls_q;                                                                         \
+
      }                                                                                        \
+
      _CASTASGN(list->prev,_ls_tail);                                                          \
+
      _CASTASGN(_tmp,list);                                                                    \
+
      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list);                       \
+
      if (_ls_nmerges <= 1) {                                                                  \
+
        _ls_looping=0;                                                                         \
+
      }                                                                                        \
+
      _ls_insize *= 2;                                                                         \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0)
+

+
/******************************************************************************
+
 * singly linked list macros (non-circular)                                   *
+
 *****************************************************************************/
+
#define LL_PREPEND(head,add)                                                                   \
+
    LL_PREPEND2(head,add,next)
+

+
#define LL_PREPEND2(head,add,next)                                                             \
+
do {                                                                                           \
+
  (add)->next = head;                                                                          \
+
  head = add;                                                                                  \
+
} while (0)
+

+
#define LL_CONCAT(head1,head2)                                                                 \
+
    LL_CONCAT2(head1,head2,next)
+

+
#define LL_CONCAT2(head1,head2,next)                                                           \
+
do {                                                                                           \
+
  LDECLTYPE(head1) _tmp;                                                                       \
+
  if (head1) {                                                                                 \
+
    _tmp = head1;                                                                              \
+
    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+
    _tmp->next=(head2);                                                                        \
+
  } else {                                                                                     \
+
    (head1)=(head2);                                                                           \
+
  }                                                                                            \
+
} while (0)
+

+
#define LL_APPEND(head,add)                                                                    \
+
    LL_APPEND2(head,add,next)
+

+
#define LL_APPEND2(head,add,next)                                                              \
+
do {                                                                                           \
+
  LDECLTYPE(head) _tmp;                                                                        \
+
  (add)->next=NULL;                                                                            \
+
  if (head) {                                                                                  \
+
    _tmp = head;                                                                               \
+
    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+
    _tmp->next=(add);                                                                          \
+
  } else {                                                                                     \
+
    (head)=(add);                                                                              \
+
  }                                                                                            \
+
} while (0)
+

+
#define LL_DELETE(head,del)                                                                    \
+
    LL_DELETE2(head,del,next)
+

+
#define LL_DELETE2(head,del,next)                                                              \
+
do {                                                                                           \
+
  LDECLTYPE(head) _tmp;                                                                        \
+
  if ((head) == (del)) {                                                                       \
+
    (head)=(head)->next;                                                                       \
+
  } else {                                                                                     \
+
    _tmp = head;                                                                               \
+
    while (_tmp->next && (_tmp->next != (del))) {                                              \
+
      _tmp = _tmp->next;                                                                       \
+
    }                                                                                          \
+
    if (_tmp->next) {                                                                          \
+
      _tmp->next = ((del)->next);                                                              \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0)
+

+
/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
+
#define LL_APPEND_VS2008(head,add)                                                             \
+
    LL_APPEND2_VS2008(head,add,next)
+

+
#define LL_APPEND2_VS2008(head,add,next)                                                       \
+
do {                                                                                           \
+
  if (head) {                                                                                  \
+
    (add)->next = head;     /* use add->next as a temp variable */                             \
+
    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \
+
    (add)->next->next=(add);                                                                   \
+
  } else {                                                                                     \
+
    (head)=(add);                                                                              \
+
  }                                                                                            \
+
  (add)->next=NULL;                                                                            \
+
} while (0)
+

+
#define LL_DELETE_VS2008(head,del)                                                             \
+
    LL_DELETE2_VS2008(head,del,next)
+

+
#define LL_DELETE2_VS2008(head,del,next)                                                       \
+
do {                                                                                           \
+
  if ((head) == (del)) {                                                                       \
+
    (head)=(head)->next;                                                                       \
+
  } else {                                                                                     \
+
    char *_tmp = (char*)(head);                                                                \
+
    while ((head)->next && ((head)->next != (del))) {                                          \
+
      head = (head)->next;                                                                     \
+
    }                                                                                          \
+
    if ((head)->next) {                                                                        \
+
      (head)->next = ((del)->next);                                                            \
+
    }                                                                                          \
+
    {                                                                                          \
+
      char **_head_alias = (char**)&(head);                                                    \
+
      *_head_alias = _tmp;                                                                     \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0)
+
#ifdef NO_DECLTYPE
+
#undef LL_APPEND
+
#define LL_APPEND LL_APPEND_VS2008
+
#undef LL_DELETE
+
#define LL_DELETE LL_DELETE_VS2008
+
#undef LL_DELETE2
+
#define LL_DELETE2 LL_DELETE2_VS2008
+
#undef LL_APPEND2
+
#define LL_APPEND2 LL_APPEND2_VS2008
+
#undef LL_CONCAT /* no LL_CONCAT_VS2008 */
+
#undef DL_CONCAT /* no DL_CONCAT_VS2008 */
+
#endif
+
/* end VS2008 replacements */
+

+
#define LL_COUNT(head,el,counter)                                                              \
+
    LL_COUNT2(head,el,counter,next)                                                            \
+

+
#define LL_COUNT2(head,el,counter,next)                                                        \
+
{                                                                                              \
+
    counter = 0;                                                                               \
+
    LL_FOREACH2(head,el,next){ ++counter; }                                                    \
+
}
+

+
#define LL_FOREACH(head,el)                                                                    \
+
    LL_FOREACH2(head,el,next)
+

+
#define LL_FOREACH2(head,el,next)                                                              \
+
    for(el=head;el;el=(el)->next)
+

+
#define LL_FOREACH_SAFE(head,el,tmp)                                                           \
+
    LL_FOREACH_SAFE2(head,el,tmp,next)
+

+
#define LL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+
  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+

+
#define LL_SEARCH_SCALAR(head,out,field,val)                                                   \
+
    LL_SEARCH_SCALAR2(head,out,field,val,next)
+

+
#define LL_SEARCH_SCALAR2(head,out,field,val,next)                                             \
+
do {                                                                                           \
+
    LL_FOREACH2(head,out,next) {                                                               \
+
      if ((out)->field == (val)) break;                                                        \
+
    }                                                                                          \
+
} while(0) 
+

+
#define LL_SEARCH(head,out,elt,cmp)                                                            \
+
    LL_SEARCH2(head,out,elt,cmp,next)
+

+
#define LL_SEARCH2(head,out,elt,cmp,next)                                                      \
+
do {                                                                                           \
+
    LL_FOREACH2(head,out,next) {                                                               \
+
      if ((cmp(out,elt))==0) break;                                                            \
+
    }                                                                                          \
+
} while(0) 
+

+
#define LL_REPLACE_ELEM(head, el, add)                                                         \
+
do {                                                                                           \
+
 LDECLTYPE(head) _tmp;                                                                         \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 (add)->next = (el)->next;                                                                     \
+
 if ((head) == (el)) {                                                                         \
+
  (head) = (add);                                                                              \
+
 } else {                                                                                      \
+
  _tmp = head;                                                                                 \
+
  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+
   _tmp = _tmp->next;                                                                          \
+
  }                                                                                            \
+
  if (_tmp->next) {                                                                            \
+
    _tmp->next = (add);                                                                        \
+
  }                                                                                            \
+
 }                                                                                             \
+
} while (0)
+

+
#define LL_PREPEND_ELEM(head, el, add)                                                         \
+
do {                                                                                           \
+
 LDECLTYPE(head) _tmp;                                                                         \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 (add)->next = (el);                                                                           \
+
 if ((head) == (el)) {                                                                         \
+
  (head) = (add);                                                                              \
+
 } else {                                                                                      \
+
  _tmp = head;                                                                                 \
+
  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+
   _tmp = _tmp->next;                                                                          \
+
  }                                                                                            \
+
  if (_tmp->next) {                                                                            \
+
    _tmp->next = (add);                                                                        \
+
  }                                                                                            \
+
 }                                                                                             \
+
} while (0)                                                                                    \
+

+

+
/******************************************************************************
+
 * doubly linked list macros (non-circular)                                   *
+
 *****************************************************************************/
+
#define DL_PREPEND(head,add)                                                                   \
+
    DL_PREPEND2(head,add,prev,next)
+

+
#define DL_PREPEND2(head,add,prev,next)                                                        \
+
do {                                                                                           \
+
 (add)->next = head;                                                                           \
+
 if (head) {                                                                                   \
+
   (add)->prev = (head)->prev;                                                                 \
+
   (head)->prev = (add);                                                                       \
+
 } else {                                                                                      \
+
   (add)->prev = (add);                                                                        \
+
 }                                                                                             \
+
 (head) = (add);                                                                               \
+
} while (0)
+

+
#define DL_APPEND(head,add)                                                                    \
+
    DL_APPEND2(head,add,prev,next)
+

+
#define DL_APPEND2(head,add,prev,next)                                                         \
+
do {                                                                                           \
+
  if (head) {                                                                                  \
+
      (add)->prev = (head)->prev;                                                              \
+
      (head)->prev->next = (add);                                                              \
+
      (head)->prev = (add);                                                                    \
+
      (add)->next = NULL;                                                                      \
+
  } else {                                                                                     \
+
      (head)=(add);                                                                            \
+
      (head)->prev = (head);                                                                   \
+
      (head)->next = NULL;                                                                     \
+
  }                                                                                            \
+
} while (0) 
+

+
#define DL_CONCAT(head1,head2)                                                                 \
+
    DL_CONCAT2(head1,head2,prev,next)
+

+
#define DL_CONCAT2(head1,head2,prev,next)                                                      \
+
do {                                                                                           \
+
  LDECLTYPE(head1) _tmp;                                                                       \
+
  if (head2) {                                                                                 \
+
    if (head1) {                                                                               \
+
        _tmp = (head2)->prev;                                                                  \
+
        (head2)->prev = (head1)->prev;                                                         \
+
        (head1)->prev->next = (head2);                                                         \
+
        (head1)->prev = _tmp;                                                                  \
+
    } else {                                                                                   \
+
        (head1)=(head2);                                                                       \
+
    }                                                                                          \
+
  }                                                                                            \
+
} while (0) 
+

+
#define DL_DELETE(head,del)                                                                    \
+
    DL_DELETE2(head,del,prev,next)
+

+
#define DL_DELETE2(head,del,prev,next)                                                         \
+
do {                                                                                           \
+
  assert((del)->prev != NULL);                                                                 \
+
  if ((del)->prev == (del)) {                                                                  \
+
      (head)=NULL;                                                                             \
+
  } else if ((del)==(head)) {                                                                  \
+
      (del)->next->prev = (del)->prev;                                                         \
+
      (head) = (del)->next;                                                                    \
+
  } else {                                                                                     \
+
      (del)->prev->next = (del)->next;                                                         \
+
      if ((del)->next) {                                                                       \
+
          (del)->next->prev = (del)->prev;                                                     \
+
      } else {                                                                                 \
+
          (head)->prev = (del)->prev;                                                          \
+
      }                                                                                        \
+
  }                                                                                            \
+
} while (0) 
+

+
#define DL_COUNT(head,el,counter)                                                              \
+
    DL_COUNT2(head,el,counter,next)                                                            \
+

+
#define DL_COUNT2(head,el,counter,next)                                                        \
+
{                                                                                              \
+
    counter = 0;                                                                               \
+
    DL_FOREACH2(head,el,next){ ++counter; }                                                    \
+
}
+

+
#define DL_FOREACH(head,el)                                                                    \
+
    DL_FOREACH2(head,el,next)
+

+
#define DL_FOREACH2(head,el,next)                                                              \
+
    for(el=head;el;el=(el)->next)
+

+
/* this version is safe for deleting the elements during iteration */
+
#define DL_FOREACH_SAFE(head,el,tmp)                                                           \
+
    DL_FOREACH_SAFE2(head,el,tmp,next)
+

+
#define DL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+
  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+

+
/* these are identical to their singly-linked list counterparts */
+
#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+
#define DL_SEARCH LL_SEARCH
+
#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
+
#define DL_SEARCH2 LL_SEARCH2
+

+
#define DL_REPLACE_ELEM(head, el, add)                                                         \
+
do {                                                                                           \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 if ((head) == (el)) {                                                                         \
+
  (head) = (add);                                                                              \
+
  (add)->next = (el)->next;                                                                    \
+
  if ((el)->next == NULL) {                                                                    \
+
   (add)->prev = (add);                                                                        \
+
  } else {                                                                                     \
+
   (add)->prev = (el)->prev;                                                                   \
+
   (add)->next->prev = (add);                                                                  \
+
  }                                                                                            \
+
 } else {                                                                                      \
+
  (add)->next = (el)->next;                                                                    \
+
  (add)->prev = (el)->prev;                                                                    \
+
  (add)->prev->next = (add);                                                                   \
+
  if ((el)->next == NULL) {                                                                    \
+
   (head)->prev = (add);                                                                       \
+
  } else {                                                                                     \
+
   (add)->next->prev = (add);                                                                  \
+
  }                                                                                            \
+
 }                                                                                             \
+
} while (0)
+

+
#define DL_PREPEND_ELEM(head, el, add)                                                         \
+
do {                                                                                           \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 (add)->next = (el);                                                                           \
+
 (add)->prev = (el)->prev;                                                                     \
+
 (el)->prev = (add);                                                                           \
+
 if ((head) == (el)) {                                                                         \
+
  (head) = (add);                                                                              \
+
 } else {                                                                                      \
+
  (add)->prev->next = (add);                                                                   \
+
 }                                                                                             \
+
} while (0)                                                                                    \
+

+

+
/******************************************************************************
+
 * circular doubly linked list macros                                         *
+
 *****************************************************************************/
+
#define CDL_PREPEND(head,add)                                                                  \
+
    CDL_PREPEND2(head,add,prev,next)
+

+
#define CDL_PREPEND2(head,add,prev,next)                                                       \
+
do {                                                                                           \
+
 if (head) {                                                                                   \
+
   (add)->prev = (head)->prev;                                                                 \
+
   (add)->next = (head);                                                                       \
+
   (head)->prev = (add);                                                                       \
+
   (add)->prev->next = (add);                                                                  \
+
 } else {                                                                                      \
+
   (add)->prev = (add);                                                                        \
+
   (add)->next = (add);                                                                        \
+
 }                                                                                             \
+
(head)=(add);                                                                                  \
+
} while (0)
+

+
#define CDL_DELETE(head,del)                                                                   \
+
    CDL_DELETE2(head,del,prev,next)
+

+
#define CDL_DELETE2(head,del,prev,next)                                                        \
+
do {                                                                                           \
+
  if ( ((head)==(del)) && ((head)->next == (head))) {                                          \
+
      (head) = 0L;                                                                             \
+
  } else {                                                                                     \
+
     (del)->next->prev = (del)->prev;                                                          \
+
     (del)->prev->next = (del)->next;                                                          \
+
     if ((del) == (head)) (head)=(del)->next;                                                  \
+
  }                                                                                            \
+
} while (0) 
+

+
#define CDL_COUNT(head,el,counter)                                                             \
+
    CDL_COUNT2(head,el,counter,next)                                                           \
+

+
#define CDL_COUNT2(head, el, counter,next)                                                     \
+
{                                                                                              \
+
    counter = 0;                                                                               \
+
    CDL_FOREACH2(head,el,next){ ++counter; }                                                   \
+
}
+

+
#define CDL_FOREACH(head,el)                                                                   \
+
    CDL_FOREACH2(head,el,next)
+

+
#define CDL_FOREACH2(head,el,next)                                                             \
+
    for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) 
+

+
#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \
+
    CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
+

+
#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)                                         \
+
  for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \
+
      (el) && ((tmp2)=(el)->next, 1);                                                          \
+
      ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
+

+
#define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \
+
    CDL_SEARCH_SCALAR2(head,out,field,val,next)
+

+
#define CDL_SEARCH_SCALAR2(head,out,field,val,next)                                            \
+
do {                                                                                           \
+
    CDL_FOREACH2(head,out,next) {                                                              \
+
      if ((out)->field == (val)) break;                                                        \
+
    }                                                                                          \
+
} while(0) 
+

+
#define CDL_SEARCH(head,out,elt,cmp)                                                           \
+
    CDL_SEARCH2(head,out,elt,cmp,next)
+

+
#define CDL_SEARCH2(head,out,elt,cmp,next)                                                     \
+
do {                                                                                           \
+
    CDL_FOREACH2(head,out,next) {                                                              \
+
      if ((cmp(out,elt))==0) break;                                                            \
+
    }                                                                                          \
+
} while(0) 
+

+
#define CDL_REPLACE_ELEM(head, el, add)                                                        \
+
do {                                                                                           \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 if ((el)->next == (el)) {                                                                     \
+
  (add)->next = (add);                                                                         \
+
  (add)->prev = (add);                                                                         \
+
  (head) = (add);                                                                              \
+
 } else {                                                                                      \
+
  (add)->next = (el)->next;                                                                    \
+
  (add)->prev = (el)->prev;                                                                    \
+
  (add)->next->prev = (add);                                                                   \
+
  (add)->prev->next = (add);                                                                   \
+
  if ((head) == (el)) {                                                                        \
+
   (head) = (add);                                                                             \
+
  }                                                                                            \
+
 }                                                                                             \
+
} while (0)
+

+
#define CDL_PREPEND_ELEM(head, el, add)                                                        \
+
do {                                                                                           \
+
 assert(head != NULL);                                                                         \
+
 assert(el != NULL);                                                                           \
+
 assert(add != NULL);                                                                          \
+
 (add)->next = (el);                                                                           \
+
 (add)->prev = (el)->prev;                                                                     \
+
 (el)->prev = (add);                                                                           \
+
 (add)->prev->next = (add);                                                                    \
+
 if ((head) == (el)) {                                                                         \
+
  (head) = (add);                                                                              \
+
 }                                                                                             \
+
} while (0)                                                                                    \
+

+
#endif /* UTLIST_H */
+

added external/libucl/uthash/utstring.h
@@ -0,0 +1,410 @@
+
/*
+
Copyright (c) 2008-2013, Troy D. Hanson   http://troydhanson.github.com/uthash/
+
All rights reserved.
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are met:
+

+
    * Redistributions of source code must retain the above copyright
+
      notice, this list of conditions and the following disclaimer.
+

+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
*/
+

+
/* a dynamic string implementation using macros 
+
 */
+
#ifndef UTSTRING_H
+
#define UTSTRING_H
+

+
#define UTSTRING_VERSION 1.9.8
+

+
#ifdef __GNUC__
+
#define _UNUSED_ __attribute__ ((__unused__)) 
+
#else
+
#define _UNUSED_ 
+
#endif
+

+
#include <stdlib.h>
+
#include <string.h>
+
#include <stdarg.h>
+

+
#ifndef oom
+
#define oom() exit(-1)
+
#endif
+

+
typedef struct {
+
    char *d;
+
    size_t n; /* allocd size */
+
    size_t i; /* index of first unused byte */
+
} UT_string;
+

+
#define utstring_reserve(s,amt)                            \
+
do {                                                       \
+
  if (((s)->n - (s)->i) < (size_t)(amt)) {                 \
+
     (s)->d = (char*)realloc((s)->d, (s)->n + amt);        \
+
     if ((s)->d == NULL) oom();                            \
+
     (s)->n += amt;                                        \
+
  }                                                        \
+
} while(0)
+

+
#define utstring_init(s)                                   \
+
do {                                                       \
+
  (s)->n = 0; (s)->i = 0; (s)->d = NULL;                   \
+
  utstring_reserve(s,128);                                 \
+
  (s)->d[0] = '\0'; \
+
} while(0)
+

+
#define utstring_done(s)                                   \
+
do {                                                       \
+
  if ((s)->d != NULL) free((s)->d);                        \
+
  (s)->n = 0;                                              \
+
} while(0)
+

+
#define utstring_free(s)                                   \
+
do {                                                       \
+
  utstring_done(s);                                        \
+
  free(s);                                                 \
+
} while(0)
+

+
#define utstring_new(s)                                    \
+
do {                                                       \
+
   s = (UT_string*)calloc(sizeof(UT_string),1);            \
+
   if (!s) oom();                                          \
+
   utstring_init(s);                                       \
+
} while(0)
+

+
#define utstring_renew(s)                                  \
+
do {                                                       \
+
   if (s) {                                                \
+
     utstring_clear(s);                                    \
+
   } else {                                                \
+
     utstring_new(s);                                      \
+
   }                                                       \
+
} while(0)
+

+
#define utstring_clear(s)                                  \
+
do {                                                       \
+
  (s)->i = 0;                                              \
+
  (s)->d[0] = '\0';                                        \
+
} while(0)
+

+
#define utstring_bincpy(s,b,l)                             \
+
do {                                                       \
+
  utstring_reserve((s),(l)+1);                               \
+
  if (l) memcpy(&(s)->d[(s)->i], b, l);                    \
+
  (s)->i += l;                                               \
+
  (s)->d[(s)->i]='\0';                                         \
+
} while(0)
+

+
#define utstring_concat(dst,src)                                 \
+
do {                                                             \
+
  utstring_reserve((dst),((src)->i)+1);                          \
+
  if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
+
  (dst)->i += (src)->i;                                          \
+
  (dst)->d[(dst)->i]='\0';                                       \
+
} while(0)
+

+
#define utstring_len(s) ((unsigned)((s)->i))
+

+
#define utstring_body(s) ((s)->d)
+

+
_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
+
   int n;
+
   va_list cp;
+
   while (1) {
+
#ifdef _WIN32
+
      cp = ap;
+
#else
+
      va_copy(cp, ap);
+
#endif
+
      n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
+
      va_end(cp);
+

+
      if ((n > -1) && (n < (int)(s->n-s->i))) {
+
        s->i += n;
+
        return;
+
      }
+

+
      /* Else try again with more space. */
+
      if (n > -1) utstring_reserve(s,n+1); /* exact */
+
      else utstring_reserve(s,(s->n)*2);   /* 2x */
+
   }
+
}
+
#ifdef __GNUC__
+
/* support printf format checking (2=the format string, 3=start of varargs) */
+
static void utstring_printf(UT_string *s, const char *fmt, ...)
+
  __attribute__ (( format( printf, 2, 3) ));
+
#endif
+
_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) {
+
   va_list ap;
+
   va_start(ap,fmt);
+
   utstring_printf_va(s,fmt,ap);
+
   va_end(ap);
+
}
+

+
#define utstring_append_len(dst, src, len)                                    \
+
do {                                                                           \
+
    while ((dst)->n-(dst)->i <= (len)) utstring_reserve((dst),((dst)->n)*2);   \
+
    memcpy(&(dst)->d[(dst)->i], (src), (len));                                 \
+
    (dst)->i+=(len);                                                           \
+
    (dst)->d[(dst)->i]='\0';                                                   \
+
} while(0)
+

+
#define utstring_append_c(dst, c)                                             \
+
do {                                                                           \
+
    if ((dst)->n-(dst)->i < 2) utstring_reserve((dst),((dst)->n)*2);            \
+
    (dst)->d[(dst)->i++] = (c);                                                \
+
    (dst)->d[(dst)->i]='\0';                                                   \
+
} while(0)
+

+
/*******************************************************************************
+
 * begin substring search functions                                            *
+
 ******************************************************************************/
+
/* Build KMP table from left to right. */
+
_UNUSED_ static void _utstring_BuildTable(
+
    const char *P_Needle, 
+
    ssize_t P_NeedleLen, 
+
    long *P_KMP_Table)
+
{
+
    long i, j;
+

+
    i = 0;
+
    j = i - 1;
+
    P_KMP_Table[i] = j;
+
    while (i < P_NeedleLen)
+
    {
+
        while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
+
        {
+
           j = P_KMP_Table[j];
+
        }
+
        i++;
+
        j++;
+
        if (i < P_NeedleLen)
+
        {
+
            if (P_Needle[i] == P_Needle[j])
+
            {
+
                P_KMP_Table[i] = P_KMP_Table[j];
+
            }
+
            else
+
            {
+
                P_KMP_Table[i] = j;
+
            }
+
        }
+
        else
+
        {
+
            P_KMP_Table[i] = j;
+
        }
+
    }
+

+
    return;
+
}
+

+

+
/* Build KMP table from right to left. */
+
_UNUSED_ static void _utstring_BuildTableR(
+
    const char *P_Needle, 
+
    ssize_t P_NeedleLen, 
+
    long *P_KMP_Table)
+
{
+
    long i, j;
+

+
    i = P_NeedleLen - 1;
+
    j = i + 1;
+
    P_KMP_Table[i + 1] = j;
+
    while (i >= 0)
+
    {
+
        while ( (j < P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
+
        {
+
           j = P_KMP_Table[j + 1];
+
        }
+
        i--;
+
        j--;
+
        if (i >= 0)
+
        {
+
            if (P_Needle[i] == P_Needle[j])
+
            {
+
                P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
+
            }
+
            else
+
            {
+
                P_KMP_Table[i + 1] = j;
+
            }
+
        }
+
        else
+
        {
+
            P_KMP_Table[i + 1] = j;
+
        }
+
    }
+

+
    return;
+
}
+

+

+
/* Search data from left to right. ( Multiple search mode. ) */
+
_UNUSED_ static long _utstring_find(
+
    const char *P_Haystack, 
+
    size_t P_HaystackLen, 
+
    const char *P_Needle, 
+
    size_t P_NeedleLen, 
+
    long *P_KMP_Table)
+
{
+
    long i, j;
+
    long V_FindPosition = -1;
+

+
    /* Search from left to right. */
+
    i = j = 0;
+
    while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
+
    {
+
        while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
+
        {
+
            i = P_KMP_Table[i];
+
        }
+
        i++;
+
        j++;
+
        if (i >= (int)P_NeedleLen)
+
        {
+
            /* Found. */
+
            V_FindPosition = j - i;
+
            break;
+
        }
+
    }
+

+
    return V_FindPosition;
+
}
+

+

+
/* Search data from right to left. ( Multiple search mode. ) */
+
_UNUSED_ static long _utstring_findR(
+
    const char *P_Haystack, 
+
    size_t P_HaystackLen, 
+
    const char *P_Needle, 
+
    size_t P_NeedleLen, 
+
    long *P_KMP_Table)
+
{
+
    long i, j;
+
    long V_FindPosition = -1;
+

+
    /* Search from right to left. */
+
    j = (P_HaystackLen - 1);
+
    i = (P_NeedleLen - 1);
+
    while ( (j >= 0) && (j >= i) )
+
    {
+
        while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
+
        {
+
            i = P_KMP_Table[i + 1];
+
        }
+
        i--;
+
        j--;
+
        if (i < 0)
+
        {
+
            /* Found. */
+
            V_FindPosition = j + 1;
+
            break;
+
        }
+
    }
+

+
    return V_FindPosition;
+
}
+

+

+
/* Search data from left to right. ( One time search mode. ) */
+
_UNUSED_ static long utstring_find(
+
    UT_string *s, 
+
    long P_StartPosition,   /* Start from 0. -1 means last position. */
+
    const char *P_Needle, 
+
    ssize_t P_NeedleLen)
+
{
+
    long V_StartPosition;
+
    long V_HaystackLen;
+
    long *V_KMP_Table;
+
    long V_FindPosition = -1;
+

+
    if (P_StartPosition < 0)
+
    {
+
        V_StartPosition = s->i + P_StartPosition;
+
    }
+
    else
+
    {
+
        V_StartPosition = P_StartPosition;
+
    }
+
    V_HaystackLen = s->i - V_StartPosition;
+
    if ( (V_HaystackLen >= P_NeedleLen) && (P_NeedleLen > 0) )
+
    {
+
        V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
+
        if (V_KMP_Table != NULL)
+
        {
+
            _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
+

+
            V_FindPosition = _utstring_find(s->d + V_StartPosition, 
+
                                            V_HaystackLen, 
+
                                            P_Needle, 
+
                                            P_NeedleLen, 
+
                                            V_KMP_Table);
+
            if (V_FindPosition >= 0)
+
            {
+
                V_FindPosition += V_StartPosition;
+
            }
+

+
            free(V_KMP_Table);
+
        }
+
    }
+

+
    return V_FindPosition;
+
}
+

+

+
/* Search data from right to left. ( One time search mode. ) */
+
_UNUSED_ static long utstring_findR(
+
    UT_string *s, 
+
    long P_StartPosition,   /* Start from 0. -1 means last position. */
+
    const char *P_Needle, 
+
    ssize_t P_NeedleLen)
+
{
+
    long V_StartPosition;
+
    long V_HaystackLen;
+
    long *V_KMP_Table;
+
    long V_FindPosition = -1;
+

+
    if (P_StartPosition < 0)
+
    {
+
        V_StartPosition = s->i + P_StartPosition;
+
    }
+
    else
+
    {
+
        V_StartPosition = P_StartPosition;
+
    }
+
    V_HaystackLen = V_StartPosition + 1;
+
    if ( (V_HaystackLen >= P_NeedleLen) && (P_NeedleLen > 0) )
+
    {
+
        V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
+
        if (V_KMP_Table != NULL)
+
        {
+
            _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
+

+
            V_FindPosition = _utstring_findR(s->d, 
+
                                             V_HaystackLen, 
+
                                             P_Needle, 
+
                                             P_NeedleLen, 
+
                                             V_KMP_Table);
+

+
            free(V_KMP_Table);
+
        }
+
    }
+

+
    return V_FindPosition;
+
}
+
/*******************************************************************************
+
 * end substring search functions                                              *
+
 ******************************************************************************/
+

+
#endif /* UTSTRING_H */
modified libpkg/pkg_config.c
@@ -347,15 +347,14 @@ static void
obj_walk_array(ucl_object_t *obj, struct pkg_config *conf)
{
	struct pkg_config_value *v;
-
	ucl_object_t *sub;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	
-
	sub =  obj->value.ov;
-
	while (sub != NULL) {
-
		if (sub->type != UCL_STRING)
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		if (cur->type != UCL_STRING)
			continue;
		v = malloc(sizeof(struct pkg_config_value));
-
		v->value = strdup(ucl_object_tostring(sub));
-
		sub = sub->next;
+
		v->value = strdup(ucl_object_tostring(cur));
		HASH_ADD_STR(conf->list, value, v);
	}
}
@@ -364,14 +363,15 @@ static void
obj_walk_object(ucl_object_t *obj, struct pkg_config *conf)
{
	struct pkg_config_kv *kv;
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;

-
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		if (sub->type != UCL_STRING)
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		if (cur->type != UCL_STRING)
			continue;
		kv = malloc(sizeof(struct pkg_config_kv));
-
		kv->key = strdup(ucl_object_key(sub));
-
		kv->value = strdup(ucl_object_tostring(sub));
+
		kv->key = strdup(ucl_object_key(cur));
+
		kv->value = strdup(ucl_object_tostring(cur));
		HASH_ADD_STR(conf->kvlist, value, kv);
	}
}
@@ -379,14 +379,15 @@ obj_walk_object(ucl_object_t *obj, struct pkg_config *conf)
void
pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	struct sbuf *b = sbuf_new_auto();
	struct pkg_config *conf;
	const char *key;

-
	HASH_ITER(hh, obj, sub, tmp) {
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
		sbuf_clear(b);
-
		key = ucl_object_key(sub);
+
		key = ucl_object_key(cur);
		for (size_t i = 0; i < strlen(key); i++)
			sbuf_putc(b, toupper(key[i]));
		sbuf_finish(b);
@@ -395,51 +396,51 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
		if (conf != NULL) {
			switch (conf->type) {
			case PKG_CONFIG_STRING:
-
				if (sub->type != UCL_STRING) {
+
				if (cur->type != UCL_STRING) {
					pkg_emit_error("Expecting a string for key %s,"
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv) {
					free(conf->string);
-
					conf->string = strdup(ucl_object_tostring(sub));
+
					conf->string = strdup(ucl_object_tostring(cur));
				}
				break;
			case PKG_CONFIG_INTEGER:
-
				if (sub->type != UCL_INT) {
+
				if (cur->type != UCL_INT) {
					pkg_emit_error("Expecting an integer for key %s,"
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
-
					conf->integer = ucl_object_toint(sub);
+
					conf->integer = ucl_object_toint(cur);
				break;
			case PKG_CONFIG_BOOL:
-
				if (sub->type != UCL_BOOLEAN) {
+
				if (cur->type != UCL_BOOLEAN) {
					pkg_emit_error("Expecting a boolean for key %s,"
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
-
					conf->boolean = ucl_object_toboolean(sub);
+
					conf->boolean = ucl_object_toboolean(cur);
				break;
			case PKG_CONFIG_LIST:
-
				if (sub->type != UCL_ARRAY) {
+
				if (cur->type != UCL_ARRAY) {
					pkg_emit_error("Expecting a list for key %s,"
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
-
					obj_walk_array(sub, conf);
+
					obj_walk_array(cur, conf);
				break;
			case PKG_CONFIG_KVLIST:
-
				if (sub->type != UCL_OBJECT) {
+
				if (cur->type != UCL_OBJECT) {
					pkg_emit_error("Expecting a mapping for key %s,"
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
-
					obj_walk_object(sub, conf);
+
					obj_walk_object(cur, conf);
				break;
			}
		}
@@ -681,62 +682,63 @@ disable_plugins_if_static(void)
static void
add_repo(ucl_object_t *obj, struct pkg_repo *r, const char *rname)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	bool enable = true;
	const char *url = NULL, *pubkey = NULL, *mirror_type = NULL;
	const char *signature_type = NULL, *fingerprints = NULL;
	const char *key;

-
	HASH_ITER(hh, obj, sub, tmp) {
-
		key = ucl_object_key(sub);
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
		if (strcasecmp(key, "url") == 0) {
-
			if (sub->type != UCL_STRING) {
+
			if (cur->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			url = ucl_object_tostring(sub);
+
			url = ucl_object_tostring(cur);
		} else if (strcasecmp(key, "pubkey") == 0) {
-
			if (sub->type != UCL_STRING) {
+
			if (cur->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			pubkey = ucl_object_tostring(sub);
+
			pubkey = ucl_object_tostring(cur);
		} else if (strcasecmp(key, "enabled") == 0) {
-
			if (sub->type != UCL_BOOLEAN) {
+
			if (cur->type != UCL_BOOLEAN) {
				pkg_emit_error("Expecting a boolean for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			enable = ucl_object_toboolean(sub);
+
			enable = ucl_object_toboolean(cur);
		} else if (strcasecmp(key, "mirror_type") == 0) {
-
			if (sub->type != UCL_STRING) {
+
			if (cur->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			mirror_type = ucl_object_tostring(sub);
+
			mirror_type = ucl_object_tostring(cur);
		} else if (strcasecmp(key, "signature_type") == 0) {
-
			if (sub->type != UCL_STRING) {
+
			if (cur->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			signature_type = ucl_object_tostring(sub);
+
			signature_type = ucl_object_tostring(cur);
		} else if (strcasecmp(key, "fingerprints") == 0) {
-
			if (sub->type != UCL_STRING) {
+
			if (cur->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
				    key, rname);
				return;
			}
-
			fingerprints = ucl_object_tostring(sub);
+
			fingerprints = ucl_object_tostring(cur);
		}
	}

@@ -788,16 +790,17 @@ add_repo(ucl_object_t *obj, struct pkg_repo *r, const char *rname)
static void
walk_repo_obj(ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	struct pkg_repo *r;
	const char *key;

-
	HASH_ITER(hh, obj, sub, tmp) {
-
		key = ucl_object_key(sub);
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
		r = pkg_repo_find_ident(key);
		if (r != NULL)
			pkg_debug(1, "PkgConfig: overwriting repository %s", key);
-
		add_repo(sub->value.ov, r, key);
+
		add_repo(cur, r, key);
	}
}

@@ -805,8 +808,8 @@ static void
load_repo_file(const char *repofile)
{
	struct ucl_parser *p;
-
	ucl_object_t *obj = NULL;
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *obj = NULL, *cur;
+
	ucl_object_iter_t it = NULL;
	bool fallback = false;

	p = ucl_parser_new(0);
@@ -822,8 +825,8 @@ load_repo_file(const char *repofile)
	if (!fallback) {
		obj = ucl_parser_get_object(p);
		if (obj->type == UCL_OBJECT) {
-
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				if (sub->type != UCL_OBJECT)
+
			while ((cur = ucl_iterate_object(obj, &it, true))) {
+
				if (cur->type != UCL_OBJECT)
					fallback = true;
				if (fallback)
					break;
@@ -855,7 +858,7 @@ load_repo_file(const char *repofile)
	}

	if (obj->type == UCL_OBJECT)
-
		walk_repo_obj(obj->value.ov);
+
		walk_repo_obj(obj);

	ucl_object_free(obj);
}
@@ -934,8 +937,8 @@ pkg_init(const char *path, const char *reposdir)
	struct pkg_config *conf;
	struct pkg_config_value *v;
	struct pkg_config_kv *kv;
-
	ucl_object_t *obj = NULL;
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *obj = NULL, *cur;
+
	ucl_object_iter_t it = NULL;
	bool fallback = false;

	pkg_get_myarch(myabi, BUFSIZ);
@@ -1083,16 +1086,16 @@ pkg_init(const char *path, const char *reposdir)
		/* Validate the first level of the configuration */
		obj = ucl_parser_get_object(p);
		if (obj->type == UCL_OBJECT) {
-
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				key = ucl_object_key(sub);
+
			while ((cur = ucl_iterate_object(obj, &it, true))) {
+
				key = ucl_object_key(cur);
				if (strcasecmp(key, "REPOS_DIR") == 0 &&
-
				    sub->type != UCL_ARRAY)
+
				    cur->type != UCL_ARRAY)
					fallback = true;
				else if (strcasecmp(key, "PKG_ENV") == 0 &&
-
				    sub->type != UCL_OBJECT)
+
				    cur->type != UCL_OBJECT)
					fallback = true;
				else if (strcasecmp(key, "ALIAS") == 0 &&
-
				    sub->type != UCL_OBJECT)
+
				    cur->type != UCL_OBJECT)
					fallback = true;
				if (fallback)
					break;
@@ -1120,7 +1123,7 @@ pkg_init(const char *path, const char *reposdir)
	}

	if (obj->type == UCL_OBJECT)
-
		pkg_object_walk(obj->value.ov, config_by_key);
+
		pkg_object_walk(obj, config_by_key);

parsed:
	disable_plugins_if_static();
modified libpkg/pkg_jobs.c
@@ -1349,9 +1349,8 @@ pkg_jobs_fetch(struct pkg_jobs *j)
		pkg_get(p, PKG_REPOPATH, &pkgrepopath);
		snprintf(path, sizeof(path), "%s/%s", cachedir,
		    pkgrepopath);
-
		if (pkg_open(&pkg, path, keys, 0) != EPKG_OK) {
+
		if (pkg_open(&pkg, path, keys, 0) != EPKG_OK)
			return (EPKG_FATAL);
-
		}

		if (pkgdb_integrity_append(j->db, pkg) != EPKG_OK)
			ret = EPKG_FATAL;
modified libpkg/pkg_manifest.c
@@ -308,62 +308,61 @@ pkg_int(struct pkg *pkg, ucl_object_t *obj, int attr)
static int
pkg_array(struct pkg *pkg, ucl_object_t *obj, int attr)
{
-
	ucl_object_t *sub;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;

-
	sub = obj->value.ov;
	pkg_debug(3, "%s", "Manifest: parsing array");
-
	while (sub) {
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
		switch (attr) {
		case PKG_CATEGORIES:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed category");
			else
-
				pkg_addcategory(pkg, ucl_object_tostring(sub));
+
				pkg_addcategory(pkg, ucl_object_tostring(cur));
			break;
		case PKG_LICENSES:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed license");
			else
-
				pkg_addlicense(pkg, ucl_object_tostring(sub));
+
				pkg_addlicense(pkg, ucl_object_tostring(cur));
			break;
		case PKG_USERS:
-
			if (sub->type == UCL_STRING)
-
				pkg_adduser(pkg, ucl_object_tostring(sub));
-
			else if (sub->type == UCL_OBJECT)
-
				pkg_object(pkg, sub, attr);
+
			if (cur->type == UCL_STRING)
+
				pkg_adduser(pkg, ucl_object_tostring(cur));
+
			else if (cur->type == UCL_OBJECT)
+
				pkg_object(pkg, cur, attr);
			else
				pkg_emit_error("Skipping malformed license");
			break;
		case PKG_GROUPS:
-
			if (sub->type == UCL_STRING)
-
				pkg_addgroup(pkg, ucl_object_tostring(sub));
-
			else if (sub->type == UCL_OBJECT)
-
				pkg_object(pkg, sub, attr);
+
			if (cur->type == UCL_STRING)
+
				pkg_addgroup(pkg, ucl_object_tostring(cur));
+
			else if (cur->type == UCL_OBJECT)
+
				pkg_object(pkg, cur, attr);
			else
				pkg_emit_error("Skipping malformed license");
			break;
		case PKG_DIRS:
-
			if (sub->type == UCL_STRING)
-
				pkg_adddir(pkg, ucl_object_tostring(sub), 1, false);
-
			else if (sub->type == UCL_OBJECT)
-
				pkg_object(pkg, sub, attr);
+
			if (cur->type == UCL_STRING)
+
				pkg_adddir(pkg, ucl_object_tostring(cur), 1, false);
+
			else if (cur->type == UCL_OBJECT)
+
				pkg_object(pkg, cur, attr);
			else
				pkg_emit_error("Skipping malformed dirs");
			break;
		case PKG_SHLIBS_REQUIRED:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed required shared library");
			else
-
				pkg_addshlib_required(pkg, ucl_object_tostring(sub));
+
				pkg_addshlib_required(pkg, ucl_object_tostring(cur));
			break;
		case PKG_SHLIBS_PROVIDED:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed provided shared library");
			else
-
				pkg_addshlib_provided(pkg, ucl_object_tostring(sub));
+
				pkg_addshlib_provided(pkg, ucl_object_tostring(cur));
			break;
		}
-
		sub = sub->next;
	}

	return (EPKG_OK);
@@ -373,52 +372,53 @@ static int
pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
{
	struct sbuf *tmp = NULL;
-
	ucl_object_t *sub, *otmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	pkg_script script_type;
	const char *key, *buf;
	size_t len;

	pkg_debug(3, "%s", "Manifest: parsing object");
-
	HASH_ITER(hh, obj->value.ov, sub, otmp) {
-
		key = ucl_object_key(sub);
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
		switch (attr) {
		case PKG_DEPS:
-
			if (sub->type != UCL_OBJECT)
+
			if (cur->type != UCL_OBJECT)
				pkg_emit_error("Skipping malformed dependency %s",
				    key);
			else
-
				pkg_set_deps_from_object(pkg, sub);
+
				pkg_set_deps_from_object(pkg, cur);
			break;
		case PKG_DIRS:
-
			if (sub->type != UCL_OBJECT)
+
			if (cur->type != UCL_OBJECT)
				pkg_emit_error("Skipping malformed dirs %s",
				    key);
			else
-
				pkg_set_dirs_from_object(pkg, sub);
+
				pkg_set_dirs_from_object(pkg, cur);
			break;
		case PKG_USERS:
-
			if (sub->type == UCL_STRING)
-
				pkg_adduid(pkg, key, ucl_object_tostring(sub));
+
			if (cur->type == UCL_STRING)
+
				pkg_adduid(pkg, key, ucl_object_tostring(cur));
			else
				pkg_emit_error("Skipping malformed users %s",
				    key);
			break;
		case PKG_GROUPS:
-
			if (sub->type == UCL_STRING)
-
				pkg_addgid(pkg, key, ucl_object_tostring(sub));
+
			if (cur->type == UCL_STRING)
+
				pkg_addgid(pkg, key, ucl_object_tostring(cur));
			else
				pkg_emit_error("Skipping malformed groups %s",
				    key);
			break;
		case PKG_DIRECTORIES:
-
			if (sub->type == UCL_BOOLEAN) {
+
			if (cur->type == UCL_BOOLEAN) {
				urldecode(key, &tmp);
-
				pkg_adddir(pkg, sbuf_data(tmp), ucl_object_toboolean(sub), false);
-
			} else if (sub->type == UCL_OBJECT) {
-
				pkg_set_dirs_from_object(pkg, sub);
-
			} else if (sub->type == UCL_STRING) {
+
				pkg_adddir(pkg, sbuf_data(tmp), ucl_object_toboolean(cur), false);
+
			} else if (cur->type == UCL_OBJECT) {
+
				pkg_set_dirs_from_object(pkg, cur);
+
			} else if (cur->type == UCL_STRING) {
				urldecode(key, &tmp);
-
				if (ucl_object_tostring(sub)[0] == 'y')
+
				if (ucl_object_tostring(cur)[0] == 'y')
					pkg_adddir(pkg, sbuf_data(tmp), 1, false);
				else
					pkg_adddir(pkg, sbuf_data(tmp), 0, false);
@@ -428,41 +428,41 @@ pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
			}
			break;
		case PKG_FILES:
-
			if (sub->type == UCL_STRING) {
-
				buf = ucl_object_tolstring(sub, &len);
+
			if (cur->type == UCL_STRING) {
+
				buf = ucl_object_tolstring(cur, &len);
				urldecode(key, &tmp);
				pkg_addfile(pkg, sbuf_get(tmp), len == 64 ? buf : NULL, false);
-
			} else if (sub->type == UCL_OBJECT)
-
				pkg_set_files_from_object(pkg, sub);
+
			} else if (cur->type == UCL_OBJECT)
+
				pkg_set_files_from_object(pkg, cur);
			else
				pkg_emit_error("Skipping malformed files %s",
				   key);
			break;
		case PKG_OPTIONS:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option %s",
				    key);
			else
-
				pkg_addoption(pkg, key, ucl_object_tostring(sub));
+
				pkg_addoption(pkg, key, ucl_object_tostring(cur));
			break;
		case PKG_OPTION_DEFAULTS:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option default %s",
				    key);
			else
				pkg_addoption_default(pkg, key,
-
				    ucl_object_tostring(sub));
+
				    ucl_object_tostring(cur));
			break;
		case PKG_OPTION_DESCRIPTIONS:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option description %s",
				    key);
			else
				pkg_addoption_description(pkg, key,
-
				    ucl_object_tostring(sub));
+
				    ucl_object_tostring(cur));
			break;
		case PKG_SCRIPTS:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed scripts %s",
				    key);
			else {
@@ -473,16 +473,16 @@ pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
					break;
				}

-
				urldecode(ucl_object_tostring(sub), &tmp);
+
				urldecode(ucl_object_tostring(cur), &tmp);
				pkg_addscript(pkg, sbuf_data(tmp), script_type);
			}
			break;
		case PKG_ANNOTATIONS:
-
			if (sub->type != UCL_STRING)
+
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed annotation %s",
				    key);
			else
-
				pkg_addannotation(pkg, key, ucl_object_tostring(sub));
+
				pkg_addannotation(pkg, key, ucl_object_tostring(cur));
			break;
		}
	}
@@ -495,7 +495,8 @@ pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
static int
pkg_set_files_from_object(struct pkg *pkg, ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	const char *sum = NULL;
	const char *uname = NULL;
	const char *gname = NULL;
@@ -505,24 +506,24 @@ pkg_set_files_from_object(struct pkg *pkg, ucl_object_t *obj)
	const char *key;

	urldecode(ucl_object_key(obj), &fname);
-
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (!strcasecmp(key, "uname") && sub->type == UCL_STRING)
-
			uname = ucl_object_tostring(sub);
-
		else if (!strcasecmp(key, "gname") && sub->type == UCL_STRING)
-
			gname = ucl_object_tostring(sub);
-
		else if (!strcasecmp(key, "sum") && sub->type == UCL_STRING &&
-
		    strlen(ucl_object_tostring(sub)) == 64)
-
			sum = ucl_object_tostring(sub);
-
		else if (!strcasecmp(key, "perm") && sub->type == UCL_STRING) {
-
			if ((set = setmode(ucl_object_tostring(sub))) == NULL)
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (!strcasecmp(key, "uname") && cur->type == UCL_STRING)
+
			uname = ucl_object_tostring(cur);
+
		else if (!strcasecmp(key, "gname") && cur->type == UCL_STRING)
+
			gname = ucl_object_tostring(cur);
+
		else if (!strcasecmp(key, "sum") && cur->type == UCL_STRING &&
+
		    strlen(ucl_object_tostring(cur)) == 64)
+
			sum = ucl_object_tostring(cur);
+
		else if (!strcasecmp(key, "perm") && cur->type == UCL_STRING) {
+
			if ((set = setmode(ucl_object_tostring(cur))) == NULL)
				pkg_emit_error("Not a valid mode: %s",
-
				    ucl_object_tostring(sub));
+
				    ucl_object_tostring(cur));
			else
				perm = getmode(set, 0);
		} else {
			pkg_emit_error("Skipping unknown key for file(%s): %s",
-
			    sbuf_data(fname), ucl_object_tostring(sub));
+
			    sbuf_data(fname), ucl_object_tostring(cur));
		}
	}

@@ -535,7 +536,8 @@ pkg_set_files_from_object(struct pkg *pkg, ucl_object_t *obj)
static int
pkg_set_dirs_from_object(struct pkg *pkg, ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	const char *uname = NULL;
	const char *gname = NULL;
	void *set;
@@ -545,20 +547,20 @@ pkg_set_dirs_from_object(struct pkg *pkg, ucl_object_t *obj)
	const char *key;

	urldecode(ucl_object_key(obj), &dirname);
-
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (!strcasecmp(key, "uname") && sub->type == UCL_STRING)
-
			uname = ucl_object_tostring(sub);
-
		else if (!strcasecmp(key, "gname") && sub->type == UCL_STRING)
-
			gname = ucl_object_tostring(sub);
-
		else if (!strcasecmp(key, "perm") && sub->type == UCL_STRING) {
-
			if ((set = setmode(ucl_object_tostring(sub))) == NULL)
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (!strcasecmp(key, "uname") && cur->type == UCL_STRING)
+
			uname = ucl_object_tostring(cur);
+
		else if (!strcasecmp(key, "gname") && cur->type == UCL_STRING)
+
			gname = ucl_object_tostring(cur);
+
		else if (!strcasecmp(key, "perm") && cur->type == UCL_STRING) {
+
			if ((set = setmode(ucl_object_tostring(cur))) == NULL)
				pkg_emit_error("Not a valid mode: %s",
-
				    ucl_object_tostring(sub));
+
				    ucl_object_tostring(cur));
			else
				perm = getmode(set, 0);
-
		} else if (!strcasecmp(key, "try") && sub->type == UCL_BOOLEAN) {
-
				try = ucl_object_toint(sub);
+
		} else if (!strcasecmp(key, "try") && cur->type == UCL_BOOLEAN) {
+
				try = ucl_object_toint(cur);
		} else {
			pkg_emit_error("Skipping unknown key for dir(%s): %s",
			    sbuf_data(dirname), key);
@@ -574,7 +576,8 @@ pkg_set_dirs_from_object(struct pkg *pkg, ucl_object_t *obj)
static int
pkg_set_deps_from_object(struct pkg *pkg, ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	const char *origin = NULL;
	const char *version = NULL;
	const char *key;
@@ -582,12 +585,12 @@ pkg_set_deps_from_object(struct pkg *pkg, ucl_object_t *obj)
	char vinteger[BUFSIZ];

	pkg_debug(2, "Found %s", ucl_object_key(obj));
-
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (sub->type != UCL_STRING) {
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (cur->type != UCL_STRING) {
			/* accept version to be an integer */
-
			if (sub->type == UCL_INT && strcasecmp(key, "version") == 0) {
-
				vint = ucl_object_toint(sub);
+
			if (cur->type == UCL_INT && strcasecmp(key, "version") == 0) {
+
				vint = ucl_object_toint(cur);
				snprintf(vinteger, sizeof(vinteger), "%"PRId64, vint);
				continue;
			}
@@ -597,9 +600,9 @@ pkg_set_deps_from_object(struct pkg *pkg, ucl_object_t *obj)
			continue;
		}
		if (strcasecmp(key, "origin") == 0)
-
			origin = ucl_object_tostring(sub);
+
			origin = ucl_object_tostring(cur);
		if (strcasecmp(key, "version") == 0)
-
			version = ucl_object_tostring(sub);
+
			version = ucl_object_tostring(cur);
	}
	if (origin != NULL && (version != NULL || vint > 0))
		pkg_adddep(pkg, ucl_object_key(obj), origin, vint > 0 ? vinteger : version, false);
@@ -613,17 +616,18 @@ pkg_set_deps_from_object(struct pkg *pkg, ucl_object_t *obj)
static int
parse_manifest(struct pkg *pkg, struct pkg_manifest_key *keys, ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	struct pkg_manifest_key *selected_key;
	struct dataparser *dp;

-
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		pkg_debug(2, "Manifest: found key: '%s'", ucl_object_key(sub));
-
		HASH_FIND_STR(keys, ucl_object_key(sub), selected_key);
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		pkg_debug(2, "Manifest: found key: '%s'", ucl_object_key(cur));
+
		HASH_FIND_STR(keys, ucl_object_key(cur), selected_key);
		if (selected_key != NULL) {
-
			HASH_FIND_UCLT(selected_key->parser, &sub->type, dp);
+
			HASH_FIND_UCLT(selected_key->parser, &cur->type, dp);
			if (dp != NULL) {
-
				dp->parse_data(pkg, sub, selected_key->type);
+
				dp->parse_data(pkg, cur, selected_key->type);
			}
		}
	}
@@ -635,8 +639,8 @@ int
pkg_parse_manifest(struct pkg *pkg, char *buf, size_t len, struct pkg_manifest_key *keys)
{
	struct ucl_parser *p = NULL;
-
	ucl_object_t *obj = NULL;
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *obj = NULL, *cur;
+
	ucl_object_iter_t it = NULL;
	int rc;
	struct pkg_manifest_key *sk;
	struct dataparser *dp;
@@ -654,10 +658,10 @@ pkg_parse_manifest(struct pkg *pkg, char *buf, size_t len, struct pkg_manifest_k
	if (!fallback) {
		obj = ucl_parser_get_object(p);
		if (obj != NULL) {
-
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				HASH_FIND_STR(keys, ucl_object_key(sub), sk);
+
			while ((cur = ucl_iterate_object(obj, &it, true))) {
+
				HASH_FIND_STR(keys, ucl_object_key(cur), sk);
				if (sk != NULL) {
-
					HASH_FIND_UCLT(sk->parser, &sub->type, dp);
+
					HASH_FIND_UCLT(sk->parser, &cur->type, dp);
					if (dp == NULL) {
						fallback = true;
						break;
@@ -671,13 +675,15 @@ pkg_parse_manifest(struct pkg *pkg, char *buf, size_t len, struct pkg_manifest_k

	if (fallback) {
		pkg_debug(2, "Falling back on yaml");
-
		ucl_parser_free(p);
		p = NULL;
		if (obj != NULL)
			ucl_object_free(obj);
		obj = yaml_to_ucl(NULL, buf, len);
-
		if (obj == NULL)
+
		if (obj == NULL) {
+
			printf("%s\n", buf);
+
			ucl_parser_free(p);
			return (EPKG_FATAL);
+
		}
	}

	rc = parse_manifest(pkg, keys, obj);
@@ -693,8 +699,8 @@ int
pkg_parse_manifest_file(struct pkg *pkg, const char *file, struct pkg_manifest_key *keys)
{
	struct ucl_parser *p = NULL;
-
	ucl_object_t *obj = NULL;
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *obj = NULL, *cur;
+
	ucl_object_iter_t it = NULL;
	int rc;
	bool fallback = false;
	struct pkg_manifest_key *sk;
@@ -718,10 +724,10 @@ pkg_parse_manifest_file(struct pkg *pkg, const char *file, struct pkg_manifest_k
	if (!fallback) {
		obj = ucl_parser_get_object(p);
		if (obj != NULL) {
-
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				HASH_FIND_STR(keys, ucl_object_key(sub), sk);
+
			while ((cur = ucl_iterate_object(obj, &it, true))) {
+
				HASH_FIND_STR(keys, ucl_object_key(cur), sk);
				if (sk != NULL) {
-
					HASH_FIND_UCLT(sk->parser, &sub->type, dp);
+
					HASH_FIND_UCLT(sk->parser, &cur->type, dp);
					if (dp == NULL) {
						fallback = true;
						break;
@@ -765,15 +771,15 @@ pkg_emit_filelist(struct pkg *pkg, FILE *f)

	pkg_get(pkg, PKG_NAME, &name, PKG_ORIGIN, &origin, PKG_VERSION, &version);
	obj = ucl_object_insert_key(obj, ucl_object_fromstring(origin), "origin", 6, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(name), "name", 4, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(version), "version", 7, false);
+
	obj = ucl_object_insert_key(obj, ucl_object_fromstring(name), "name", 4, false);
+
	obj = ucl_object_insert_key(obj, ucl_object_fromstring(version), "version", 7, false);

	seq = NULL;
	while (pkg_files(pkg, &file) == EPKG_OK) {
		urlencode(pkg_file_path(file), &b);
		seq = ucl_array_append(seq, ucl_object_fromlstring(sbuf_data(b), sbuf_len(b)));
	}
-
	ucl_object_insert_key(obj, seq, "files", 5, false);
+
	obj = ucl_object_insert_key(obj, seq, "files", 5, false);

	output = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
	fprintf(f, "%s", output);
@@ -809,6 +815,7 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
	lic_t licenselogic;
	int64_t flatsize, pkgsize;
	ucl_object_t *obj = NULL, *map, *seq, *submap;
+
	ucl_object_t *top = NULL;

	pkg_get(pkg, PKG_NAME, &name, PKG_ORIGIN, &pkgorigin,
	    PKG_COMMENT, &comment, PKG_ARCH, &pkgarch, PKG_WWW, &www,
@@ -818,93 +825,104 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
	    PKG_VERSION, &version, PKG_REPOPATH, &repopath,
	    PKG_CKSUM, &pkgsum, PKG_PKGSIZE, &pkgsize);

-
	obj = ucl_object_insert_key(obj, ucl_object_fromstring(name), "name", 4, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgorigin), "origin", 6, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(version), "version", 7, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(comment), "comment", 7, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgarch), "arch", 4, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgmaintainer), "maintainer", 10, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(prefix), "prefix", 6, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(www), "www", 3, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(repopath), "path", 4, false);
-
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgsum), "sum", 3, false);
+
	pkg_debug(1, "Emitting basic metadata");
+
	top = ucl_object_insert_key(top, ucl_object_fromstring(name), "name", 4, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(pkgorigin), "origin", 6, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(version), "version", 7, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(comment), "comment", 7, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(pkgarch), "arch", 4, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(pkgmaintainer), "maintainer", 10, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(prefix), "prefix", 6, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(www), "www", 3, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(repopath), "path", 4, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromstring(pkgsum), "sum", 3, false);

	switch (licenselogic) {
	case LICENSE_SINGLE:
-
		ucl_object_insert_key(obj, ucl_object_fromlstring("single", 6), "licenselogic", 12, false);
+
		obj = ucl_object_insert_key(top, ucl_object_fromlstring("single", 6), "licenselogic", 12, false);
		break;
	case LICENSE_AND:
-
		ucl_object_insert_key(obj, ucl_object_fromlstring("and", 3), "licenselogic", 12, false);
+
		obj = ucl_object_insert_key(top, ucl_object_fromlstring("and", 3), "licenselogic", 12, false);
		break;
	case LICENSE_OR:
-
		ucl_object_insert_key(obj, ucl_object_fromlstring("or", 2), "licenselogic", 12, false);
+
		obj = ucl_object_insert_key(top, ucl_object_fromlstring("or", 2), "licenselogic", 12, false);
		break;
	}

+
	pkg_debug(1, "Emitting licenses");
	seq = NULL;
	while (pkg_licenses(pkg, &license) == EPKG_OK)
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_license_name(license)));
-
	ucl_object_insert_key(obj, seq, "licenses", 8, false);
+
	obj = ucl_object_insert_key(top, seq, "licenses", 8, false);

-
	ucl_object_insert_key(obj, ucl_object_fromint(flatsize), "flatsize", 8, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromint(flatsize), "flatsize", 8, false);
	if (pkgsize > 0)
-
		ucl_object_insert_key(obj, ucl_object_fromint(pkgsize), "pkgsize", 7, false);
+
		obj = ucl_object_insert_key(top, ucl_object_fromint(pkgsize), "pkgsize", 7, false);

	urlencode(desc, &tmpsbuf);
-
	ucl_object_insert_key(obj, ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)), "desc", 4, false);
+
	obj = ucl_object_insert_key(top, ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)), "desc", 4, false);

+
	pkg_debug(1, "Emitting deps");
	map = NULL;
	while (pkg_deps(pkg, &dep) == EPKG_OK) {
		submap = NULL;
		submap = ucl_object_insert_key(submap, ucl_object_fromstring(pkg_dep_origin(dep)), "origin", 6, false);
-
		ucl_object_insert_key(submap, ucl_object_fromstring(pkg_dep_version(dep)), "version", 7, false);
+
		submap = ucl_object_insert_key(submap, ucl_object_fromstring(pkg_dep_version(dep)), "version", 7, false);
		map = ucl_object_insert_key(map, submap, pkg_dep_name(dep), 0, false);
	}
-
	ucl_object_insert_key(obj, map, "deps", 4, false);
+
	obj = ucl_object_insert_key(top, map, "deps", 4, false);

+
	pkg_debug(1, "Emitting categories");
	seq = NULL;
	while (pkg_categories(pkg, &category) == EPKG_OK)
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_category_name(category)));
-
	ucl_object_insert_key(obj, seq, "categories", 10, false);
+
	obj = ucl_object_insert_key(top, seq, "categories", 10, false);

+
	pkg_debug(1, "Emitting users");
	seq = NULL;
	while (pkg_users(pkg, &user) == EPKG_OK)
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_user_name(user)));
-
	ucl_object_insert_key(obj, seq, "users", 5, false);
+
	obj = ucl_object_insert_key(top, seq, "users", 5, false);

+
	pkg_debug(1, "Emitting groups");
	seq = NULL;
	while (pkg_groups(pkg, &group) == EPKG_OK) 
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_group_name(group)));
-
	ucl_object_insert_key(obj, seq, "groups", 6, false);
+
	obj = ucl_object_insert_key(top, seq, "groups", 6, false);

+
	pkg_debug(1, "Emitting required");
	seq = NULL;
	while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK)
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_shlib_name(shlib)));
-
	ucl_object_insert_key(obj, seq, "shlibs_required", 15, false);
+
	obj = ucl_object_insert_key(top, seq, "shlibs_required", 15, false);

+
	pkg_debug(1, "Emitting shlibs_provided");
	seq = NULL;
	while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK)
		seq = ucl_array_append(seq, ucl_object_fromstring(pkg_shlib_name(shlib)));
-
	ucl_object_insert_key(obj, seq, "shlibs_provided", 15, false);
+
	obj = ucl_object_insert_key(top, seq, "shlibs_provided", 15, false);

+
	pkg_debug(1, "Emitting options");
	map = NULL;
	while (pkg_options(pkg, &option) == EPKG_OK) {
		map = ucl_object_insert_key(map,
		    ucl_object_fromstring(pkg_option_value(option)),
		    pkg_option_opt(option), 0, false);
	}
-
	ucl_object_insert_key(obj, map, "options", 7, false);
+
	obj = ucl_object_insert_key(top, map, "options", 7, false);

+
	pkg_debug(1, "Emitting annotations");
	map = NULL;
	while (pkg_annotations(pkg, &note) == EPKG_OK) {
		map = ucl_object_insert_key(map,
		    ucl_object_fromstring(pkg_annotation_value(note)),
		    pkg_annotation_tag(note), 0, false);
	}
-
	ucl_object_insert_key(obj, map, "annotations", 11, false);
+
	obj = ucl_object_insert_key(top, map, "annotations", 11, false);

	if ((flags & PKG_MANIFEST_EMIT_COMPACT) == 0) {
		if ((flags & PKG_MANIFEST_EMIT_NOFILES) == 0) {
+
			pkg_debug(1, "Emitting files");
			map = NULL;
			while (pkg_files(pkg, &file) == EPKG_OK) {
				const char *pkg_sum = pkg_file_cksum(file);
@@ -916,9 +934,11 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
				map = ucl_object_insert_key(map,
				    ucl_object_fromstring(pkg_sum),
				    sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), true);
+
				printf("%s\n", sbuf_data(tmpsbuf));
			}
-
			ucl_object_insert_key(obj, map, "files", 5, false);
+
			obj = ucl_object_insert_key(top, map, "files", 5, false);

+
			pkg_debug(1, "Emitting directories");
			map = NULL;
			while (pkg_dirs(pkg, &dir) == EPKG_OK) {
				urlencode(pkg_dir_path(dir), &tmpsbuf);
@@ -929,9 +949,10 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
				    ucl_object_fromstring(pkg_dir_try(dir) ? "y" : "n"),
				    sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), true);
			}
-
			ucl_object_insert_key(obj, map, "directories", 11, false);
+
			obj = ucl_object_insert_key(top, map, "directories", 11, false);
		}

+
		pkg_debug(1, "Emitting scripts");
		map = NULL;
		for (i = 0; i < PKG_NUM_SCRIPTS; i++) {
			if (pkg_script_get(pkg, i) == NULL)
@@ -971,12 +992,13 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
			    ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)),
			    script_types, 0, true);
		}
-
		ucl_object_insert_key(obj, map, "scripts", 7, false);
+
		obj = ucl_object_insert_key(top, map, "scripts", 7, false);
	}

+
	pkg_debug(1, "Emitting message");
	if (message != NULL && *message != '\0') {
		urlencode(message, &tmpsbuf);
-
		ucl_object_insert_key(obj,
+
		obj = ucl_object_insert_key(top,
		    ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)),
		    "message", 7, false);
	}
modified libpkg/pkg_ports.c
@@ -642,18 +642,16 @@ parse_actions(ucl_object_t *o, struct plist *p,
    char *line, struct file_attr *a)
{
	ucl_object_t *cur;
-

-
	cur = o;
+
	ucl_object_iter_t it = NULL;
	int i;

-
	while (cur) {
+
	while ((cur = ucl_iterate_object(o, &it, true))) {
		for (i = 0; list_actions[i].name != NULL; i++) {
			if (!strcasecmp(ucl_object_tostring(cur), list_actions[i].name)) {
				list_actions[i].perform(p, line, a);
				break;
			}
		}
-
		cur = cur->next;
	}

	return (EPKG_OK);
@@ -661,29 +659,30 @@ parse_actions(ucl_object_t *o, struct plist *p,

static void
parse_attributes(ucl_object_t *o, struct file_attr **a) {
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it = NULL;
	const char *key;

	if (*a == NULL)
		*a = calloc(1, sizeof(struct file_attr));

-
	HASH_ITER(hh, o, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (!strcasecmp(key, "owner") && sub->type == UCL_STRING) {
+
	while ((cur = ucl_iterate_object(o, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (!strcasecmp(key, "owner") && cur->type == UCL_STRING) {
			free((*a)->owner);
-
			(*a)->owner = strdup(ucl_object_tostring(sub));
+
			(*a)->owner = strdup(ucl_object_tostring(cur));
			continue;
		}
-
		if (!strcasecmp(key, "group") && sub->type == UCL_STRING) {
+
		if (!strcasecmp(key, "group") && cur->type == UCL_STRING) {
			free((*a)->group);
-
			(*a)->group = strdup(ucl_object_tostring(sub));
+
			(*a)->group = strdup(ucl_object_tostring(cur));
			continue;
		}
		if (!strcasecmp(key, "mode")) {
-
			if (sub->type == UCL_STRING) {
+
			if (cur->type == UCL_STRING) {
				void *set;
-
				if ((set = setmode(ucl_object_tostring(sub))) == NULL)
-
					pkg_emit_error("Bad format for the mode attribute: %s", ucl_object_tostring(sub));
+
				if ((set = setmode(ucl_object_tostring(cur))) == NULL)
+
					pkg_emit_error("Bad format for the mode attribute: %s", ucl_object_tostring(cur));
				else
					(*a)->mode = getmode(set, 0);
				free(set);
@@ -698,58 +697,59 @@ parse_attributes(ucl_object_t *o, struct file_attr **a) {
static int
parse_and_apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_attr *attr)
{
-
	ucl_object_t *sub, *tmp, *actions = NULL;
+
	ucl_object_t *cur, *actions = NULL;
+
	ucl_object_iter_t it = NULL;
	char *cmd;
	const char *key;

-
	HASH_ITER(hh, obj, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (!strcasecmp(key, "actions") && sub->type == UCL_ARRAY) {
-
			actions = sub->value.ov;
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (!strcasecmp(key, "actions") && cur->type == UCL_ARRAY) {
+
			actions = cur;
			continue;
		}

-
		if (!strcasecmp(key, "attributes") && sub->type == UCL_OBJECT) {
-
			parse_attributes(sub->value.ov, &attr);
+
		if (!strcasecmp(key, "attributes") && cur->type == UCL_OBJECT) {
+
			parse_attributes(cur, &attr);
			continue;
		}

-
		if (!strcasecmp(key, "pre-install") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "pre-install") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			sbuf_cat(p->pre_install_buf, cmd);
			free(cmd);
			continue;
		}

-
		if (!strcasecmp(key, "post-install") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "post-install") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			sbuf_cat(p->post_install_buf, cmd);
			free(cmd);
			continue;
		}

-
		if (!strcasecmp(key, "pre-deinstall") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "pre-deinstall") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			sbuf_cat(p->pre_deinstall_buf, cmd);
			free(cmd);
			continue;
		}

-
		if (!strcasecmp(key, "post-deinstall") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "post-deinstall") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			free(cmd);
			continue;
		}

-
		if (!strcasecmp(key, "pre-upgrade") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "pre-upgrade") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			sbuf_cat(p->pre_upgrade_buf, cmd);
			free(cmd);
			continue;
		}

-
		if (!strcasecmp(key, "post-upgrade") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "post-upgrade") && cur->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(cur), p->prefix, p->last_file, line);
			sbuf_cat(p->post_upgrade_buf, cmd);
			free(cmd);
			continue;
@@ -783,7 +783,7 @@ external_keyword(struct plist *plist, char *keyword, char *line, struct file_att
	if ((o = yaml_to_ucl(keyfile_path, NULL, 0)) == NULL)
		return (EPKG_UNKNOWN);

-
	ret = parse_and_apply_keyword_file(o->value.ov, plist, line, attr);
+
	ret = parse_and_apply_keyword_file(o, plist, line, attr);

	return (ret);
}
modified libpkg/plugins.c
@@ -561,7 +561,7 @@ pkg_plugin_parse(struct pkg_plugin *p)

	obj = ucl_parser_get_object(pr);
	if (obj->type == UCL_OBJECT)
-
		pkg_object_walk(obj->value.ov, p->conf_by_key);
+
		pkg_object_walk(obj, p->conf_by_key);

	p->parsed = true;
	ucl_object_free(obj);
modified libpkg/update.c
@@ -125,25 +125,25 @@ has_ext(const char *path, const char *ext)
static struct fingerprint *
parse_fingerprint(ucl_object_t *obj)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *cur;
+
	ucl_object_iter_t it;
	const char *function = NULL, *fp = NULL;
	hash_t fct = HASH_UNKNOWN;
	struct fingerprint *f = NULL;
	const char *key;

-

-
	HASH_ITER(hh, obj, sub, tmp) {
-
		key = ucl_object_key(sub);
-
		if (sub->type != UCL_STRING)
+
	while ((cur = ucl_iterate_object(obj, &it, true))) {
+
		key = ucl_object_key(cur);
+
		if (cur->type != UCL_STRING)
			continue;

		if (strcasecmp(key, "function") == 0) {
-
			function = ucl_object_tostring(sub);
+
			function = ucl_object_tostring(cur);
			continue;
		}

		if (strcasecmp(key, "fingerprint") == 0) {
-
			fp = ucl_object_tostring(sub);
+
			fp = ucl_object_tostring(cur);
			continue;
		}
	}
@@ -187,7 +187,7 @@ load_fingerprint(const char *dir, const char *filename)
	obj = ucl_parser_get_object(p);

	if (obj->type == UCL_OBJECT)
-
		f = parse_fingerprint(obj->value.ov);
+
		f = parse_fingerprint(obj);

	ucl_object_free(obj);
	ucl_parser_free(p);