Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Sync with libucl
Baptiste Daroussin committed 12 years ago
commit 3605cfa3dee2d5fc341fc27866b623594d52f43a
parent c12e1bb
6 files changed +145 -88
modified external/libucl/include/ucl.h
@@ -88,29 +88,65 @@ enum ucl_error {
	UCL_ESSL       //!< UCL_ESSL
};

+
/**
+
 * Object types
+
 */
enum ucl_type {
-
	UCL_OBJECT = 0,
-
	UCL_ARRAY,
-
	UCL_INT,
-
	UCL_FLOAT,
-
	UCL_STRING,
-
	UCL_BOOLEAN,
-
	UCL_TIME,
-
	UCL_USERDATA
+
	UCL_OBJECT = 0,//!< UCL_OBJECT
+
	UCL_ARRAY,     //!< UCL_ARRAY
+
	UCL_INT,       //!< UCL_INT
+
	UCL_FLOAT,     //!< UCL_FLOAT
+
	UCL_STRING,    //!< UCL_STRING
+
	UCL_BOOLEAN,   //!< UCL_BOOLEAN
+
	UCL_TIME,      //!< UCL_TIME
+
	UCL_USERDATA   //!< UCL_USERDATA
};

+
/**
+
 * Emitting types
+
 */
enum ucl_emitter {
-
	UCL_EMIT_JSON = 0,
-
	UCL_EMIT_JSON_COMPACT,
-
	UCL_EMIT_CONFIG,
-
	UCL_EMIT_YAML
+
	UCL_EMIT_JSON = 0,    //!< UCL_EMIT_JSON
+
	UCL_EMIT_JSON_COMPACT,//!< UCL_EMIT_JSON_COMPACT
+
	UCL_EMIT_CONFIG,      //!< UCL_EMIT_CONFIG
+
	UCL_EMIT_YAML         //!< UCL_EMIT_YAML
+
};
+

+
/**
+
 * Parsing flags
+
 */
+
enum ucl_parser_flags {
+
	UCL_PARSER_KEY_LOWERCASE = 0x1,//!< UCL_FLAG_KEY_LOWERCASE
+
	UCL_PARSER_ZEROCOPY = 0x2      //!< UCL_FLAG_ZEROCOPY
+
};
+

+
/**
+
 * String conversion flags
+
 */
