Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to latest version
Baptiste Daroussin committed 6 years ago
commit b291152ae8d7904e1a6c07ddb23652f32c24b344
parent 5fb1f4f
11 files changed +428 -133
modified external/libucl/Makefile.autosetup
@@ -14,6 +14,7 @@ LOCAL_CFLAGS= -I$(top_srcdir)/external/libucl/include \
		-I$(top_srcdir)/external/libucl/uthash \
		-I$(top_srcdir)/external/libucl/klib \
		-I$(top_srcdir)/external/libucl/src/ \
-
		-Wno-unused-parameter
+
		-Wno-unused-parameter \
+
		-Wno-pointer-sign

include $(MK)/static-lib.mk
modified external/libucl/doc/api.md
@@ -432,7 +432,8 @@ UCL defines the following functions to manage safe iterators:

- `ucl_object_iterate_new` - creates new safe iterator
- `ucl_object_iterate_reset` - resets iterator to a new object
-
- `ucl_object_iterate_safe` - safely iterate the object inside iterator
+
- `ucl_object_iterate_safe` - safely iterate the object inside iterator. Note: function may allocate and free memory during its operation. Therefore it returns `NULL` either while trying to access item after the last one or when exception (such as memory allocation failure) happens.
+
- `ucl_object_iter_chk_excpn` -  check if the last call to `ucl_object_iterate_safe` ended up in unrecoverable exception (e.g. `ENOMEM`).
- `ucl_object_iterate_free` - free memory associated with the safe iterator

Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed.
@@ -447,6 +448,11 @@ it = ucl_object_iterate_new (obj);
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
	/* Do something */
}
+
/* Check error condition */
+
if (ucl_object_iter_chk_excpn (it)) {
+
    ucl_object_iterate_free (it);
+
    exit (1);
+
}

/* Switch to another object */
it = ucl_object_iterate_reset (it, another_obj);
@@ -454,6 +460,11 @@ it = ucl_object_iterate_reset (it, another_obj);
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
	/* Do something else */
}
+
/* Check error condition */
+
if (ucl_object_iter_chk_excpn (it)) {
+
    ucl_object_iterate_free (it);
+
    exit (1);
+
}

ucl_object_iterate_free (it);
~~~
modified external/libucl/doc/libucl.3
@@ -612,15 +612,23 @@ Iteration\ without\ expansion:
.PP
UCL defines the following functions to manage safe iterators:
.IP \[bu] 2
-
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator
+
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator.
.IP \[bu] 2
-
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object
+
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object.
.IP \[bu] 2
\f[C]ucl_object_iterate_safe\f[] \- safely iterate the object inside
-
iterator
+
iterator.
+
Note: function may allocate and free memory during its operation.
+
Therefore it returns \f[C]NULL\f[] either while trying to access item
+
after the last one or when exception (such as memory allocation
+
failure) happens.
+
.IP \[bu] 2
+
\f[C]ucl_object_iter_chk_excpn\f[] \- check if the last call to
+
\f[C]ucl_object_iterate_safe\f[] ended up in unrecoverable exception
+
(e.g. \f[C]ENOMEM\f[]).
.IP \[bu] 2
\f[C]ucl_object_iterate_free\f[] \- free memory associated with the safe
-
iterator
+
iterator.
.PP
Please note that unlike unsafe iterators, safe iterators \f[I]must\f[]
be explicitly initialized and freed.
@@ -637,6 +645,11 @@ it\ =\ ucl_object_iterate_new\ (obj);
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
\ \ \ \ /*\ Do\ something\ */
}
+
/*\ Check\ error\ condition\ */
+
if\ (ucl_object_iter_chk_excpn\ (it))\ {
+
\ \ \ \ ucl_object_iterate_free\ (it);
+
\ \ \ \ exit\ (1);
+
}

/*\ Switch\ to\ another\ object\ */
it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
@@ -644,6 +657,11 @@ it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
\ \ \ \ /*\ Do\ something\ else\ */
}
+
/*\ Check\ error\ condition\ */
+
if\ (ucl_object_iter_chk_excpn\ (it))\ {
+
\ \ \ \ ucl_object_iterate_free\ (it);
+
\ \ \ \ exit\ (1);
+
}

ucl_object_iterate_free\ (it);
\f[]
modified external/libucl/include/ucl.h
@@ -469,8 +469,9 @@ UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *e
 * Reserve space in ucl array or object for `elt` elements
 * @param obj object to reserve
 * @param reserved size to reserve in an object
+
 * @return 0 on success, -1 on failure (i.e. ENOMEM)
 */
-
UCL_EXTERN void ucl_object_reserve (ucl_object_t *obj, size_t reserved);
+
UCL_EXTERN bool ucl_object_reserve (ucl_object_t *obj, size_t reserved);

