Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update to latest ucl
Baptiste Daroussin committed 12 years ago
commit f4e298139e7cc2eaf4ca80758a2cdff14a860bb4
parent 2236f4c
10 files changed +838 -457
modified external/libucl/include/ucl.h
@@ -33,9 +33,38 @@
#include <stdio.h>

#include "uthash.h"
+
#include "utlist.h"
#include "utstring.h"

/**
+
 * @file rcl.h
+
 * RCL is an rspamd configuration language, which is a form of
+
 * JSON with less strict rules that make it more comfortable for
+
 * using as a configuration language
+
 */
+

+
/**
+
 * XXX: Poorly named API functions, need to replace them with the appropriate
+
 * named function. All API functions *must* use naming ucl_object_*. Usage of
+
 * ucl_obj* should be avoided.
+
 */
+
#define ucl_object_todouble_safe ucl_obj_todouble_safe
+
#define ucl_object_todouble ucl_obj_todouble
+
#define ucl_object_tostring ucl_obj_tostring
+
#define ucl_object_tostring_safe ucl_obj_tostring_safe
+
#define ucl_object_tolstring ucl_obj_tolstring
+
#define ucl_object_tolstring_safe ucl_obj_tolstring_safe
+
#define ucl_object_toint ucl_obj_toint
+
#define ucl_object_toint_safe ucl_obj_toint_safe
+
#define ucl_object_toboolean ucl_obj_toboolean
+
#define ucl_object_toboolean_safe ucl_obj_toboolean_safe
+
#define ucl_object_find_key ucl_obj_get_key
+
#define ucl_object_find_keyl ucl_obj_get_keyl
+
#define ucl_object_unref ucl_obj_unref
+
#define ucl_object_ref ucl_obj_ref
+
#define ucl_object_free ucl_obj_free
+

+
/**
 * Memory allocation utilities
 * UCL_ALLOC(size) - allocate memory for UCL
 * UCL_FREE(size, ptr) - free memory of specified size at ptr
@@ -48,13 +77,6 @@
#define UCL_FREE(size, ptr) free(ptr)
#endif

-
/**
-
 * @file rcl.h
-
 * RCL is an rspamd configuration language, which is a form of
-
 * JSON with less strict rules that make it more comfortable for
-
 * using as a configuration language
-
 */
-

enum ucl_error {
	UCL_EOK = 0,   //!< UCL_EOK
	UCL_ESYNTAX,   //!< UCL_ESYNTAX
@@ -86,27 +108,43 @@ enum ucl_emitter {
};

enum ucl_flags {
-
	UCL_FLAG_KEY_LOWERCASE = 0x1
+
	UCL_FLAG_KEY_LOWERCASE = 0x1,
+
	UCL_FLAG_ZEROCOPY = 0x2
};

typedef struct ucl_object_s {
-
	char *key;								/**< the key of an object */
	union {
		int64_t iv;							/**< int value of an object */
-
		char *sv;							/**< string 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 			*/
-
		void* ud;						/**< opaque user data		*/
+
		struct ucl_object_s *ov;			/**< array or hash 			*/
+
		void* ud;							/**< opaque user data		*/
	} value;
-
	enum ucl_type type;				/**< real type				*/
+
	enum ucl_type type;						/**< real type				*/
	int ref;								/**< reference count		*/
-
	struct ucl_object_s *next;		/**< array handle			*/
-
	struct ucl_object_s *prev;		/**< array handle			*/
+
	size_t len;								/**< size 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			*/
} ucl_object_t;


/**
+
 * Copy and return a key of an object, returned key is zero-terminated
+
 * @param obj CL object
+
 * @return zero terminated key
+
 */
+
char* ucl_copy_key_trash (ucl_object_t *obj);
+

+
/**
+
 * Copy and return a string value of an object, returned key is zero-terminated
+
 * @param obj CL object
+
 * @return zero terminated string representation of object value
+
 */
+
char* ucl_copy_value_trash (ucl_object_t *obj);
+

+
/**
 * Creates a new object
 * @return new object
 */
@@ -122,6 +160,173 @@ ucl_object_new (void)
	return new;
}

+
/**
+
 * String conversion flags
+
 */
+
enum ucl_string_flags {
+
	UCL_STRING_ESCAPE = 0x0,  /**< UCL_STRING_ESCAPE perform JSON escape */
+
	UCL_STRING_TRIM = 0x1     /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
+
};
+

+
/**
+
 * Convert any string to an ucl object making the specified transformations
+
 * @param str fixed size or NULL terminated string
+
 * @param len length (if len is zero, than str is treated as NULL terminated)
+
 * @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);
+

+
/**
+
 * Create a UCL object from the specified string
+
 * @param str NULL terminated string, will be json escaped
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_fromstring (const char *str)
+
{
+
	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
+
}
+

+
/**
+
 * Create a UCL object from the specified string
+
 * @param str fixed size string, will be json escaped
+
 * @param len length of a string
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_fromlstring (const char *str, size_t len)
+
{
+
	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
+
}
+

+
/**
+
 * Create an object from an integer number
+
 * @param iv number
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_fromint (int64_t iv)
+
{
+
	ucl_object_t *obj;
+

+
	obj = ucl_object_new ();
+
	if (obj != NULL) {
+
		obj->type = UCL_INT;
+
		obj->value.iv = iv;
+
	}
+

+
	return obj;
+
}
+

+
/**
+
 * Create an object from a float number
+
 * @param dv number
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_fromdouble (double dv)
+
{
+
	ucl_object_t *obj;
+

+
	obj = ucl_object_new ();
+
	if (obj != NULL) {
+
		obj->type = UCL_FLOAT;
+
		obj->value.dv = dv;
+
	}
+

+
	return obj;
+
}
+

+
/**
+
 * Create an object from a boolean
+
 * @param bv bool value
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_frombool (bool bv)
+
{
+
	ucl_object_t *obj;
+

+
	obj = ucl_object_new ();
+
	if (obj != NULL) {
+
		obj->type = UCL_BOOLEAN;
+
		obj->value.iv = bv;
+
	}
+

+
	return obj;
+
}
+

+
/**
+
 * Insert a object 'elt' to the hash 'top' and associate it with key 'key'
+
 * @param top destination object (will be created automatically if top is NULL)
+
 * @param elt element to insert (must NOT be NULL)
+
 * @param key key to associate with this object (either const or preallocated)
+
 * @param keylen length of the key (or 0 for NULL terminated keys)
+
 * @return new value of top object
+
 */
+
static inline ucl_object_t *
+
ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, const char *key, size_t keylen)
+
{
+
	ucl_object_t *found;
+

+
	if (elt == NULL || key == NULL) {
+
		return NULL;
+
	}
+

+
	if (top == NULL) {
+
		top = ucl_object_new ();
+
		top->type = UCL_OBJECT;
+
	}
+
	if (keylen == 0) {
+
		keylen = strlen (key);
+
	}
+

+
	HASH_FIND (hh, top->value.ov, key, keylen, found);
+

+
	if (!found) {
+
		HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt);
+
	}
+
	DL_APPEND (found, elt);
+

+
	return top;
+
}
+

+
/**
+
 * Append an element to the array object
+
 * @param top destination object (will be created automatically if top is NULL)
+
 * @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)
+
{
+
	if (elt == NULL) {
+
		return NULL;
+
	}
+

+
	if (top == NULL) {
+
		top = ucl_object_new ();
+
		top->type = UCL_ARRAY;
+
	}
+

+
	DL_APPEND (top->value.ov, elt);
+

+
	return top;
+
}
+

+
/**
+
 * Append a element to another element forming an implicit array
+
 * @param head head to append (may be NULL)
+
 * @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)
+
{
+
	DL_APPEND (head, elt);
+
	return head;
+
}

/**
 * Converts an object to double value
@@ -160,7 +365,7 @@ ucl_obj_todouble (ucl_object_t *obj)
{
	double result = 0.;

-
	ucl_obj_todouble_safe (obj, &result);
+
	ucl_object_todouble_safe (obj, &result);
	return result;
}

@@ -201,7 +406,7 @@ ucl_obj_toint (ucl_object_t *obj)
{
	int64_t result = 0;

-
	ucl_obj_toint_safe (obj, &result);
+
	ucl_object_toint_safe (obj, &result);
	return result;
}

@@ -238,7 +443,7 @@ ucl_obj_toboolean (ucl_object_t *obj)
{
	bool result = false;

-
	ucl_obj_toboolean_safe (obj, &result);
+
	ucl_object_toboolean_safe (obj, &result);
	return result;
}

@@ -254,9 +459,10 @@ ucl_obj_tostring_safe (ucl_object_t *obj, const char **target)
	if (obj == NULL) {
		return false;
	}
+

	switch (obj->type) {
	case UCL_STRING:
-
		*target = obj->value.sv;
+
		*target = ucl_copy_value_trash (obj);
		break;
	default:
		return false;
@@ -275,7 +481,58 @@ ucl_obj_tostring (ucl_object_t *obj)
{
	const char *result = NULL;

-
	ucl_obj_tostring_safe (obj, &result);
+
	ucl_object_tostring_safe (obj, &result);
+
	return result;
+
}
+

+
/**
+
 * Convert any object to a string in JSON notation if needed
+
 * @param obj CL object
+
 * @return string value
+
 */