+
enum ucl_string_flags {
+
	UCL_STRING_ESCAPE = 0x1,  /**< UCL_STRING_ESCAPE perform JSON escape */
+
	UCL_STRING_TRIM = 0x2,    /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
+
	UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */
+
	UCL_STRING_PARSE_INT = 0x8,    /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */
+
	UCL_STRING_PARSE_DOUBLE = 0x10,    /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */
+
	UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE ,  /**<
+
									UCL_STRING_PARSE_NUMBER parse passed string and detect number */
+
	UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER   /**<
+
									UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
};

-
enum ucl_flags {
-
	UCL_FLAG_KEY_LOWERCASE = 0x1,
-
	UCL_FLAG_ZEROCOPY = 0x2
+
/**
+
 * Basic flags for an object
+
 */
+
enum ucl_object_flags {
+
	UCL_OBJECT_ALLOCATED_KEY = 1, //!< UCL_OBJECT_ALLOCATED_KEY
+
	UCL_OBJECT_ALLOCATED_VALUE = 2, //!< UCL_OBJECT_ALLOCATED_VALUE
+
	UCL_OBJECT_NEED_KEY_ESCAPE = 4 //!< UCL_OBJECT_NEED_KEY_ESCAPE
};

+
/**
+
 * UCL object
+
 */
typedef struct ucl_object_s {
	union {
		int64_t iv;							/**< int value of an object */
@@ -120,7 +156,8 @@ typedef struct ucl_object_s {
		void* ud;							/**< opaque user data		*/
	} value;
	enum ucl_type type;						/**< real type				*/
-
	int ref;								/**< reference count		*/
+
	short int ref;							/**< reference count		*/
+
	short int flags;						/**< object flags			*/
	size_t len;								/**< size of an object		*/
	struct ucl_object_s *next;				/**< array handle			*/
	struct ucl_object_s *prev;				/**< array handle			*/
@@ -160,21 +197,6 @@ ucl_object_new (void)
}

/**
-
 * String conversion flags
-
 */
-
enum ucl_string_flags {
-
	UCL_STRING_ESCAPE = 0x1,  /**< UCL_STRING_ESCAPE perform JSON escape */
-
	UCL_STRING_TRIM = 0x2,    /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
-
	UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */
-
	UCL_STRING_PARSE_INT = 0x8,    /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */
-
	UCL_STRING_PARSE_DOUBLE = 0x10,    /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */
-
	UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE ,  /**<
-
									UCL_STRING_PARSE_NUMBER parse passed string and detect number */
-
	UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER   /**<
-
									UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
-
};
-

-
/**
 * 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)
@@ -272,37 +294,8 @@ ucl_object_frombool (bool bv)
 * @param copy_key make an internal copy of key
 * @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, bool copy_key)
-
{
-
	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);
-

-
	if (copy_key) {
-
		ucl_copy_key_trash (elt);
-
	}
-

-
	return top;
-
}
+
ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
+
		const char *key, size_t keylen, bool copy_key);

/**
 * Append an element to the array object
modified external/libucl/src/ucl_chartable.h
@@ -29,21 +29,22 @@
static const unsigned int ucl_chartable[255] = {
UCL_CHARACTER_VALUE_END, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
-
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_JSON_UNSAFE,
-
UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE,
-
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE,
+
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+
UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
UCL_CHARACTER_WHITESPACE_UNSAFE,
-
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE,
-
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE,
+
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
+
UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
-
UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /*   */,
+
UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /*   */,
UCL_CHARACTER_VALUE_STR /* ! */,
-
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* " */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* " */,
UCL_CHARACTER_VALUE_END /* # */, UCL_CHARACTER_VALUE_STR /* $ */,
UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */,
UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */,
@@ -63,9 +64,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 7 */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 8 */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 9 */,
-
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* : */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* : */,
UCL_CHARACTER_VALUE_END /* ; */, UCL_CHARACTER_VALUE_STR /* < */,
-
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* = */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* = */,
UCL_CHARACTER_VALUE_STR /* > */, UCL_CHARACTER_VALUE_STR /* ? */,
UCL_CHARACTER_VALUE_STR /* @ */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* A */,
@@ -94,8 +95,8 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* X */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Y */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Z */,
-
UCL_CHARACTER_VALUE_STR /* [ */,
-
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* \ */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* [ */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* \ */,
UCL_CHARACTER_VALUE_END /* ] */, UCL_CHARACTER_VALUE_STR /* ^ */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR /* _ */,
UCL_CHARACTER_VALUE_STR /* ` */,
@@ -125,9 +126,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* x */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* y */,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* z */,
-
UCL_CHARACTER_VALUE_STR /* { */, UCL_CHARACTER_VALUE_STR /* | */,
-
UCL_CHARACTER_VALUE_END /* } */, UCL_CHARACTER_VALUE_STR /* ~ */,
-
UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* { */,
+
UCL_CHARACTER_VALUE_STR /* | */, UCL_CHARACTER_VALUE_END /* } */,
+
UCL_CHARACTER_VALUE_STR /* ~ */, UCL_CHARACTER_DENIED,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
modified external/libucl/src/ucl_emitter.c
@@ -346,7 +346,12 @@ 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);
-
		utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+
		if (cur->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+
			ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+
		}
+
		else {
+
			utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+
		}
		if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
			utstring_append_len (buf, " = ", 3);
		}
@@ -481,7 +486,12 @@ 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);
-
		utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+
		if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+
			ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf);
+
		}
+
		else {
+
			utstring_append_len (buf, cur->hh.key, cur->hh.keylen);
+
		}
		if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
			utstring_append_len (buf, " : ", 3);
		}
modified external/libucl/src/ucl_internal.h
@@ -79,7 +79,8 @@ enum ucl_character_type {
	UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7,
	UCL_CHARACTER_ESCAPE = 1 << 8,
	UCL_CHARACTER_KEY_SEP = 1 << 9,
-
	UCL_CHARACTER_JSON_UNSAFE = 1 << 10
+
	UCL_CHARACTER_JSON_UNSAFE = 1 << 10,
+
	UCL_CHARACTER_UCL_UNSAFE = 1 << 11
};