/**
 * Append an element to the end of array object
@@ -825,11 +826,14 @@ typedef void* ucl_object_iter_t;
 * @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) ...
+
 * @param ep pointer record exception (such as ENOMEM), could be NULL
 * @return the next object or NULL
 */
-
UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj,
-
		ucl_object_iter_t *iter, bool expand_values);
+
UCL_EXTERN const ucl_object_t* ucl_object_iterate_with_error (const ucl_object_t *obj,
+
		ucl_object_iter_t *iter, bool expand_values, int *ep);
+

#define ucl_iterate_object ucl_object_iterate
+
#define ucl_object_iterate(ob, it, ev) ucl_object_iterate_with_error((ob), (it), (ev), NULL)

/**
 * Create new safe iterator for the specified object
@@ -839,6 +843,15 @@ UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj,
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj)
	UCL_WARN_UNUSED_RESULT;
/**
+
 * Check safe iterator object after performing some operations on it
+
 * (such as ucl_object_iterate_safe()) to see if operation has encountered
+
 * fatal exception while performing that operation (e.g. ENOMEM).
+
 * @param iter opaque iterator
+
 * @return true if exception has occured, false otherwise
+
 */
+
UCL_EXTERN bool ucl_object_iter_chk_excpn(ucl_object_iter_t *it);
+

+
/**
 * Reset initialized iterator to a new object
 * @param obj new object to iterate
 * @return modified iterator object
@@ -951,8 +964,9 @@ UCL_EXTERN int ucl_parser_get_default_priority (struct ucl_parser *parser);
 * @param macro macro name (without leading dot)
 * @param handler handler (it is called immediately after macro is parsed)
 * @param ud opaque user data for a handler
+
 * @return true on success, false on failure (i.e. ENOMEM)
 */
-
UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser,
+
UCL_EXTERN bool ucl_parser_register_macro (struct ucl_parser *parser,
		const char *macro,
		ucl_macro_handler handler, void* ud);

@@ -962,8 +976,9 @@ UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser,
 * @param macro macro name (without leading dot)
 * @param handler handler (it is called immediately after macro is parsed)
 * @param ud opaque user data for a handler
+
 * @return true on success, false on failure (i.e. ENOMEM)
 */
-
UCL_EXTERN void ucl_parser_register_context_macro (struct ucl_parser *parser,
+
UCL_EXTERN bool ucl_parser_register_context_macro (struct ucl_parser *parser,
		const char *macro,
		ucl_context_macro_handler handler,
		void* ud);
@@ -1280,6 +1295,13 @@ UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *
		bool need_expand);

/**
+
 * Returns current file for the parser
+
 * @param parser parser object
+
 * @return current file or NULL if parsing memory
+
 */
+
UCL_EXTERN const char *ucl_parser_get_cur_file (struct ucl_parser *parser);
+

+
/**
 * Defines special handler for certain types of data (identified by magic)
 */