+
static inline const char *
+
ucl_obj_tostring_forced (ucl_object_t *obj)
+
{
+
	return ucl_copy_value_trash (obj);
+
}
+

+
/**
+
 * Return string as char * and len, string may be not zero terminated, more efficient that tostring as it
+
 * allows zero-copy
+
 * @param obj CL object
+
 * @param target target string variable, no need to free value
+
 * @param tlen target length
+
 * @return true if conversion was successful
+
 */
+
static inline bool
+
ucl_obj_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
+
{
+
	if (obj == NULL) {
+
		return false;
+
	}
+
	switch (obj->type) {
+
	case UCL_STRING:
+
		*target = obj->value.sv;
+
		*tlen = obj->len;
+
		break;
+
	default:
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Unsafe version of \ref ucl_obj_tolstring_safe
+
 * @param obj CL object
+
 * @return string value
+
 */
+
static inline const char *
+
ucl_obj_tolstring (ucl_object_t *obj, size_t *tlen)
+
{
+
	const char *result = NULL;
+

+
	ucl_object_tolstring_safe (obj, &result, tlen);
	return result;
}

@@ -296,12 +553,57 @@ ucl_obj_get_key (ucl_object_t *obj, const char *key)
	}

	keylen = strlen (key);
-
	HASH_FIND(hh, obj->value.ov, __DECONST(char *, key), keylen, ret);
+
	HASH_FIND (hh, obj->value.ov, key, keylen, ret);
+

+
	return ret;
+
}
+

+
/**
+
 * Return object identified by a fixed size key in the specified object
+
 * @param obj object to get a key from (must be of type UCL_OBJECT)
+
 * @param key key to search
+
 * @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;
}

/**
+
 * Returns a key of an object as a NULL terminated string
+
 * @param obj CL object
+
 * @return key or NULL if there is no key
+
 */
+
static inline const char *
+
ucl_object_key (ucl_object_t *obj)
+
{
+
	return ucl_copy_key_trash (obj);
+
}
+

+
/**
+
 * Returns a key of an object as a fixed size string (may be more efficient)
+
 * @param obj CL object
+
 * @param len target key length
+
 * @return key pointer
+
 */
+
static inline const char *
+
ucl_object_keyl (ucl_object_t *obj, size_t *len)
+
{
+
	*len = obj->hh.keylen;
+
	return obj->hh.key;
+
}
+

+
/**
 * Macro handler for a parser
 * @param data the content of macro
 * @param len the length of content
modified external/libucl/src/ucl_emitter.c
@@ -33,7 +33,6 @@
 */


-
static void ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact);
static void ucl_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact);
static void ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
		bool start_tabs, bool is_top, bool expand_array);
@@ -70,13 +69,13 @@ ucl_add_tabs (UT_string *buf, unsigned int tabs, bool compact)
 * @param buf target buffer
 */
static void
-
ucl_elt_string_write_json (const char *str, UT_string *buf)
+
ucl_elt_string_write_json (const char *str, size_t size, UT_string *buf)
{
	const char *p = str, *c = str;
	size_t len = 0;

	utstring_append_c (buf, '"');
-
	while (*p != '\0') {
+
	while (size) {
		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
			if (len > 0) {
				utstring_append_len (buf, c, len);
@@ -111,6 +110,7 @@ ucl_elt_string_write_json (const char *str, UT_string *buf)
			p ++;
			len ++;
		}
+
		size --;
	}
	if (len > 0) {
		utstring_append_len (buf, c, len);
@@ -154,7 +154,12 @@ ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
	}
	HASH_ITER (hh, obj, cur, tmp) {
		ucl_add_tabs (buf, tabs + 1, compact);
-
		ucl_elt_string_write_json (cur->key, buf);
+
		if (cur->hh.keylen > 0) {
+
			ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+
		}
+
		else {
+
			utstring_append_len (buf, "null", 4);
+
		}
		if (compact) {
			utstring_append_c (buf, ':');
		}
@@ -221,7 +226,7 @@ ucl_elt_array_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
 * @param obj object
 * @param buf buffer
 */
-
static void
+
void
ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
{
	switch (obj->type) {
@@ -229,26 +234,26 @@ ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
		if (start_tabs) {
			ucl_add_tabs (buf, tabs, compact);
		}
-
		utstring_printf (buf, "%ld", (long int)ucl_obj_toint (obj));
+
		utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
		break;
	case UCL_FLOAT:
	case UCL_TIME:
		if (start_tabs) {
			ucl_add_tabs (buf, tabs, compact);
		}
-
		ucl_print_float (buf, ucl_obj_todouble (obj));
+
		ucl_print_float (buf, ucl_object_todouble (obj));
		break;
	case UCL_BOOLEAN:
		if (start_tabs) {
			ucl_add_tabs (buf, tabs, compact);
		}
-
		utstring_printf (buf, "%s", ucl_obj_toboolean (obj) ? "true" : "false");
+
		utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
		break;
	case UCL_STRING:
		if (start_tabs) {
			ucl_add_tabs (buf, tabs, compact);
		}
-
		ucl_elt_string_write_json (ucl_obj_tostring (obj), buf);
+
		ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
		break;
	case UCL_OBJECT:
		ucl_elt_obj_write_json (obj->value.ov, buf, tabs, start_tabs, compact);
@@ -331,7 +336,6 @@ 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;
-
	size_t keylen;

	if (start_tabs) {
		ucl_add_tabs (buf, tabs, is_top);
@@ -342,8 +346,7 @@ ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, boo

	HASH_ITER (hh, obj, cur, tmp) {
		ucl_add_tabs (buf, tabs + 1, is_top);
-
		keylen = strlen (cur->key);
-
		utstring_append_len (buf, cur->key, keylen);
+
		utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
		if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
			utstring_append_len (buf, " = ", 3);
		}
@@ -407,26 +410,26 @@ ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			utstring_printf (buf, "%ld", (long int)ucl_obj_toint (obj));
+
			utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
			break;
		case UCL_FLOAT:
		case UCL_TIME:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			ucl_print_float (buf, ucl_obj_todouble (obj));
+
			ucl_print_float (buf, ucl_object_todouble (obj));
			break;
		case UCL_BOOLEAN:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			utstring_printf (buf, "%s", ucl_obj_toboolean (obj) ? "true" : "false");
+
			utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
			break;
		case UCL_STRING:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			ucl_elt_string_write_json (ucl_obj_tostring (obj), buf);
+
			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);
@@ -468,7 +471,6 @@ 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;
-
	size_t keylen;

	if (start_tabs) {
		ucl_add_tabs (buf, tabs, is_top);
@@ -479,8 +481,7 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo

	HASH_ITER (hh, obj, cur, tmp) {
		ucl_add_tabs (buf, tabs + 1, is_top);
-
		keylen = strlen (cur->key);
-
		utstring_append_len (buf, cur->key, keylen);
+
		utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
		if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
			utstring_append_len (buf, " : ", 3);
		}
@@ -549,26 +550,26 @@ ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			utstring_printf (buf, "%ld", (long int)ucl_obj_toint (obj));
+
			utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
			break;
		case UCL_FLOAT:
		case UCL_TIME:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			ucl_print_float (buf, ucl_obj_todouble (obj));
+
			ucl_print_float (buf, ucl_object_todouble (obj));
			break;
		case UCL_BOOLEAN:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			utstring_printf (buf, "%s", ucl_obj_toboolean (obj) ? "true" : "false");
+
			utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
			break;
		case UCL_STRING:
			if (start_tabs) {
				ucl_add_tabs (buf, tabs, false);
			}
-
			ucl_elt_string_write_json (ucl_obj_tostring (obj), buf);
+
			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);
modified external/libucl/src/ucl_internal.h
@@ -48,6 +48,8 @@
 */

#define UCL_MAX_RECURSION 16
+
#define UCL_TRASH_KEY 0
+
#define UCL_TRASH_VALUE 1

enum ucl_parser_state {
	UCL_STATE_INIT = 0,
@@ -129,7 +131,7 @@ struct ucl_parser {
 * Unescape json string inplace
 * @param str
 */
-
void ucl_unescape_json_string (char *str);
+
size_t ucl_unescape_json_string (char *str, size_t len);

/**
 * Handle include macro
@@ -155,6 +157,10 @@ size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);

+

+
void ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
+
		bool start_tabs, bool compact);
+

#ifdef __GNUC__
static inline void
ucl_create_err (UT_string **err, const char *fmt, ...)
modified external/libucl/src/ucl_parser.c
@@ -233,6 +233,41 @@ ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
	return false;
}

+
static inline size_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, UT_string **err)
+
{
+
	size_t ret = 0;
+

+
	if (need_unescape || need_lowercase || !(parser->flags & UCL_FLAG_ZEROCOPY)) {
+
		/* Copy string */
+
		*dst = UCL_ALLOC (in_len + 1);
+
		if (*dst == NULL) {
+
			ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", err);
+
			return false;
+
		}
+
		if (need_lowercase) {
+
			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
+
		}
+
		else {
+
			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
+
		}
+

+
		if (need_unescape) {
+
			ret = ucl_unescape_json_string (*dst, ret);
+
		}
+
		*dst_const = *dst;
+
	}
+
	else {
+
		*dst_const = src;
+
		ret = in_len;
+
	}
+

+
	return ret;
+
}
+

/**
 * Parse possible number
 * @param parser
@@ -490,7 +525,7 @@ ucl_lex_json_string (struct ucl_parser *parser,
			}
			return false;
		}
-
		if (c == '\\') {
+
		else if (c == '\\') {
			ucl_chunk_skipc (chunk, p);
			c = *p;
			if (p >= chunk->end) {
@@ -530,6 +565,7 @@ ucl_lex_json_string (struct ucl_parser *parser,
		ucl_chunk_skipc (chunk, p);
	}

+
	ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", err);
	return false;
}

@@ -545,6 +581,7 @@ ucl_parse_key (struct ucl_parser *parser,
		struct ucl_chunk *chunk, UT_string **err)
{
	const unsigned char *p, *c = NULL, *end;
+
	const char *key;
	bool got_quote = false, got_eq = false, got_semicolon = false, need_unescape = false;
	ucl_object_t *nobj, *tobj, *container;
	size_t keylen;
@@ -663,28 +700,17 @@ ucl_parse_key (struct ucl_parser *parser,

	/* Create a new object */
	nobj = ucl_object_new ();
-
	keylen = end - c;
-
	nobj->key = malloc (keylen + 1);
-
	if (nobj->key == NULL) {
-
		ucl_set_err (chunk, 0, "cannot allocate memory for a key", err);
+
	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
+
			&key, end - c, need_unescape, parser->flags & UCL_FLAG_KEY_LOWERCASE, err);
+
	if (keylen == 0) {
		return false;
	}
-
	if (parser->flags & UCL_FLAG_KEY_LOWERCASE) {
-
		ucl_strlcpy_tolower (nobj->key, c, keylen + 1);
-
	}
-
	else {
-
		ucl_strlcpy_unsafe (nobj->key, c, keylen + 1);
-
	}
-

-
	if (need_unescape) {
-
		ucl_unescape_json_string (nobj->key);
-
	}

	container = parser->stack->obj->value.ov;
-
	HASH_FIND (hh, container, nobj->key, keylen, tobj);
+
	HASH_FIND (hh, container, key, keylen, tobj);
	if (tobj == NULL) {
		DL_APPEND (tobj, nobj);
-
		HASH_ADD_KEYPTR (hh, container, nobj->key, keylen, nobj);
+
		HASH_ADD_KEYPTR (hh, container, key, keylen, nobj);
	}
	else {
		DL_APPEND (tobj, nobj);
@@ -902,12 +928,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
			if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) {
				return false;
			}
-
			obj->value.sv = malloc (chunk->pos - c - 1);
-
			ucl_strlcpy_unsafe (obj->value.sv, c + 1, chunk->pos - c - 1);
-
			if (need_unescape) {
-
				ucl_unescape_json_string (obj->value.sv);
-
			}
+
			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, err)) == 0) {
+
				return false;
+
			}
+
			obj->len = str_len;
			parser->state = UCL_STATE_AFTER_VALUE;
			p = chunk->pos;
			return true;
@@ -960,13 +987,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
							ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", err);
							return false;
						}
-
						obj->value.sv = malloc (str_len);
-
						if (obj->value.sv == NULL) {
-
							ucl_set_err (chunk, 0, "cannot allocate memory for a string", err);
+
						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, err)) == 0) {
							return false;
						}