struct ucl_macro {
modified external/libucl/src/ucl_parser.c
@@ -241,7 +241,7 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
{
	size_t ret = 0;

-
	if (need_unescape || need_lowercase || !(parser->flags & UCL_FLAG_ZEROCOPY)) {
+
	if (need_unescape || need_lowercase || !(parser->flags & UCL_PARSER_ZEROCOPY)) {
		/* Copy string */
		*dst = UCL_ALLOC (in_len + 1);
		if (*dst == NULL) {
@@ -525,7 +525,7 @@ ucl_lex_number (struct ucl_parser *parser,
 */
static bool
ucl_lex_json_string (struct ucl_parser *parser,
-
		struct ucl_chunk *chunk, bool *need_unescape)
+
		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape)
{
	const unsigned char *p = chunk->pos;
	unsigned char c;
@@ -574,12 +574,16 @@ ucl_lex_json_string (struct ucl_parser *parser,
				return false;
			}
			*need_unescape = true;
+
			*ucl_escape = true;
			continue;
		}
		else if (c == '"') {
			ucl_chunk_skipc (chunk, p);
			return true;
		}
+
		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
+
			*ucl_escape = true;
+
		}
		ucl_chunk_skipc (chunk, p);
	}

@@ -598,7 +602,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
{
	const unsigned char *p, *c = NULL, *end;
	const char *key;
-
	bool got_quote = false, got_eq = false, got_semicolon = false, need_unescape = false;
+
	bool got_quote = false, got_eq = false, got_semicolon = false,
+
			need_unescape = false, ucl_escape = false;
	ucl_object_t *nobj, *tobj, *container;
	size_t keylen;

@@ -656,9 +661,10 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
			}
			else {
				/* We need to parse json like quoted string */
-
				if (!ucl_lex_json_string (parser, chunk, &need_unescape)) {
+
				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
					return false;
				}
+
				/* Always escape keys obtained via json */
				end = chunk->pos - 1;
				p = chunk->pos;
				break;
@@ -717,7 +723,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
	/* Create a new object */
	nobj = ucl_object_new ();
	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
-
			&key, end - c, need_unescape, parser->flags & UCL_FLAG_KEY_LOWERCASE);
+
			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE);
	if (keylen == 0) {
		return false;
	}
@@ -732,6 +738,9 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
		DL_APPEND (tobj, nobj);
	}

+
	if (ucl_escape) {
+
		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
+
	}
	parser->stack->obj->value.ov = container;

	parser->cur_obj = nobj;
@@ -861,7 +870,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
	ucl_object_t *obj = NULL, *t;
	unsigned int stripped_spaces;
	int str_len;
-
	bool need_unescape = false;
+
	bool need_unescape = false, ucl_escape = false;

	p = chunk->pos;

@@ -884,7 +893,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
		switch (*p) {
		case '"':
			ucl_chunk_skipc (chunk, p);
-
			if (!ucl_lex_json_string (parser, chunk, &need_unescape)) {
+
			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
				return false;
			}
			str_len = chunk->pos - c - 2;
@@ -1130,7 +1139,7 @@ ucl_parse_macro_value (struct ucl_parser *parser,
		unsigned char const **macro_start, size_t *macro_len)
{
	const unsigned char *p, *c;
-
	bool need_unescape = false;
+
	bool need_unescape = false, ucl_escape = false;

	p = chunk->pos;

@@ -1139,7 +1148,7 @@ ucl_parse_macro_value (struct ucl_parser *parser,
		/* We have macro value encoded in quotes */
		c = p;
		ucl_chunk_skipc (chunk, p);
-
		if (!ucl_lex_json_string (parser, chunk, &need_unescape)) {
+
		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) {
			return false;
		}

modified external/libucl/src/ucl_util.c
@@ -186,6 +186,7 @@ ucl_copy_key_trash (ucl_object_t *obj)
			obj->trash_stack[UCL_TRASH_KEY][obj->hh.keylen] = '\0';
		}
		obj->hh.key = obj->trash_stack[UCL_TRASH_KEY];
+
		obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
	}

	return obj->trash_stack[UCL_TRASH_KEY];
@@ -202,6 +203,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
			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';
+
				obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
			}
		}
		else {
@@ -215,6 +217,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
				free (emitted);
			}
		}
+
		obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
	}
	return obj->trash_stack[UCL_TRASH_VALUE];
}
@@ -851,3 +854,43 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags

	return obj;
}
+

+
ucl_object_t *
+
ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
+
		const char *key, size_t keylen, bool copy_key)
+
{
+
	ucl_object_t *found;
+
	const char *p;
+

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

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

+
	for (p = key; p < key + keylen; p ++) {
+
		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
+
			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
+
			break;
+
		}
+
	}
+

+
	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);
+

+
	if (copy_key) {
+
		ucl_copy_key_trash (elt);
+
	}
+

+
	return top;
+
}