typedef bool (*ucl_parser_special_handler_t) (struct ucl_parser *parser,
@@ -1288,11 +1310,20 @@ typedef bool (*ucl_parser_special_handler_t) (struct ucl_parser *parser,
		void *user_data);

/**
+
 * Special handler flags
+
 */
+
enum ucl_special_handler_flags {
+
	UCL_SPECIAL_HANDLER_DEFAULT = 0,
+
	UCL_SPECIAL_HANDLER_PREPROCESS_ALL = (1u << 0),
+
};
+

+
/**
 * Special handler structure
 */
struct ucl_parser_special_handler {
	const unsigned char *magic;
	size_t magic_len;
+
	enum ucl_special_handler_flags flags;
	ucl_parser_special_handler_t handler;
	void (*free_function) (unsigned char *data, size_t len, void *user_data);
	void *user_data;
@@ -1300,13 +1331,39 @@ struct ucl_parser_special_handler {
};

/**
-
 * Add special handler for a parser
+
 * Add special handler for a parser, handles special sequences identified by magic
 * @param parser parser structure
 * @param handler handler structure
 */
UCL_EXTERN void ucl_parser_add_special_handler (struct ucl_parser *parser,
		struct ucl_parser_special_handler *handler);

+
/**
+
 * Handler for include traces:
+
 * @param parser parser object
+
 * @param parent where include is done from
+
 * @param args arguments to an include
+
 * @param path path of the include
+
 * @param pathlen length of the path
+
 * @param user_data opaque userdata
+
 */
+
typedef void (ucl_include_trace_func_t) (struct ucl_parser *parser,
+
		const ucl_object_t *parent,
+
		const ucl_object_t *args,
+
		const char *path,
+
		size_t pathlen,
+
		void *user_data);
+

+
/**
+
 * Register trace function for an include handler
+
 * @param parser parser object
+
 * @param func function to trace includes
+
 * @param user_data opaque data
+
 */
+
UCL_EXTERN void ucl_parser_set_include_tracer (struct ucl_parser *parser,
+
											   ucl_include_trace_func_t func,
+
											   void *user_data);
+

/** @} */

/**
modified external/libucl/klib/kvec.h
@@ -30,11 +30,13 @@
int main() {
	kvec_t(int) array;
	kv_init(array);
-
	kv_push(int, array, 10); // append
+
	kv_push_safe(int, array, 10, e0); // append
	kv_a(int, array, 20) = 5; // dynamic
	kv_A(array, 20) = 4; // static
	kv_destroy(array);
	return 0;
+
e0:
+
	return 1;
}
*/

@@ -60,8 +62,71 @@ int main() {
#define kv_size(v) ((v).n)
#define kv_max(v) ((v).m)

-
#define kv_resize(type, v, s)  ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
+
#define kv_resize_safe(type, v, s, el)  do { \
+
		type *_tp = (type*)realloc((v).a, sizeof(type) * (s)); \
+
		if (_tp == NULL) { \
+
			goto el; \
+
		} else { \
+
			(v).a = _tp; \
+
			(v).m = (s); \
+
		} \
+
	} while (0)
+

#define kv_grow_factor 1.5
+
#define kv_grow_safe(type, v, el)  do { \
+
		size_t _ts = ((v).m > 1 ? (v).m * kv_grow_factor : 2); \
+
		type *_tp = (type*)realloc((v).a, sizeof(type) * _ts); \
+
		if (_tp == NULL) { \
+
			goto el; \
+
		} else { \
+
			(v).a = _tp; \
+
			(v).m = _ts; \
+
		} \
+
	} while (0)
+

+
#define kv_copy_safe(type, v1, v0, el) do { \
+
		if ((v1).m < (v0).n) kv_resize_safe(type, v1, (v0).n, el); \
+
		(v1).n = (v0).n; \
+
		memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
+
	} while (0)
+

+
#define kv_push_safe(type, v, x, el) do { \
+
		if ((v).n == (v).m) { \
+
			kv_grow_safe(type, v, el); \
+
		} \
+
		(v).a[(v).n++] = (x); \
+
	} while (0)
+

+
#define kv_prepend_safe(type, v, x, el) do { \
+
		if ((v).n == (v).m) { \
+
			kv_grow_safe(type, v, el); \
+
		} \
+
		memmove((v).a + 1, (v).a, sizeof(type) * (v).n); \
+
		(v).a[0] = (x);	\
+
		(v).n ++; \
+
	} while (0)
+

+
#define kv_concat_safe(type, v1, v0, el) do { \
+
		if ((v1).m < (v0).n + (v1).n) \
+
			kv_resize_safe(type, v1, (v0).n + (v1).n, el); \
+
		memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * (v0).n);	\
+
		(v1).n = (v0).n + (v1).n; \
+
	} while (0)
+

+
#define kv_del(type, v, i) do {												\
+
	if ((i) < (v).n) {														\
+
		memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
+
		(v).n --;															\
+
	}																		\
+
} while (0)
+

+
/*
+
 * Old (ENOMEM-unsafe) version of kv_xxx macros. Compat-only, not for use in
+
 * the new library code.
+
 */
+

+
#define kv_resize(type, v, s)  ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
+

#define kv_grow(type, v)  ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \
		(v).a = (type*)realloc((v).a, sizeof(type) * (v).m))

@@ -93,11 +158,4 @@ int main() {
		(v1).n = (v0).n + (v1).n;											\
	} while (0)

-
#define kv_del(type, v, i) do {												\
-
	if ((i) < (v).n) {														\
-
		memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
-
		(v).n --;															\
-
	}																		\
-
} while (0)
-

-
#endif
+
#endif /* AC_KVEC_H */
modified external/libucl/src/ucl_hash.c
@@ -237,17 +237,21 @@ ucl_hash_create (bool ignore_case)

	new = UCL_ALLOC (sizeof (ucl_hash_t));
	if (new != NULL) {
+
		void *h;
		kv_init (new->ar);

		new->caseless = ignore_case;
		if (ignore_case) {
-
			khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node);
-
			new->hash = (void *)h;
+
			h = (void *)kh_init (ucl_hash_caseless_node);
		}
		else {
-
			khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node);
-
			new->hash = (void *)h;
+
			h = (void *)kh_init (ucl_hash_node);
		}
+
		if (h == NULL) {
+
			UCL_FREE (sizeof (ucl_hash_t), new);
+
			return NULL;
+
		}
+
		new->hash = h;
	}
	return new;
}
@@ -293,7 +297,7 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
	UCL_FREE (sizeof (*hashlin), hashlin);
}