-
						ucl_strlcpy_unsafe (obj->value.sv, c, str_len);
-
						obj->type = UCL_STRING;
+
						obj->len = str_len;
						parser->state = UCL_STATE_AFTER_VALUE;
						return true;
					}
@@ -1002,18 +1028,17 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
								UCL_CHARACTER_WHITESPACE)) {
							stripped_spaces ++;
						}
-
						str_len = chunk->pos - c + 1 - stripped_spaces;
+
						str_len = chunk->pos - c - stripped_spaces;
						if (str_len <= 0) {
							ucl_set_err (chunk, 0, "string value must not be empty", err);
							return false;
						}
-
						obj->value.sv = malloc (str_len);
-
						if (obj->value.sv == NULL) {
-
							ucl_set_err (chunk, 0, "cannot allocate memory for a string", err);
+
						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, err)) == 0) {
							return false;
						}
-
						ucl_strlcpy_unsafe (obj->value.sv, c, str_len);
-
						obj->type = UCL_STRING;
+
						obj->len = str_len;
					}
					parser->state = UCL_STATE_AFTER_VALUE;
					return true;
@@ -1035,18 +1060,17 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string *
							UCL_CHARACTER_WHITESPACE)) {
						stripped_spaces ++;
					}
-
					str_len = chunk->pos - c + 1 - stripped_spaces;
+
					str_len = chunk->pos - c - stripped_spaces;
					if (str_len <= 0) {
						ucl_set_err (chunk, 0, "string value must not be empty", err);
						return false;
					}
-
					obj->value.sv = malloc (str_len);
-
					if (obj->value.sv == NULL) {
-
						ucl_set_err (chunk, 0, "cannot allocate memory for a string", err);
+
					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, err)) == 0) {
						return false;
					}
-
					ucl_strlcpy_unsafe (obj->value.sv, c, str_len);
-
					obj->type = UCL_STRING;
+
					obj->len = str_len;
				}
				parser->state = UCL_STATE_AFTER_VALUE;
				return true;
@@ -1366,6 +1390,8 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err)
			break;
		default:
			/* TODO: add all states */
+
			ucl_set_err (chunk, UCL_EMACRO, "internal error: parser is in an unknown state", err);
+
			parser->state = UCL_STATE_ERROR;
			return false;
		}
	}
modified external/libucl/src/ucl_util.c
@@ -23,6 +23,7 @@

#include "ucl.h"
#include "ucl_internal.h"
+
#include "ucl_chartable.h"

#ifdef HAVE_OPENSSL
#include <openssl/err.h>
@@ -39,30 +40,30 @@


static void
-
ucl_obj_free_internal (ucl_object_t *obj, bool allow_rec)
+
ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
{
	ucl_object_t *sub, *tmp;

	while (obj != NULL) {
-
		if (obj->key != NULL) {
-
			free (obj->key);
+
		if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
+
			UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
		}
-

-
		if (obj->type == UCL_STRING) {
-
			free (obj->value.sv);
+
		if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
+
			UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
		}
-
		else if (obj->type == UCL_ARRAY) {
+

+
		if (obj->type == UCL_ARRAY) {
			sub = obj->value.ov;
			while (sub != NULL) {
				tmp = sub->next;
-
				ucl_obj_free_internal (sub, false);
+
				ucl_object_free_internal (sub, false);
				sub = tmp;
			}
		}
		else if (obj->type == UCL_OBJECT) {
			HASH_ITER (hh, obj->value.ov, sub, tmp) {
				HASH_DELETE (hh, obj->value.ov, sub);
-
				ucl_obj_free_internal (sub, true);
+
				ucl_object_free_internal (sub, true);
			}
		}
		tmp = obj->next;
@@ -78,18 +79,18 @@ ucl_obj_free_internal (ucl_object_t *obj, bool allow_rec)
void
ucl_obj_free (ucl_object_t *obj)
{
-
	ucl_obj_free_internal (obj, true);
+
	ucl_object_free_internal (obj, true);
}

-
void
-
ucl_unescape_json_string (char *str)
+
size_t
+
ucl_unescape_json_string (char *str, size_t len)
{
	char *t = str, *h = str;
	int i, uval;

	/* t is target (tortoise), h is source (hare) */

-
	while (*h != '\0') {
+
	while (len) {
		if (*h == '\\') {
			h ++;
			switch (*h) {
@@ -130,6 +131,7 @@ ucl_unescape_json_string (char *str)
					}
				}
				h += 3;
+
				len -= 3;
				/* Encode */
				if(uval < 0x80) {
					t[0] = (char)uval;
@@ -162,19 +164,65 @@ ucl_unescape_json_string (char *str)
				break;
			}
			h ++;
+
			len --;
		}
		else {
			*t++ = *h++;
		}
+
		len --;
	}
	*t = '\0';
+

+
	return (t - str);
+
}
+

+
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) {
+
			memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->hh.key, obj->hh.keylen);
+
			obj->trash_stack[UCL_TRASH_KEY][obj->hh.keylen] = '\0';
+
		}
+
	}