-
void
+
bool
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
		const char *key, unsigned keylen)
{
@@ -302,7 +306,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
	struct ucl_hash_elt *elt;

	if (hashlin == NULL) {
-
		return;
+
		return false;
	}

	if (hashlin->caseless) {
@@ -311,7 +315,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
		k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
		if (ret > 0) {
			elt = &kh_value (h, k);
-
			kv_push (const ucl_object_t *, hashlin->ar, obj);
+
			kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0);
			elt->obj = obj;
			elt->ar_idx = kv_size (hashlin->ar) - 1;
		}
@@ -322,11 +326,16 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
		k = kh_put (ucl_hash_node, h, obj, &ret);
		if (ret > 0) {
			elt = &kh_value (h, k);
-
			kv_push (const ucl_object_t *, hashlin->ar, obj);
+
			kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0);
			elt->obj = obj;
			elt->ar_idx = kv_size (hashlin->ar) - 1;
+
		} else if (ret < 0) {
+
			goto e0;
		}
	}
+
	return true;
+
e0:
+
	return false;
}

void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
@@ -375,13 +384,16 @@ struct ucl_hash_real_iter {
	const ucl_object_t **end;
};

+
#define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);}
+

const void*
-
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
+
ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep)
{
	struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
	const ucl_object_t *ret = NULL;

	if (hashlin == NULL) {
+
		UHI_SETERR(ep, EINVAL);
		return NULL;
	}

@@ -389,6 +401,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
		it = UCL_ALLOC (sizeof (*it));

		if (it == NULL) {
+
			UHI_SETERR(ep, ENOMEM);
			return NULL;
		}

@@ -396,6 +409,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
		it->end = it->cur + hashlin->ar.n;
	}

+
	UHI_SETERR(ep, 0);
	if (it->cur < it->end) {
		ret = *it->cur++;
	}
@@ -505,14 +519,14 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
	}
}

-
void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
+
bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
{
	if (hashlin == NULL) {
-
		return;
+
		return false;
	}

	if (sz > hashlin->ar.m) {
-
		kv_resize (const ucl_object_t *, hashlin->ar, sz);
+
		kv_resize_safe (const ucl_object_t *, hashlin->ar, sz, e0);

		if (hashlin->caseless) {
			khash_t(ucl_hash_caseless_node) *h = (khash_t(
@@ -525,4 +539,7 @@ void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
			kh_resize (ucl_hash_node, h, sz * 2);
		}
	}
-
}

\ No newline at end of file
+
	return true;
+
e0:
+
	return false;
+
}
modified external/libucl/src/ucl_hash.h
@@ -55,8 +55,9 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func);

/**
 * Inserts an element in the the hashtable.
+
 * @return true on success, false on failure (i.e. ENOMEM)
 */
-
void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
+
bool ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
		unsigned keylen);

/**
@@ -81,9 +82,15 @@ const ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key,
 * Iterate over hash table
 * @param hashlin hash
 * @param iter iterator (must be NULL on first iteration)
+
 * @param ep pointer record exception (such as ENOMEM), could be NULL
 * @return the next object
 */
-
const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
+
const void* ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep);
+

+
/**
+
 * Helper macro to support older code
+
 */
+
#define ucl_hash_iterate(hl, ip) ucl_hash_iterate2((hl), (ip), NULL)

/**
 * Check whether an iterator has next element
@@ -92,8 +99,9 @@ bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);

/**
 * Reserves space in hash
+
 * @return true on sucess, false on failure (e.g. ENOMEM)
 * @param hashlin
 */
-
void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz);
+
bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz);

#endif
modified external/libucl/src/ucl_internal.h
@@ -205,6 +205,13 @@ struct ucl_stack {
	struct ucl_chunk *chunk;
};

+
struct ucl_parser_special_handler_chain {
+
	unsigned char *begin;
+
	size_t len;
+
	struct ucl_parser_special_handler *special_handler;
+
	struct ucl_parser_special_handler_chain *next;
+
};
+