+

+
	return obj->trash_stack[UCL_TRASH_KEY];
+
}
+

+
char *
+
ucl_copy_value_trash (ucl_object_t *obj)
+
{
+
	UT_string *emitted;
+
	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
+
		if (obj->type == UCL_STRING) {
+
			/* Special case for strings */
+
			obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
+
			if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
+
				memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
+
				obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
+
			}
+
		}
+
		else {
+
			/* Just emit value in json notation */
+
			utstring_new (emitted);
+

+
			if (emitted != NULL) {
+
				ucl_elt_write_json (obj, emitted, 0, 0, true);
+
				obj->trash_stack[UCL_TRASH_VALUE] = emitted->d;
+
				obj->len = emitted->i;
+
				free (emitted);
+
			}
+
		}
+
	}
+
	return obj->trash_stack[UCL_TRASH_VALUE];
}

ucl_object_t*
ucl_parser_get_object (struct ucl_parser *parser, UT_string **err)
{
	if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) {
-
		return ucl_obj_ref (parser->top_obj);
+
		return ucl_object_ref (parser->top_obj);
	}

	return NULL;
@@ -189,7 +237,7 @@ ucl_parser_free (struct ucl_parser *parser)
	struct ucl_pubkey *key, *ktmp;

	if (parser->top_obj != NULL) {
-
		ucl_obj_unref (parser->top_obj);
+
		ucl_object_unref (parser->top_obj);
	}

	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
@@ -672,5 +720,108 @@ ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
		*d = '\0';
	}

-
	return (s - src - 1);    /* count does not include NUL */
+
	return (s - src);    /* count does not include NUL */
+
}
+

+
ucl_object_t *
+
ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
+
{
+
	ucl_object_t *obj;
+
	const char *start, *end, *p;
+
	char *dst, *d;
+
	size_t escaped_len;
+

+
	if (str == NULL) {
+
		return NULL;
+
	}
+

+
	obj = ucl_object_new ();
+
	if (obj) {
+
		if (len == 0) {
+
			len = strlen (str);
+
		}
+
		if (flags & UCL_STRING_TRIM) {
+
			/* Skip leading spaces */
+
			for (start = str; (size_t)(start - str) < len; start ++) {
+
				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+
					break;
+
				}
+
			}
+
			/* Skip trailing spaces */
+
			for (end = str + len - 1; end > start; end --) {
+
				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+
					break;
+
				}
+
			}
+
			end ++;
+
		}
+
		else {
+
			start = str;
+
			end = str + len;
+
		}
+

+
		obj->type = UCL_STRING;
+
		if (flags & UCL_STRING_ESCAPE) {
+
			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
+
				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
+
					escaped_len ++;
+
				}
+
			}
+
			dst = malloc (escaped_len + 1);
+
			if (dst != NULL) {
+
				for (p = start, d = dst; p < end; p ++, d ++) {
+
					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
+
						switch (*p) {
+
						case '\n':
+
							*d++ = '\\';
+
							*d = 'n';
+
							break;
+
						case '\r':
+
							*d++ = '\\';
+
							*d = 'r';
+
							break;
+
						case '\b':
+
							*d++ = '\\';
+
							*d = 'b';
+
							break;
+
						case '\t':
+
							*d++ = '\\';
+
							*d = 't';
+
							break;
+
						case '\f':
+
							*d++ = '\\';
+
							*d = 'f';
+
							break;
+
						case '\\':
+
							*d++ = '\\';
+
							*d = '\\';
+
							break;
+
						case '"':
+
							*d++ = '\\';
+
							*d = '"';
+
							break;
+
						}
+
					}
+
					else {
+
						*d = *p;
+
					}
+
				}
+
				*d = '\0';
+
				obj->value.sv = dst;
+
				obj->trash_stack[UCL_TRASH_VALUE] = dst;
+
				obj->len = escaped_len;
+
			}
+
		}
+
		else {
+
			dst = malloc (end - start + 1);
+
			if (dst != NULL) {
+
				ucl_strlcpy_unsafe (dst, start, end - start + 1);
+
				obj->value.sv = dst;
+
				obj->trash_stack[UCL_TRASH_VALUE] = dst;
+
				obj->len = end - start;
+
			}
+
		}
+
	}
+

+
	return obj;
}
modified libpkg/pkg_config.c
@@ -370,7 +370,7 @@ obj_walk_object(ucl_object_t *obj, struct pkg_config *conf)
		if (sub->type != UCL_STRING)
			continue;
		kv = malloc(sizeof(struct pkg_config_kv));
-
		kv->key = strdup(sub->key);
+
		kv->key = strdup(ucl_object_key(sub));
		kv->value = strdup(ucl_obj_tostring(sub));
		HASH_ADD_STR(conf->kvlist, value, kv);
	}
@@ -382,11 +382,13 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
	ucl_object_t *sub, *tmp;
	struct sbuf *b = sbuf_new_auto();
	struct pkg_config *conf;
+
	const char *key;

	HASH_ITER(hh, obj, sub, tmp) {
		sbuf_clear(b);
-
		for (size_t i = 0; i < strlen(sub->key); i++)
-
			sbuf_putc(b, toupper(sub->key[i]));
+
		key = ucl_object_key(sub);
+
		for (size_t i = 0; i < strlen(key); i++)
+
			sbuf_putc(b, toupper(key[i]));
		sbuf_finish(b);

		HASH_FIND(hhkey, conf_by_key, sbuf_data(b), (size_t)sbuf_len(b), conf);
@@ -395,7 +397,7 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
			case PKG_CONFIG_STRING:
				if (sub->type != UCL_STRING) {
					pkg_emit_error("Expecting a string for key %s,"
-
					    " ignoring...", sub->key);
+
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv) {
@@ -406,7 +408,7 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
			case PKG_CONFIG_INTEGER:
				if (sub->type != UCL_INT) {
					pkg_emit_error("Expecting an integer for key %s,"
-
					    " ignoring...", sub->key);
+
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
@@ -415,7 +417,7 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
			case PKG_CONFIG_BOOL:
				if (sub->type != UCL_BOOLEAN) {
					pkg_emit_error("Expecting a boolean for key %s,"
-
					    " ignoring...", sub->key);
+
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
@@ -424,7 +426,7 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
			case PKG_CONFIG_LIST:
				if (sub->type != UCL_ARRAY) {
					pkg_emit_error("Expecting a list for key %s,"
-
					    " ignoring...", sub->key);
+
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
@@ -433,7 +435,7 @@ pkg_object_walk(ucl_object_t *obj, struct pkg_config *conf_by_key)
			case PKG_CONFIG_KVLIST:
				if (sub->type != UCL_OBJECT) {
					pkg_emit_error("Expecting a mapping for key %s,"
-
					    " ignoring...", sub->key);
+
					    " ignoring...", key);
					continue;
				}
				if (!conf->fromenv)
@@ -683,53 +685,55 @@ add_repo(ucl_object_t *obj, struct pkg_repo *r, const char *rname)
	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) {
-
		if (strcasecmp(sub->key, "url") == 0) {
+
		key = ucl_object_key(sub);
+
		if (strcasecmp(key, "url") == 0) {
			if (sub->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			url = ucl_obj_tostring(sub);
-
		} else if (strcasecmp(sub->key, "pubkey") == 0) {
+
		} else if (strcasecmp(key, "pubkey") == 0) {
			if (sub->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			pubkey = ucl_obj_tostring(sub);
-
		} else if (strcasecmp(sub->key, "enabled") == 0) {
+
		} else if (strcasecmp(key, "enabled") == 0) {
			if (sub->type != UCL_BOOLEAN) {
				pkg_emit_error("Expecting a boolean for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			enable = ucl_obj_toboolean(sub);
-
		} else if (strcasecmp(sub->key, "mirror_type") == 0) {
+
		} else if (strcasecmp(key, "mirror_type") == 0) {
			if (sub->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			mirror_type = ucl_obj_tostring(sub);
-
		} else if (strcasecmp(sub->key, "signature_type") == 0) {
+
		} else if (strcasecmp(key, "signature_type") == 0) {
			if (sub->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			signature_type = ucl_obj_tostring(sub);
-
		} else if (strcasecmp(sub->key, "fingerprints") == 0) {
+
		} else if (strcasecmp(key, "fingerprints") == 0) {
			if (sub->type != UCL_STRING) {
				pkg_emit_error("Expecting a string for the "
				    "'%s' key of the '%s' repo",
-
				    sub->key, rname);
+
				    key, rname);
				return;
			}
			fingerprints = ucl_obj_tostring(sub);
@@ -786,12 +790,14 @@ walk_repo_obj(ucl_object_t *obj)
{
	ucl_object_t *sub, *tmp;
	struct pkg_repo *r;
+
	const char *key;

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

@@ -1080,13 +1086,14 @@ pkg_init(const char *path, const char *reposdir)
		obj = ucl_parser_get_object(p, &err);
		if (obj->type == UCL_OBJECT) {
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				if (strcasecmp(sub->key, "REPOS_DIR") == 0 &&
+
				key = ucl_object_key(sub);
+
				if (strcasecmp(key, "REPOS_DIR") == 0 &&
				    sub->type != UCL_ARRAY)
					fallback = true;
-
				else if (strcasecmp(sub->key, "PKG_ENV") == 0 &&
+
				else if (strcasecmp(key, "PKG_ENV") == 0 &&
				    sub->type != UCL_OBJECT)
					fallback = true;
-
				else if (strcasecmp(sub->key, "ALIAS") == 0 &&
+
				else if (strcasecmp(key, "ALIAS") == 0 &&
				    sub->type != UCL_OBJECT)
					fallback = true;
				if (fallback)
modified libpkg/pkg_manifest.c
@@ -263,29 +263,30 @@ static int
pkg_string(struct pkg *pkg, ucl_object_t *obj, int attr)
{
	int ret = EPKG_OK;
+
	const char *str;
+
	str = ucl_object_tostring(obj);

	switch (attr)
	{
	case PKG_INFOS:
-
		pkg_addannotation(pkg, "_INFOS_", obj->value.sv);
+
		pkg_addannotation(pkg, "_INFOS_", str);
		break;
	case PKG_LICENSE_LOGIC:
-
		if (!strcmp(obj->value.sv, "single"))
+
		if (!strcmp(str, "single"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE);
-
		else if (!strcmp(obj->value.sv, "or") ||
-
		         !strcmp(obj->value.sv, "dual"))
+
		else if (!strcmp(str, "or") ||
+
		         !strcmp(str, "dual"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR);
-
		else if (!strcmp(obj->value.sv, "and") ||
-
		         !strcmp(obj->value.sv, "multi"))
+
		else if (!strcmp(str, "and") ||
+
		         !strcmp(str, "multi"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND);
		else {
-
			pkg_emit_error("Unknown license logic: %s",
-
			    obj->value.sv);
+
			pkg_emit_error("Unknown license logic: %s", str);
			ret = EPKG_FATAL;
		}
		break;
	default:
-
		ret = urldecode(obj->value.sv, &pkg->fields[attr]);
+
		ret = urldecode(str, &pkg->fields[attr]);
		break;
	}

@@ -297,10 +298,10 @@ pkg_int(struct pkg *pkg, ucl_object_t *obj, int attr)
{
	char vint[BUFSIZ];
	if (attr == PKG_VERSION) {
-
		snprintf(vint, sizeof(vint), "%"PRId64, obj->value.iv);
+
		snprintf(vint, sizeof(vint), "%"PRId64, ucl_object_toint(obj));
		pkg_set(pkg, attr, vint);
	}
-
	return (pkg_set(pkg, attr, obj->value.iv));
+
	return (pkg_set(pkg, attr, ucl_object_toint(obj)));
}

static int
@@ -316,17 +317,17 @@ pkg_array(struct pkg *pkg, ucl_object_t *obj, int attr)
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed category");
			else
-
				pkg_addcategory(pkg, sub->value.sv);
+
				pkg_addcategory(pkg, ucl_object_tostring(sub));
			break;
		case PKG_LICENSES:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed license");
			else
-
				pkg_addlicense(pkg, sub->value.sv);
+
				pkg_addlicense(pkg, ucl_object_tostring(sub));
			break;
		case PKG_USERS:
			if (sub->type == UCL_STRING)
-
				pkg_adduser(pkg, sub->value.sv);
+
				pkg_adduser(pkg, ucl_object_tostring(sub));
			else if (sub->type == UCL_OBJECT)
				pkg_object(pkg, sub, attr);
			else
@@ -334,7 +335,7 @@ pkg_array(struct pkg *pkg, ucl_object_t *obj, int attr)
			break;
		case PKG_GROUPS:
			if (sub->type == UCL_STRING)
-
				pkg_addgroup(pkg, sub->value.sv);
+
				pkg_addgroup(pkg, ucl_object_tostring(sub));
			else if (sub->type == UCL_OBJECT)
				pkg_object(pkg, sub, attr);
			else
@@ -342,7 +343,7 @@ pkg_array(struct pkg *pkg, ucl_object_t *obj, int attr)
			break;
		case PKG_DIRS:
			if (sub->type == UCL_STRING)
-
				pkg_adddir(pkg, sub->value.sv, 1, false);
+
				pkg_adddir(pkg, ucl_object_tostring(sub), 1, false);
			else if (sub->type == UCL_OBJECT)
				pkg_object(pkg, sub, attr);
			else
@@ -352,13 +353,13 @@ pkg_array(struct pkg *pkg, ucl_object_t *obj, int attr)
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed required shared library");
			else
-
				pkg_addshlib_required(pkg, sub->value.sv);
+
				pkg_addshlib_required(pkg, ucl_object_tostring(sub));
			break;
		case PKG_SHLIBS_PROVIDED:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed provided shared library");
			else
-
				pkg_addshlib_provided(pkg, sub->value.sv);
+
				pkg_addshlib_provided(pkg, ucl_object_tostring(sub));
			break;
		}
		sub = sub->next;
@@ -373,113 +374,114 @@ pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
	struct sbuf *tmp = NULL;
	ucl_object_t *sub, *otmp;
	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);
		switch (attr) {
		case PKG_DEPS:
			if (sub->type != UCL_OBJECT)
				pkg_emit_error("Skipping malformed dependency %s",
-
				    sub->key);
+
				    key);
			else
				pkg_set_deps_from_object(pkg, sub);
			break;
		case PKG_DIRS:
			if (sub->type != UCL_OBJECT)
				pkg_emit_error("Skipping malformed dirs %s",
-
				    sub->key);
+
				    key);
			else
				pkg_set_dirs_from_object(pkg, sub);
			break;
		case PKG_USERS:
			if (sub->type == UCL_STRING)
-
				pkg_adduid(pkg, sub->key, sub->value.sv);
+
				pkg_adduid(pkg, key, ucl_object_tostring(sub));
			else
				pkg_emit_error("Skipping malformed users %s",
-
				    sub->key);
+
				    key);
			break;
		case PKG_GROUPS:
			if (sub->type == UCL_STRING)
-
				pkg_addgid(pkg, sub->key, sub->value.sv);
+
				pkg_addgid(pkg, key, ucl_object_tostring(sub));
			else
				pkg_emit_error("Skipping malformed groups %s",
-
				    sub->key);
+
				    key);
			break;
		case PKG_DIRECTORIES:
			if (sub->type == UCL_BOOLEAN) {
-
				urldecode(sub->key, &tmp);
-
				pkg_adddir(pkg, sbuf_get(tmp), sub->value.iv, false);
+
				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) {
-
				urldecode(sub->key, &tmp);
-
				if (sub->value.sv[0] == 'y')
-
					pkg_adddir(pkg, sbuf_get(tmp), 1, false);
+
				urldecode(key, &tmp);
+
				if (ucl_object_tostring(sub)[0] == 'y')
+
					pkg_adddir(pkg, sbuf_data(tmp), 1, false);
				else
-
					pkg_adddir(pkg, sbuf_get(tmp), 0, false);
+
					pkg_adddir(pkg, sbuf_data(tmp), 0, false);
			} else {
				pkg_emit_error("Skipping malformed directories %s",
-
				    sub->key);
+
				    key);
			}
			break;
		case PKG_FILES:
			if (sub->type == UCL_STRING) {
-
				const char *pkg_sum = NULL;
-
				if (strlen(sub->value.sv) == 64)
-
					pkg_sum = sub->value.sv;
-
				urldecode(sub->key, &tmp);
-
				pkg_addfile(pkg, sbuf_get(tmp), pkg_sum, false);
+
				buf = ucl_object_tolstring(sub, &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
				pkg_emit_error("Skipping malformed files %s",
-
				    sub->key);
+
				   key);
			break;
		case PKG_OPTIONS:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option %s",
-
				    sub->key);
+
				    key);
			else
-
				pkg_addoption(pkg, sub->key, sub->value.sv);
+
				pkg_addoption(pkg, key, ucl_object_tostring(sub));
			break;
		case PKG_OPTION_DEFAULTS:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option default %s",
-
				    sub->key);
+
				    key);
			else
-
				pkg_addoption_default(pkg, sub->key,
-
				    sub->value.sv);
+
				pkg_addoption_default(pkg, key,
+
				    ucl_object_tostring(sub));
			break;
		case PKG_OPTION_DESCRIPTIONS:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option description %s",
-
				    sub->key);
+
				    key);
			else
-
				pkg_addoption_description(pkg, sub->key,
-
				    sub->value.sv);
+
				pkg_addoption_description(pkg, key,
+
				    ucl_object_tostring(sub));
			break;
		case PKG_SCRIPTS:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed scripts %s",
-
				    sub->key);
+
				    key);
			else {
-
				script_type = script_type_str(sub->key);
+
				script_type = script_type_str(key);
				if (script_type == PKG_SCRIPT_UNKNOWN) {
					pkg_emit_error("Skipping unknown script "
-
					    "type: %s", sub->key);
+
					    "type: %s", key);
					break;
				}

-
				urldecode(sub->value.sv, &tmp);
-
				pkg_addscript(pkg, sbuf_get(tmp), script_type);
+
				urldecode(ucl_object_tostring(sub), &tmp);
+
				pkg_addscript(pkg, sbuf_data(tmp), script_type);
			}
			break;
		case PKG_ANNOTATIONS:
			if (sub->type != UCL_STRING)
				pkg_emit_error("Skipping malformed annotation %s",
-
				    sub->key);
+
				    key);
			else
-
				pkg_addannotation(pkg, sub->key, sub->value.sv);
+
				pkg_addannotation(pkg, key, ucl_object_tostring(sub));
			break;
		}
	}
@@ -499,25 +501,27 @@ pkg_set_files_from_object(struct pkg *pkg, ucl_object_t *obj)
	void *set = NULL;
	mode_t perm = 0;
	struct sbuf *fname = NULL;
+
	const char *key;

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

@@ -537,24 +541,26 @@ pkg_set_dirs_from_object(struct pkg *pkg, ucl_object_t *obj)
	mode_t perm = 0;
	bool try = false;
	struct sbuf *dirname = NULL;
+
	const char *key;

-
	urldecode(obj->key, &dirname);
+
	urldecode(ucl_object_key(obj), &dirname);
	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		if (!strcasecmp(sub->key, "uname") && sub->type == UCL_STRING)
-
			uname = sub->value.sv;
-
		else if (!strcasecmp(sub->key, "gname") && sub->type == UCL_STRING)
-
			gname = sub->value.sv;
-
		else if (!strcasecmp(sub->key, "perm") && sub->type == UCL_STRING) {
-
			if ((set = setmode(sub->value.sv)) == NULL)
+
		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)
				pkg_emit_error("Not a valid mode: %s",
-
				    sub->value.sv);
+
				    ucl_object_tostring(sub));
			else
				perm = getmode(set, 0);
-
		} else if (!strcasecmp(sub->key, "try") && sub->type == UCL_BOOLEAN) {
-
				try = sub->value.iv;
+
		} else if (!strcasecmp(key, "try") && sub->type == UCL_BOOLEAN) {
+
				try = ucl_object_toint(sub);
		} else {
			pkg_emit_error("Skipping unknown key for dir(%s): %s",
-
			    sbuf_data(dirname), sub->key);
+
			    sbuf_data(dirname), key);
		}
	}