struct ucl_chunk {
	const unsigned char *begin;
	const unsigned char *end;
@@ -216,7 +223,7 @@ struct ucl_chunk {
	unsigned priority;
	enum ucl_duplicate_strategy strategy;
	enum ucl_parse_type parse_type;
-
	struct ucl_parser_special_handler *special_handler;
+
	struct ucl_parser_special_handler_chain *special_handlers;
	struct ucl_chunk *next;
};

@@ -255,7 +262,9 @@ struct ucl_parser {
	struct ucl_stack *stack;
	struct ucl_chunk *chunks;
	struct ucl_pubkey *keys;
-
    struct ucl_parser_special_handler *special_handlers;
+
	struct ucl_parser_special_handler *special_handlers;
+
	ucl_include_trace_func_t *include_trace_func;
+
	void *include_trace_ud;
	struct ucl_variable *variables;
	ucl_variable_handler var_handler;
	void *var_data;
@@ -463,12 +472,24 @@ ucl_hash_insert_object (ucl_hash_t *hashlin,
		const ucl_object_t *obj,
		bool ignore_case)
{
+
	ucl_hash_t *nhp;
+

	if (hashlin == NULL) {
-
		hashlin = ucl_hash_create (ignore_case);
+
		nhp = ucl_hash_create (ignore_case);
+
		if (nhp == NULL) {
+
			return NULL;
+
		}
+
	} else {
+
		nhp = hashlin;
+
	}
+
	if (!ucl_hash_insert (nhp, obj, obj->key, obj->keylen)) {
+
		if (nhp != hashlin) {
+
			ucl_hash_destroy(nhp, NULL);
+
		}
+
		return NULL;
	}
-
	ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);

-
	return hashlin;
+
	return nhp;
}

/**
modified external/libucl/src/ucl_parser.c
@@ -634,70 +634,51 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
		bool is_array, uint32_t level, bool has_obrace)
{
	struct ucl_stack *st;
-
	bool need_free = false;
-

-
	if (!is_array) {
-
		if (obj == NULL) {
-
			obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
-
			need_free = true;
-
		}
-
		else {
-
			if (obj->type == UCL_ARRAY) {
-
				/* Bad combination for merge: array and object */
-
				ucl_set_err (parser, UCL_EMERGE,
-
						"cannot merge an array with an object",
-
						&parser->err);
-

-
				return NULL;
-
			}
+
	ucl_object_t *nobj;

-
			obj->type = UCL_OBJECT;
+
	if (obj == NULL) {
+
		nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority);
+
		if (nobj == NULL) {
+
			goto enomem0;
		}
+
	} else {
+
		if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) {
+
			/* Bad combination for merge: array and object */
+
			ucl_set_err (parser, UCL_EMERGE,
+
					"cannot merge an object with an array",
+
					&parser->err);

-
		if (obj->value.ov == NULL) {
-
			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
			return NULL;
		}
-
		parser->state = UCL_STATE_KEY;
+
		nobj = obj;
+
		nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT;
	}
-
	else {
-
		if (obj == NULL) {
-
			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
-
			need_free = true;
-
		}
-
		else {
-
			if (obj->type == UCL_OBJECT) {
-
				/* Bad combination for merge: array and object */
-
				ucl_set_err (parser, UCL_EMERGE,
-
						"cannot merge an object with an array",
-
						&parser->err);

-
				return NULL;
+
	if (!is_array) {
+
		if (nobj->value.ov == NULL) {
+
			nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
			if (nobj->value.ov == NULL) {
+
				goto enomem1;
			}
-

-
			obj->type = UCL_ARRAY;
		}
+
		parser->state = UCL_STATE_KEY;
+
	} else {
		parser->state = UCL_STATE_VALUE;
	}

	st = UCL_ALLOC (sizeof (struct ucl_stack));

	if (st == NULL) {
-
		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
-
				&parser->err);
-
		if (need_free) {
-
			ucl_object_unref (obj);
-
		}
-

-
		return NULL;
+
		goto enomem1;
	}

-
	st->obj = obj;
+
	st->obj = nobj;

	if (level >= UINT16_MAX) {
		ucl_set_err (parser, UCL_ENESTED,
				"objects are nesting too deep (over 65535 limit)",
				&parser->err);
-
		if (need_free) {
+
		if (nobj != obj) {
			ucl_object_unref (obj);
		}

@@ -717,9 +698,16 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
	}

	LL_PREPEND (parser->stack, st);
-
	parser->cur_obj = obj;
+
	parser->cur_obj = nobj;

-
	return obj;
+
	return nobj;
+
enomem1:
+
	if (nobj != obj)
+
		ucl_object_unref (nobj);
+
enomem0:
+
	ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
+
			&parser->err);
+
	return NULL;
}

int
@@ -1194,6 +1182,9 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
	if (tobj == NULL) {
		container = ucl_hash_insert_object (container, nobj,
				parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
		if (container == NULL) {
+
			return false;
+
		}
		nobj->prev = nobj;
		nobj->next = NULL;
		parser->stack->obj->len ++;
@@ -1477,6 +1468,9 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,

	/* Create a new object */
	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
+
	if (nobj == NULL) {
+
		return false;
+
	}
	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,
			false, false);
@@ -1816,8 +1810,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
					}
					if (*p =='\n') {
						/* Set chunk positions and start multiline parsing */
+
						chunk->remain -= p - c + 1;
						c += 2;
-
						chunk->remain -= p - c;
						chunk->pos = p + 1;
						chunk->column = 0;
						chunk->line ++;
@@ -2672,6 +2666,11 @@ ucl_state_machine (struct ucl_parser *parser)
	return true;
}

+
#define UPRM_SAFE(fn, a, b, c, el) do { \
+
		if (!fn(a, b, c, a)) \
+
			goto el; \
+
	} while (0)