@@ -570,32 +576,34 @@ pkg_set_deps_from_object(struct pkg *pkg, ucl_object_t *obj)
	ucl_object_t *sub, *tmp;
	const char *origin = NULL;
	const char *version = NULL;
+
	const char *key;
	int64_t vint = 0;
	char vinteger[BUFSIZ];

-
	pkg_debug(2, "Found %s", obj->key);
+
	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) {
			/* accept version to be an integer */
-
			if (sub->type == UCL_INT && strcasecmp(sub->key, "version") == 0) {
-
				vint = sub->value.iv;
+
			if (sub->type == UCL_INT && strcasecmp(key, "version") == 0) {
+
				vint = ucl_object_toint(sub);
				snprintf(vinteger, sizeof(vinteger), "%"PRId64, vint);
				continue;
			}

			pkg_emit_error("Skipping malformed dependency entry "
-
			    "for %s", obj->key);
+
			    "for %s", ucl_object_key(obj));
			continue;
		}
-
		if (strcasecmp(sub->key, "origin") == 0)
-
			origin = sub->value.sv;
-
		if (strcasecmp(sub->key, "version") == 0)
-
			version = sub->value.sv;
+
		if (strcasecmp(key, "origin") == 0)
+
			origin = ucl_object_tostring(sub);
+
		if (strcasecmp(key, "version") == 0)
+
			version = ucl_object_tostring(sub);
	}
	if (origin != NULL && (version != NULL || vint > 0))
-
		pkg_adddep(pkg, obj->key, origin, vint > 0 ? vinteger : version, false);
+
		pkg_adddep(pkg, ucl_object_key(obj), origin, vint > 0 ? vinteger : version, false);
	else
-
		pkg_emit_error("Skipping malformed dependency %s", obj->key);
+
		pkg_emit_error("Skipping malformed dependency %s", ucl_object_key(obj));

	return (EPKG_OK);
}
@@ -608,8 +616,8 @@ parse_manifest(struct pkg *pkg, struct pkg_manifest_key *keys, ucl_object_t *obj
	struct dataparser *dp;

	HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
		pkg_debug(2, "Manifest: found key: '%s'", sub->key);
-
		HASH_FIND_STR(keys, sub->key, selected_key);
+
		pkg_debug(2, "Manifest: found key: '%s'", ucl_object_key(sub));
+
		HASH_FIND_STR(keys, __DECONST(char *, ucl_object_key(sub)), selected_key);
		if (selected_key != NULL) {
			HASH_FIND_UCLT(selected_key->parser, &sub->type, dp);
			if (dp != NULL) {
@@ -646,7 +654,7 @@ pkg_parse_manifest(struct pkg *pkg, char *buf, size_t len, struct pkg_manifest_k
		obj = ucl_parser_get_object(p, &error);
		if (obj != NULL) {
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				HASH_FIND_STR(keys, sub->key, sk);
+
				HASH_FIND_STR(keys, __DECONST(char *, ucl_object_key(obj)), sk);
				if (sk != NULL) {
					HASH_FIND_UCLT(sk->parser, &sub->type, dp);
					if (dp == NULL) {
@@ -711,7 +719,7 @@ pkg_parse_manifest_file(struct pkg *pkg, const char *file, struct pkg_manifest_k
		obj = ucl_parser_get_object(p, &error);
		if (obj != NULL) {
			HASH_ITER(hh, obj->value.ov, sub, tmp) {
-
				HASH_FIND_STR(keys, sub->key, sk);
+
				HASH_FIND_STR(keys, ucl_object_key(sub), sk);
				if (sk != NULL) {
					HASH_FIND_UCLT(sk->parser, &sub->type, dp);
					if (dp == NULL) {
@@ -746,74 +754,26 @@ pkg_parse_manifest_file(struct pkg *pkg, const char *file, struct pkg_manifest_k
	return (rc);
}

-
#define obj_append_kv(o, k, v) do {        \
-
	sub = ucl_object_new();                     \
-
	sub->key = strdup(k);                  \
-
	sub->type = UCL_STRING;                  \
-
	sub->value.sv = strdup(v);           \
-
	HASH_ADD_KEYPTR(hh, o->value.ov, sub->key, strlen(sub->key), sub); \
-
} while (0)
-

-
#define obj_append_boolean(o, k, v) do {       \
-
	sub = ucl_object_new();                     \
-
	sub->key = strdup(k);                  \
-
	sub->type = UCL_BOOLEAN;                     \
-
	sub->value.iv = v;                   \
-
	HASH_ADD_KEYPTR(hh, o->value.ov, sub->key, strlen(sub->key), sub); \
-
} while (0);
-

-
#define obj_append_int(o, k, v) do {       \
-
	sub = ucl_object_new();                     \
-
	sub->key = strdup(k);                  \
-
	sub->type = UCL_INT;                     \
-
	sub->value.iv = v;                   \
-
	HASH_ADD_KEYPTR(hh, o->value.ov, sub->key, strlen(sub->key), sub); \
-
} while (0);
-

-
#define obj_append_map(o, k, m) do {              \
-
	m = ucl_object_new();                     \
-
	m->key = strdup(k);                  \
-
	m->type = UCL_OBJECT;                  \
-
	HASH_ADD_KEYPTR(hh, o->value.ov, m->key, strlen(m->key), m); \
-
} while (0);
-

-
#define obj_append_seq(o, k, s) do {              \
-
	s = ucl_object_new();                     \
-
	s->key = strdup(k);                  \
-
	s->type = UCL_ARRAY;                  \
-
	HASH_ADD_KEYPTR(hh, o->value.ov, s->key, strlen(s->key), s); \
-
} while (0);
-

-
#define seq_append_val(o, v) do {             \
-
	sub = ucl_object_new();                      \
-
	sub->type = UCL_STRING;                   \
-
	sub->value.sv = strdup(v);            \
-
	LL_PREPEND(o->value.ov, sub);             \
-
} while (0);
-

int
pkg_emit_filelist(struct pkg *pkg, FILE *f)
{
-
	ucl_object_t *obj, *sub, *seq;
+
	ucl_object_t *obj = NULL, *seq;
	struct pkg_file *file = NULL;
	char *output;
	const char *name, *origin, *version;
	struct sbuf *b = NULL;

-
	obj = ucl_object_new();
-

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

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

	output = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
	fprintf(f, "%s", output);
@@ -822,6 +782,8 @@ pkg_emit_filelist(struct pkg *pkg, FILE *f)
	if (b != NULL)
		sbuf_delete(b);

+
	ucl_object_free(obj);
+

	return (EPKG_OK);
}

@@ -846,10 +808,7 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
	const char *script_types = NULL;
	lic_t licenselogic;
	int64_t flatsize, pkgsize;
-
	ucl_object_t *obj, *sub, *map, *seq, *submap;
-

-
	obj = ucl_object_new();
-
	obj->type = UCL_OBJECT;
+
	ucl_object_t *obj = NULL, *map, *seq, *submap;

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

-
	obj_append_kv(obj, "name", name);
-
	obj_append_kv(obj, "version", version);
-
	obj_append_kv(obj, "origin", pkgorigin);
-
	obj_append_kv(obj, "comment", comment);
-
	obj_append_kv(obj, "arch", pkgarch);
-
	obj_append_kv(obj, "maintainer", pkgmaintainer);
-
	obj_append_kv(obj, "prefix", prefix);
-
	obj_append_kv(obj, "www", www);
-
	if (repopath != NULL)
-
		obj_append_kv(obj, "path", repopath);
-
	if (pkgsum != NULL)
-
		obj_append_kv(obj, "sum", pkgsum);
+
	obj = ucl_object_insert_key(obj, ucl_object_fromstring(name), "name", 4);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgorigin), "origin", 6);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(version), "version", 7);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(comment), "comment", 7);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgarch), "arch", 4);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgmaintainer), "maintainer", 10);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(prefix), "prefix", 6);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(www), "www", 3);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(repopath), "path", 4);
+
	ucl_object_insert_key(obj, ucl_object_fromstring(pkgsum), "sum", 3);

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

	seq = NULL;
-
	while (pkg_licenses(pkg, &license) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "licenses", seq);
-
		seq_append_val(seq, pkg_license_name(license));
-
	}
+
	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);

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

	urlencode(desc, &tmpsbuf);
-
	obj_append_kv(obj, "desc", sbuf_get(tmpsbuf));
+
	ucl_object_insert_key(obj, ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)), "desc", 4);

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

	seq = NULL;
-
	while (pkg_categories(pkg, &category) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "categories", seq);
-
		seq_append_val(seq, pkg_category_name(category));
-
	}
+
	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);

	seq = NULL;
-
	while (pkg_users(pkg, &user) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "users", seq);
-
		seq_append_val(seq, pkg_user_name(user));
-
	}
+
	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);

	seq = NULL;
-
	while (pkg_groups(pkg, &group) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "groups", seq);
-
		seq_append_val(seq, pkg_group_name(group));
-
	}
+
	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);

	seq = NULL;
-
	while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "shlibs_required", seq);
-
		seq_append_val(seq, pkg_shlib_name(shlib));
-
	}
+
	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);

	seq = NULL;
-
	while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK) {
-
		if (seq == NULL)
-
			obj_append_seq(obj, "shlibs_provided", seq);
-
		seq_append_val(seq, pkg_shlib_name(shlib));
-
	}
+
	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);

	map = NULL;
	while (pkg_options(pkg, &option) == EPKG_OK) {
-
		if (map == NULL)
-
			obj_append_map(obj, "options", map);
-
		obj_append_kv(map, pkg_option_opt(option),
-
		    pkg_option_value(option));
+
		map = ucl_object_insert_key(map,
+
		    ucl_object_fromstring(pkg_option_value(option)),
+
		    pkg_option_opt(option), 0);
	}
+
	ucl_object_insert_key(obj, map, "options", 7);

	map = NULL;
	while (pkg_annotations(pkg, &note) == EPKG_OK) {
-
		if (map == NULL)
-
			obj_append_map(obj, "annotations", map);
-
		obj_append_kv(map, pkg_annotation_tag(note),
-
		    pkg_annotation_value(note));
+
		map = ucl_object_insert_key(map,
+
		    ucl_object_fromstring(pkg_annotation_value(note)),
+
		    pkg_annotation_tag(note), 0);
	}
+
	ucl_object_insert_key(obj, map, "annotations", 11);

	if ((flags & PKG_MANIFEST_EMIT_COMPACT) == 0) {
		if ((flags & PKG_MANIFEST_EMIT_NOFILES) == 0) {
@@ -967,30 +912,28 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
				if (pkg_sum == NULL || pkg_sum[0] == '\0')
					pkg_sum = "-";

-
				if (map == NULL)
-
					obj_append_map(obj, "files", map);
				urlencode(pkg_file_path(file), &tmpsbuf);
-
				obj_append_kv(map, sbuf_get(tmpsbuf), pkg_sum);
+
				map = ucl_object_insert_key(map,
+
				    ucl_object_fromstring(pkg_sum),
+
				    strdup(sbuf_data(tmpsbuf)), sbuf_len(tmpsbuf));
			}
+
			ucl_object_insert_key(obj, map, "files", 5);

-
			seq = NULL;
			map = NULL;
			while (pkg_dirs(pkg, &dir) == EPKG_OK) {
-
				if (map == NULL)
-
					obj_append_map(obj, "directories", map);
				urlencode(pkg_dir_path(dir), &tmpsbuf);
				/* For now append y/n to stay compatible with libyaml version 
				 * obj_append_boolean(map, sbuf_get(tmpsbuf), pkg_dir_try(dir));
				 */
-
				obj_append_kv(map, sbuf_get(tmpsbuf), pkg_dir_try(dir) ? "y" : "n");
+
				map = ucl_object_insert_key(map,
+
				    ucl_object_fromstring(pkg_dir_try(dir) ? "y" : "n"),
+
				    strdup(sbuf_data(tmpsbuf)), sbuf_len(tmpsbuf));
			}
+
			ucl_object_insert_key(obj, map, "directories", 11);
		}

		map = NULL;
		for (i = 0; i < PKG_NUM_SCRIPTS; i++) {
-
			if (map == NULL)
-
				obj_append_map(obj, "scripts", map);
-

			if (pkg_script_get(pkg, i) == NULL)
				continue;

@@ -1024,13 +967,18 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
				break;
			}
			urlencode(pkg_script_get(pkg, i), &tmpsbuf);
-
			obj_append_kv(map, script_types, sbuf_get(tmpsbuf));
+
			map = ucl_object_insert_key(map,
+
			    ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)),
+
			    script_types, 0);
		}
+
		ucl_object_insert_key(obj, map, "scripts", 7);
	}

	if (message != NULL && *message != '\0') {
		urlencode(message, &tmpsbuf);
-
		obj_append_kv(obj, "message", sbuf_get(tmpsbuf));
+
		ucl_object_insert_key(obj,
+
		    ucl_object_fromlstring(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf)),
+
		    "message", 7);
	}

	if ((flags & PKG_MANIFEST_EMIT_PRETTY) == PKG_MANIFEST_EMIT_PRETTY)
@@ -1038,6 +986,8 @@ emit_manifest(struct pkg *pkg, char **out, short flags)
	else
		*out = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);

+
	ucl_object_free(obj);
+

	return (EPKG_OK);
}