+

struct ucl_parser*
ucl_parser_new (int flags)
{
@@ -2684,12 +2683,12 @@ ucl_parser_new (int flags)

	memset (parser, 0, sizeof (struct ucl_parser));

-
	ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
-
	ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
-
	ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
-
	ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
-
	ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
-
	ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
+
	UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0);
+
	UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0);
+
	UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0);
+
	UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0);
+
	UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0);
+
	UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0);

	parser->flags = flags;
	parser->includepaths = NULL;
@@ -2704,6 +2703,9 @@ ucl_parser_new (int flags)
	}

	return parser;
+
e0:
+
	ucl_parser_free(parser);
+
	return NULL;
}

bool
@@ -2728,49 +2730,59 @@ ucl_parser_get_default_priority (struct ucl_parser *parser)
	return parser->default_priority;
}

-
void
+
bool
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
		ucl_macro_handler handler, void* ud)
{
	struct ucl_macro *new;

	if (macro == NULL || handler == NULL) {
-
		return;
+
		return false;
	}

	new = UCL_ALLOC (sizeof (struct ucl_macro));
	if (new == NULL) {
-
		return;
+
		return false;
	}

	memset (new, 0, sizeof (struct ucl_macro));
	new->h.handler = handler;
	new->name = strdup (macro);
+
	if (new->name == NULL) {
+
		UCL_FREE (sizeof (struct ucl_macro), new);
+
		return false;
+
	}
	new->ud = ud;
	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
+
	return true;
}

-
void
+
bool
ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
		ucl_context_macro_handler handler, void* ud)
{
	struct ucl_macro *new;

	if (macro == NULL || handler == NULL) {
-
		return;
+
		return false;
	}

	new = UCL_ALLOC (sizeof (struct ucl_macro));
	if (new == NULL) {
-
		return;
+
		return false;
	}

	memset (new, 0, sizeof (struct ucl_macro));
	new->h.context_handler = handler;
	new->name = strdup (macro);
+
	if (new->name == NULL) {
+
		UCL_FREE (sizeof (struct ucl_macro), new);
+
		return false;
+
	}
	new->ud = ud;
	new->is_context = true;
	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
+
	return true;
}

void
@@ -2861,9 +2873,11 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,

		memset (chunk, 0, sizeof (*chunk));

+
		/* Apply all matching handlers from the first to the last */
		LL_FOREACH (parser->special_handlers, special_handler) {
-
			if (len >= special_handler->magic_len &&
-
					memcmp (data, special_handler->magic, special_handler->magic_len) == 0) {
+
			if ((special_handler->flags & UCL_SPECIAL_HANDLER_PREPROCESS_ALL) ||
+
					(len >= special_handler->magic_len &&
+
					 memcmp (data, special_handler->magic, special_handler->magic_len) == 0)) {
				unsigned char *ndata = NULL;
				size_t nlen = 0;

@@ -2873,11 +2887,17 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
					return false;
				}

+
				struct ucl_parser_special_handler_chain *nchain;
+
				nchain = UCL_ALLOC (sizeof (*nchain));
+
				nchain->begin = ndata;
+
				nchain->len = nlen;
+
				nchain->special_handler = special_handler;
+

+
				/* Free order is reversed */
+
				LL_PREPEND (chunk->special_handlers, nchain);
+

				data = ndata;
				len = nlen;
-
				chunk->special_handler = special_handler;
-

-
				break;
			}
		}

modified external/libucl/src/ucl_util.c
@@ -520,18 +520,23 @@ void
ucl_chunk_free (struct ucl_chunk *chunk)
{
	if (chunk) {
-
		if (chunk->special_handler) {
-
			if (chunk->special_handler->free_function) {
-
				chunk->special_handler->free_function (
-
						(unsigned char *) chunk->begin,
-
						chunk->end - chunk->begin,
-
						chunk->special_handler->user_data);
+
		struct ucl_parser_special_handler_chain *chain, *tmp;
+

+
		LL_FOREACH_SAFE (chunk->special_handlers, chain, tmp) {
+
			if (chain->special_handler->free_function) {
+
				chain->special_handler->free_function (
+
						chain->begin,
+
						chain->len,
+
						chain->special_handler->user_data);
			} else {
-
				UCL_FREE (chunk->end - chunk->begin,
-
						(unsigned char *) chunk->begin);
+
				UCL_FREE (chain->len, chain->begin);
			}
+

+
			UCL_FREE (sizeof (*chain), chain);
		}

+
		chunk->special_handlers = NULL;
+

		if (chunk->fname) {
			free (chunk->fname);
		}
@@ -1149,7 +1154,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
	}

	old_curfile = parser->cur_file;
-
	parser->cur_file = strdup (realbuf);
+
	parser->cur_file = NULL;

	/* Store old file vars */
	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
@@ -1394,7 +1399,9 @@ ucl_include_file_single (const unsigned char *data, size_t len,
 */
static bool
ucl_include_file (const unsigned char *data, size_t len,
-
		struct ucl_parser *parser, struct ucl_include_params *params)
+
				  struct ucl_parser *parser,
+
				  struct ucl_include_params *params,
+
				  const ucl_object_t *args)
{
	const unsigned char *p = data, *end = data + len;
	bool need_glob = false;
@@ -1424,6 +1431,20 @@ ucl_include_file (const unsigned char *data, size_t len,
				return (!params->must_exist || false);
			}
			for (i = 0; i < globbuf.gl_pathc; i ++) {
+

+
				if (parser->include_trace_func) {
+
					const ucl_object_t *parent = NULL;
+

+
					if (parser->stack) {
+
						parent = parser->stack->obj;
+
					}
+

+
					parser->include_trace_func (parser, parent, NULL,
+
							globbuf.gl_pathv[i],
+
							strlen (globbuf.gl_pathv[i]),
+
							parser->include_trace_ud);
+
				}
+

				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
						strlen (globbuf.gl_pathv[i]), parser, params)) {
					if (params->soft_fail) {
@@ -1490,6 +1511,17 @@ ucl_include_common (const unsigned char *data, size_t len,
	params.strat = UCL_DUPLICATE_APPEND;
	params.must_exist = !default_try;

+
	if (parser->include_trace_func) {
+
		const ucl_object_t *parent = NULL;
+

+
		if (parser->stack) {
+
			parent = parser->stack->obj;
+
		}
+

+
		parser->include_trace_func (parser, parent, args,
+
				data, len, parser->include_trace_ud);
+
	}
+

	/* Process arguments */
	if (args != NULL && args->type == UCL_OBJECT) {
		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
@@ -1554,7 +1586,7 @@ ucl_include_common (const unsigned char *data, size_t len,
		}
		else if (data != NULL) {
			/* Try to load a file */
-
			return ucl_include_file (data, len, parser, &params);
+
			return ucl_include_file (data, len, parser, &params, args);
		}
	}
	else {
@@ -1569,7 +1601,7 @@ ucl_include_common (const unsigned char *data, size_t len,
				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
						(int)len, data);
				if ((search = ucl_include_file (ipath, strlen (ipath),
-
						parser, &params))) {
+
						parser, &params, args))) {
					if (!params.allow_glob) {
						break;
					}
@@ -1930,6 +1962,12 @@ ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool n
			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
		}

+
		if (parser->cur_file) {
+
			free (parser->cur_file);
+
		}
+

+
		parser->cur_file = strdup (realbuf);
+

		/* Define variables */
		ucl_parser_register_variable (parser, "FILENAME", realbuf);
		curdir = dirname (realbuf);
@@ -1966,10 +2004,6 @@ ucl_parser_add_file_full (struct ucl_parser *parser, const char *filename,
		return false;
	}

-
	if (parser->cur_file) {
-
		free (parser->cur_file);
-
	}
-
	parser->cur_file = strdup (realbuf);
	ucl_parser_set_filevars (parser, realbuf, false);
	ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
			parse_type);
@@ -2654,7 +2688,8 @@ ucl_object_lookup_any (const ucl_object_t *obj,
}

const ucl_object_t*
-
ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
+
ucl_object_iterate_with_error (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values,
+
    int *ep)
{
	const ucl_object_t *elt = NULL;

@@ -2665,7 +2700,7 @@ ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
	if (expand_values) {
		switch (obj->type) {
		case UCL_OBJECT:
-
			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
+
			return (const ucl_object_t*)ucl_hash_iterate2 (obj->value.ov, iter, ep);
			break;
		case UCL_ARRAY: {
			unsigned int idx;
@@ -2711,6 +2746,7 @@ enum ucl_safe_iter_flags {
	UCL_ITERATE_FLAG_INSIDE_ARRAY,
	UCL_ITERATE_FLAG_INSIDE_OBJECT,
	UCL_ITERATE_FLAG_IMPLICIT,
+
	UCL_ITERATE_FLAG_EXCEPTION
};

const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
@@ -2743,6 +2779,15 @@ ucl_object_iterate_new (const ucl_object_t *obj)
	return (ucl_object_iter_t)it;
}

+
bool
+
ucl_object_iter_chk_excpn(ucl_object_iter_t *it)
+
{
+
        struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
+

+
        UCL_SAFE_ITER_CHECK (rit);
+

+
	return (rit->flags == UCL_ITERATE_FLAG_EXCEPTION);
+
}

ucl_object_iter_t
ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
@@ -2776,6 +2821,7 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
{
	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
	const ucl_object_t *ret = NULL;
+
	int ern;

	UCL_SAFE_ITER_CHECK (rit);

@@ -2785,7 +2831,12 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)

	if (rit->impl_it->type == UCL_OBJECT) {
		rit->flags = UCL_ITERATE_FLAG_INSIDE_OBJECT;
-
		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
+
		ret = ucl_object_iterate_with_error (rit->impl_it, &rit->expl_it, true, &ern);
+

+
		if (ret == NULL && ern != 0) {
+
			rit->flags = UCL_ITERATE_FLAG_EXCEPTION;
+
			return NULL;
+
		}

		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
			/* Need to switch to another implicit object in chain */
@@ -2933,7 +2984,7 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
					UCL_ARRAY_GET (vec, new);

					/* Preallocate some space for arrays */
-
					kv_resize (ucl_object_t *, *vec, 8);
+
					kv_resize_safe (ucl_object_t *, *vec, 8, enomem);
				}
			}
		}
@@ -2942,23 +2993,26 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
		new = ucl_object_new_userdata (NULL, NULL, NULL);
		ucl_object_set_priority (new, priority);
	}
-

+
enomem:
	return new;
}

-
void ucl_object_reserve (ucl_object_t *obj, size_t reserved)
+
bool ucl_object_reserve (ucl_object_t *obj, size_t reserved)
{
	if (obj->type == UCL_ARRAY) {
		UCL_ARRAY_GET (vec, obj);

		if (vec->m < reserved) {
			/* Preallocate some space for arrays */
-
			kv_resize (ucl_object_t *, *vec, reserved);
+
			kv_resize_safe (ucl_object_t *, *vec, reserved, e0);
		}
	}
	else if (obj->type == UCL_OBJECT) {
		ucl_hash_reserve (obj->value.ov, reserved);
	}
+
	return true;
+
e0:
+
	return false;
}

ucl_object_t*
@@ -3068,11 +3122,13 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
		top->value.av = (void *)vec;
	}

-
	kv_push (ucl_object_t *, *vec, elt);
+
	kv_push_safe (ucl_object_t *, *vec, elt, e0);

	top->len ++;

	return true;
+
e0:
+
	return false;
}

bool
@@ -3088,16 +3144,18 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
		vec = UCL_ALLOC (sizeof (*vec));
		kv_init (*vec);
		top->value.av = (void *)vec;
-
		kv_push (ucl_object_t *, *vec, elt);
+
		kv_push_safe (ucl_object_t *, *vec, elt, e0);
	}
	else {
		/* Slow O(n) algorithm */
-
		kv_prepend (ucl_object_t *, *vec, elt);
+
		kv_prepend_safe (ucl_object_t *, *vec, elt, e0);
	}

	top->len ++;

	return true;
+
e0:
+
	return false;
}

bool
@@ -3122,7 +3180,7 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
	UCL_ARRAY_GET (v2, cp);

	if (v1 && v2) {
-
		kv_concat (ucl_object_t *, *v1, *v2);
+
		kv_concat_safe (ucl_object_t *, *v1, *v2, e0);

		for (i = v2->n; i < v1->n; i ++) {
			obj = &kv_A (*v1, i);
@@ -3134,6 +3192,8 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
	}

	return true;
+
e0:
+
	return false;
}

ucl_object_t *
@@ -3838,3 +3898,18 @@ ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
				(const char *)&obj, sizeof (void *), true);
	}
}
+

+
void
+
ucl_parser_set_include_tracer (struct ucl_parser *parser,
+
							   ucl_include_trace_func_t func,
+
							   void *user_data)
+
{
+
	parser->include_trace_func = func;
+
	parser->include_trace_ud = user_data;
+
}
+

+
const char *
+
ucl_parser_get_cur_file (struct ucl_parser *parser)
+
{
+
	return parser->cur_file;
+
}

\ No newline at end of file
modified external/libucl/tests/test_generate.c
@@ -240,27 +240,36 @@ main (int argc, char **argv)
	/* Test iteration */
	it = ucl_object_iterate_new (obj);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	/* key0 = 0.1 */
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	/* key1 = "" */
	assert (ucl_object_type (it_obj) == UCL_STRING);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	/* key2 = "" */
	assert (ucl_object_type (it_obj) == UCL_STRING);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	/* key3 = "" */
	assert (ucl_object_type (it_obj) == UCL_STRING);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	/* key4 = ([float, int, float], boolean) */
	ucl_object_iterate_reset (it, it_obj);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	assert (ucl_object_type (it_obj) == UCL_INT);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (!ucl_object_iter_chk_excpn (it));
	assert (ucl_object_type (it_obj) == UCL_BOOLEAN);
	ucl_object_iterate_free (it);