modified libpkg/pkg_ports.c
@@ -662,26 +662,28 @@ 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;
+
	const char *key;

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

	HASH_ITER(hh, o, sub, tmp) {
-
		if (!strcasecmp(sub->key, "owner") && sub->type == UCL_STRING) {
+
		key = ucl_object_key(sub);
+
		if (!strcasecmp(key, "owner") && sub->type == UCL_STRING) {
			free((*a)->owner);
-
			(*a)->owner = strdup(sub->value.sv);
+
			(*a)->owner = strdup(ucl_object_tostring(sub));
			continue;
		}
-
		if (!strcasecmp(sub->key, "group") && sub->type == UCL_STRING) {
+
		if (!strcasecmp(key, "group") && sub->type == UCL_STRING) {
			free((*a)->group);
-
			(*a)->group = strdup(sub->value.sv);
+
			(*a)->group = strdup(ucl_object_tostring(sub));
			continue;
		}
-
		if (!strcasecmp(sub->key, "mode")) {
+
		if (!strcasecmp(key, "mode")) {
			if (sub->type == UCL_STRING) {
				void *set;
-
				if ((set = setmode(sub->value.sv)) == NULL)
-
					pkg_emit_error("Bad format for the mode attribute: %s", sub->value.sv);
+
				if ((set = setmode(ucl_object_tostring(sub))) == NULL)
+
					pkg_emit_error("Bad format for the mode attribute: %s", ucl_object_tostring(sub));
				else
					(*a)->mode = getmode(set, 0);
				free(set);
@@ -698,54 +700,56 @@ parse_and_apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, str
{
	ucl_object_t *sub, *tmp, *actions;
	char *cmd;
+
	const char *key;

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

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

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

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

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

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

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

-
		if (!strcasecmp(sub->key, "post-upgrade") && sub->type == UCL_STRING) {
-
			format_exec_cmd(&cmd, sub->value.sv, p->prefix, p->last_file, line);
+
		if (!strcasecmp(key, "post-upgrade") && sub->type == UCL_STRING) {
+
			format_exec_cmd(&cmd, ucl_object_tostring(sub), p->prefix, p->last_file, line);
			sbuf_cat(p->post_upgrade_buf, cmd);
			free(cmd);
			continue;
modified libpkg/update.c
@@ -151,19 +151,21 @@ parse_fingerprint(ucl_object_t *obj)
	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)
			continue;

-
		if (strcasecmp(sub->key, "function") == 0) {
-
			function = sub->value.sv;
+
		if (strcasecmp(key, "function") == 0) {
+
			function = ucl_object_tostring(sub);
			continue;
		}

-
		if (strcasecmp(sub->key, "fingerprint") == 0) {
-
			fp = sub->value.sv;
+
		if (strcasecmp(key, "fingerprint") == 0) {
+
			fp = ucl_object_tostring(sub);
			continue;
		}
	}
@@ -738,7 +740,7 @@ pkg_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime)
	pkg_emit_incremental_update(updated, removed, added, processed);

cleanup:
-
	if (pkg != NULL)
+
/*	if (pkg != NULL)
		pkg_free(pkg);
	if (it != NULL)
		pkgdb_it_free(it);
@@ -748,7 +750,7 @@ cleanup:
		fclose(fdigests);
	if (map != MAP_FAILED)
		munmap(map, len);
-

+
*/
	return (rc);
}

modified libpkg/utils.c
@@ -479,7 +479,7 @@ is_valid_abi(const char *arch, bool emit_error) {
static void yaml_mapping_to_object(ucl_object_t *obj, yaml_document_t *doc, yaml_node_t *node);

static void
-
yaml_sequence_to_object(ucl_object_t *obj, yaml_document_t *doc, yaml_node_t *node)
+
yaml_sequence_to_object(ucl_object_t **obj, yaml_document_t *doc, yaml_node_t *node)
{
	yaml_node_item_t *item;
	yaml_node_t *val;
@@ -488,88 +488,28 @@ yaml_sequence_to_object(ucl_object_t *obj, yaml_document_t *doc, yaml_node_t *no
	item = node->data.sequence.items.start;
	while (item < node->data.sequence.items.top) {
		val = yaml_document_get_node(doc, *item);
-
		sub = ucl_object_new();
		switch (val->type) {
		case YAML_MAPPING_NODE:
-
			sub->type = UCL_OBJECT;
+
			sub = ucl_object_new();
			yaml_mapping_to_object(sub, doc, val);
			break;
		case YAML_SEQUENCE_NODE:
-
			sub->type = UCL_ARRAY;
-
			yaml_sequence_to_object(sub, doc, val);
+
			sub = NULL;
+
			yaml_sequence_to_object(&sub, doc, val);
			break;
		case YAML_SCALAR_NODE:
-
			sub->type = UCL_STRING;
-
			sub->value.sv = strdup(val->data.scalar.value);
+
			sub = ucl_object_fromstring_common (val->data.scalar.value,
+
			    val->data.scalar.length, UCL_STRING_TRIM);
			break;
		case YAML_NO_NODE:
			/* Should not happen */
			break;
		}
-
		DL_APPEND(obj->value.ov, sub);
+
		*obj = ucl_array_append(*obj, sub);
		++item;
	}
}

-
static bool
-
maybe_boolean(ucl_object_t *obj, yaml_node_t *node)
-
{
-
	const char *p = node->data.scalar.value;
-
	bool ret = false;
-
	bool val = false;
-

-
	if (node->data.scalar.length == 5) {
-
		if (tolower(p[0]) == 'f' && strncasecmp(p, "false", 5) == 0) {
-
			ret = true;
-
			val = false;
-
		}
-
	} else if (node->data.scalar.length == 4) {
-
		if (tolower(p[0]) == 't' && strncasecmp(p, "true", 4) == 0) {
-
			ret = true;
-
			val = true;
-
		}
-
	} else if (node->data.scalar.length == 3) {
-
		if (tolower(p[0]) == 'y' && strncasecmp(p, "yes", 3) == 0) {
-
			ret = true;
-
			val = true;
-
		} else if (tolower(p[0]) == 'o' && strncasecmp(p, "off", 3) == 0) {
-
			ret = true;
-
			val = false;
-
		}
-
	} else if (node->data.scalar.length == 2) {
-
		if (tolower(p[0]) == 'n' && strncasecmp(p, "no", 2) == 0) {
-
			ret = true;
-
			val = false;
-
		} else if (tolower(p[0]) == 'o' && strncasecmp(p, "on", 2) == 0) {
-
			ret = true;
-
			val = true;
-
		}
-
	}
-

-
	if (ret) {
-
		obj->type = UCL_BOOLEAN;
-
		obj->value.iv = val;
-
	}
-

-
	return (ret);
-
}
-

-
static bool
-
maybe_integer(ucl_object_t *obj, yaml_node_t *node)
-
{
-
	int64_t val;
-
	const char *errstr;
-

-
	val = strtonum(node->data.scalar.value, 0, INT64_MAX, &errstr);
-
	if (errstr)
-
		return (false);
-
	
-
	obj->type = UCL_INT;
-
	obj->value.iv = val;
-

-
	return (true);
-
}
-

static void
yaml_mapping_to_object(ucl_object_t *obj, yaml_document_t *doc, yaml_node_t *node)
{
@@ -583,32 +523,24 @@ yaml_mapping_to_object(ucl_object_t *obj, yaml_document_t *doc, yaml_node_t *nod
		key = yaml_document_get_node(doc, pair->key);
		val = yaml_document_get_node(doc, pair->value);

-
		sub = ucl_object_new();
-
		sub->key = strdup(key->data.scalar.value);
		switch (val->type) {
		case YAML_MAPPING_NODE:
-
			sub->type = UCL_OBJECT;
+
			sub = ucl_object_new();
			yaml_mapping_to_object(sub, doc, val);
			break;
		case YAML_SEQUENCE_NODE:
-
			sub->type = UCL_ARRAY;
-
			yaml_sequence_to_object(sub, doc, val);
+
			sub = NULL;
+
			yaml_sequence_to_object(&sub, doc, val);
			break;
		case YAML_SCALAR_NODE:
-
			if (maybe_boolean(sub, val))
-
				break;
-
			if (maybe_integer(sub, val))
-
				break;
-
			sub->type = UCL_STRING;
-
			while (val->data.scalar.value[strlen(val->data.scalar.value) - 1] == '\n')
-
				val->data.scalar.value[strlen(val->data.scalar.value) -1 ] = '\0';
-
			sub->value.sv = strdup(val->data.scalar.value);
+
			sub = ucl_object_fromstring_common (val->data.scalar.value,
+
			    val->data.scalar.length, UCL_STRING_TRIM);
			break;
		case YAML_NO_NODE:
			/* Should not happen */
			break;
		}
-
		HASH_ADD_KEYPTR(hh, obj->value.ov, sub->key, strlen(sub->key), sub);
+
		ucl_object_insert_key(obj, sub, key->data.scalar.value, key->data.scalar.length);
		++pair;
	}
}
@@ -640,14 +572,14 @@ yaml_to_ucl(const char *file, const char *buffer, size_t len) {

	node = yaml_document_get_root_node(&doc);
	if (node != NULL) {
-
		obj = ucl_object_new();
-
		obj->type = UCL_OBJECT;
		switch (node->type) {
		case YAML_MAPPING_NODE:
+
			obj = ucl_object_new();
			yaml_mapping_to_object(obj, &doc, node);
			break;
		case YAML_SEQUENCE_NODE:
-
			yaml_sequence_to_object(obj, &doc, node);
+
			obj = NULL;
+
			yaml_sequence_to_object(&obj, &doc, node);
			break;
		case YAML_SCALAR_NODE:
		case YAML_NO_NODE: