Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Sync libucl (this fixes: #649)
Baptiste Daroussin committed 12 years ago
commit 344db47d71fb327b4d3713cbace82dc4ced551fd
parent 89ddac9
5 files changed +393 -65
modified external/libucl/include/ucl.h
@@ -103,7 +103,8 @@ enum ucl_type {
	UCL_STRING,    //!< UCL_STRING
	UCL_BOOLEAN,   //!< UCL_BOOLEAN
	UCL_TIME,      //!< UCL_TIME
-
	UCL_USERDATA   //!< UCL_USERDATA
+
	UCL_USERDATA,  //!< UCL_USERDATA
+
	UCL_NULL       //!< UCL_NULL
};

/**
@@ -135,8 +136,9 @@ enum ucl_string_flags {
	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 =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER,   /**<
									UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
+
	UCL_STRING_PARSE_BYTES = 0x20  /**< Treat numbers as bytes */
};

/**
@@ -199,6 +201,26 @@ ucl_object_new (void)
	if (new != NULL) {
		memset (new, 0, sizeof (ucl_object_t));
		new->ref = 1;
+
		new->type = UCL_NULL;
+
	}
+
	return new;
+
}
+

+
/**
+
 * Create new object with type specified
+
 * @param type type of a new object
+
 * @return new object
+
 */
+
static inline ucl_object_t* ucl_object_typed_new (unsigned int type) UCL_WARN_UNUSED_RESULT;
+
static inline ucl_object_t *
+
ucl_object_typed_new (unsigned int type)
+
{
+
	ucl_object_t *new;
+
	new = malloc (sizeof (ucl_object_t));
+
	if (new != NULL) {
+
		memset (new, 0, sizeof (ucl_object_t));
+
		new->ref = 1;
+
		new->type = (type <= UCL_NULL ? type : UCL_NULL);
	}
	return new;
}
@@ -660,6 +682,15 @@ void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
		ucl_macro_handler handler, void* ud);

/**
+
 * Register new parser variable
+
 * @param parser parser object
+
 * @param var variable name
+
 * @param value variable value
+
 */
+
void ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
+
		const char *value);
+

+
/**
 * Load new chunk to a parser
 * @param parser parser structure
 * @param data the pointer to the beginning of a chunk
modified external/libucl/src/ucl_emitter.c
@@ -257,6 +257,12 @@ ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
		}
		ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
		break;
+
	case UCL_NULL:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		utstring_printf (buf, "null");
+
		break;
	case UCL_OBJECT:
		ucl_elt_obj_write_json (obj, buf, tabs, start_tabs, compact);
		break;
@@ -441,6 +447,12 @@ ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
			}
			ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
			break;
+
		case UCL_NULL:
+
			if (start_tabs) {
+
				ucl_add_tabs (buf, tabs, false);
+
			}
+
			utstring_printf (buf, "null");
+
			break;
		case UCL_OBJECT:
			ucl_elt_obj_write_rcl (obj, buf, tabs, start_tabs, is_top);
			break;
@@ -475,7 +487,6 @@ ucl_object_emit_rcl (ucl_object_t *obj)
static void
ucl_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs)
{
-
	ucl_object_t *cur;
	bool is_array = (obj->next != NULL);

	if (is_array) {
@@ -485,6 +496,7 @@ ucl_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
		ucl_elt_write_yaml(obj, buf, tabs, start_tabs, false, true);
	}
}
+

/**
 * Write a single object to the buffer
 * @param obj object to write
@@ -595,6 +607,12 @@ ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
			}
			ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
			break;
+
		case UCL_NULL:
+
			if (start_tabs) {
+
				ucl_add_tabs (buf, tabs, false);
+
			}
+
			utstring_printf (buf, "null");
+
			break;
		case UCL_OBJECT:
			ucl_elt_obj_write_yaml (obj, buf, tabs, start_tabs, is_top);
			break;
modified external/libucl/src/ucl_internal.h
@@ -119,6 +119,14 @@ struct ucl_pubkey {
};
#endif

+
struct ucl_variable {
+
	char *var;
+
	char *value;
+
	size_t var_len;
+
	size_t value_len;
+
	struct ucl_variable *next;
+
};
+

struct ucl_parser {
	enum ucl_parser_state state;
	enum ucl_parser_state prev_state;
@@ -130,6 +138,7 @@ struct ucl_parser {
	struct ucl_stack *stack;
	struct ucl_chunk *chunks;
	struct ucl_pubkey *keys;
+
	struct ucl_variable *variables;
	UT_string *err;
};

@@ -250,7 +259,7 @@ ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t l
 * @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error
 */
int ucl_maybe_parse_number (ucl_object_t *obj,
-
		const char *start, const char *end, const char **pos, bool allow_double);
+
		const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes);


static inline ucl_object_t *
modified external/libucl/src/ucl_parser.c
@@ -233,15 +233,185 @@ ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
	return false;
}

+
static inline const char *
+
ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
+
		size_t *out_len, bool strict, bool *found)
+
{
+
	struct ucl_variable *var;
+

+
	LL_FOREACH (parser->variables, var) {
+
		if (strict) {
+
			if (remain == var->var_len) {
+
				if (memcmp (ptr, var->var, var->var_len) == 0) {
+
					*out_len += var->value_len;
+
					*found = true;
+
					return (ptr + var->var_len);
+
				}
+
			}
+
		}
+
		else {
+
			if (remain >= var->var_len) {
+
				if (memcmp (ptr, var->var, var->var_len) == 0) {
+
					*out_len += var->value_len;
+
					*found = true;
+
					return (ptr + var->var_len);
+
				}
+
			}
+
		}
+
	}
+

+
	return ptr;
+
}
+

+
static const char *
+
ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
+
{
+
	const char *p, *end, *ret = ptr;
+
	bool found = false;
+

+
	if (*ptr == '{') {
+
		/* We need to match the variable enclosed in braces */
+
		p = ptr + 1;
+
		end = ptr + remain;
+
		while (p < end) {
+
			if (*p == '}') {
+
				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found);
+
				if (found) {
+
					/* {} must be excluded actually */
+
					ret ++;
+
					if (!*vars_found) {
+
						*vars_found = true;
+
					}
+
				}
+
				else {
+
					*out_len += 2;
+
				}
+
				break;
+
			}
+
			p ++;
+
		}
+
	}
+
	else if (*ptr != '$') {
+
		/* Not count escaped dollar sign */
+
		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
+
		if (found && !*vars_found) {
+
			*vars_found = true;
+
		}
+
		if (!found) {
+
			(*out_len) ++;
+
		}
+
	}
+
	else {
+
		ret ++;
+
		(*out_len) ++;
+
	}
+

+
	return ret;
+
}
+

+
static const char *
+
ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
+
		size_t remain, unsigned char **dest)
+
{
+
	unsigned char *d = *dest;
+
	const char *p = ptr + 1, *ret;
+
	struct ucl_variable *var;
+
	bool found = false;
+

+
	ret = ptr + 1;
+
	remain --;
+

+
	if (*p == '$') {
+
		*d++ = *p++;
+
		*dest = d;
+
		return p;
+
	}
+
	else if (*p == '{') {
+
		p ++;
+
		ret += 2;
+
		remain -= 2;
+
	}
+

+
	LL_FOREACH (parser->variables, var) {
+
		if (remain >= var->var_len) {
+
			if (memcmp (p, var->var, var->var_len) == 0) {
+
				memcpy (d, var->value, var->value_len);
+
				ret += var->var_len;
+
				d += var->value_len;
+
				found = true;
+
				break;
+
			}
+
		}
+
	}
+
	if (!found) {
+
		memcpy (d, ptr, 2);
+
		d += 2;
+
		ret --;
+
	}
+

+
	*dest = d;
+
	return ret;
+
}
+

+
static ssize_t
+
ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
+
		const char *src, size_t in_len)
+
{
+
	const char *p, *end = src + in_len;
+
	unsigned char *d;
+
	size_t out_len = 0;
+
	bool vars_found = false;
+

+
	p = src;
+
	while (p != end) {
+
		if (*p == '$') {
+
			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
+
		}
+
		else {
+
			p ++;
+
			out_len ++;
+
		}
+
	}
+

+
	if (!vars_found) {
+
		/* Trivial case */
+
		*dst = NULL;
+
		return in_len;
+
	}
+

+
	*dst = UCL_ALLOC (out_len + 1);
+
	if (*dst == NULL) {
+
		return in_len;
+
	}
+

+
	d = *dst;
+
	p = src;
+
	while (p != end) {
+
		if (*p == '$') {
+
			p = ucl_expand_single_variable (parser, p, end - p, &d);
+
		}
+
		else {
+
			*d++ = *p++;
+
		}
+
	}
+

+
	*d = '\0';
+

+
	return out_len;
+
}
+

static inline ssize_t
ucl_copy_or_store_ptr (struct ucl_parser *parser,
		const unsigned char *src, unsigned char **dst,
		const char **dst_const, size_t in_len,
-
		bool need_unescape, bool need_lowercase)
+
		bool need_unescape, bool need_lowercase, bool need_expand)
{
-
	ssize_t ret = -1;
+
	ssize_t ret = -1, tret;
+
	unsigned char *tmp;

-
	if (need_unescape || need_lowercase || !(parser->flags & UCL_PARSER_ZEROCOPY)) {
+
	if (need_unescape || need_lowercase ||
+
			(need_expand && parser->variables != NULL) ||
+
			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
		/* Copy string */
		*dst = UCL_ALLOC (in_len + 1);
		if (*dst == NULL) {
@@ -258,6 +428,16 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
		if (need_unescape) {
			ret = ucl_unescape_json_string (*dst, ret);
		}
+
		if (need_expand) {
+
			tmp = *dst;
+
			tret = ret;
+
			ret = ucl_expand_variable (parser, dst, tmp, ret);
+
			if (*dst == NULL) {
+
				/* Nothing to expand */
+
				*dst = tmp;
+
				ret = tret;
+
			}
+
		}
		*dst_const = *dst;
	}
	else {
@@ -270,7 +450,7 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,

int
ucl_maybe_parse_number (ucl_object_t *obj,
-
		const char *start, const char *end, const char **pos, bool allow_double)
+
		const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes)
{
	const char *p = start, *c = start;
	char *endptr;
@@ -387,8 +567,8 @@ ucl_maybe_parse_number (ucl_object_t *obj,
					p += 2;
					goto set_obj;
				}
-
				else if (p[1] == 'b' || p[1] == 'B') {
-
					/* Megabytes */
+
				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
+
					/* Bytes */
					if (need_double) {
						need_double = false;
						lv = dv;
@@ -402,7 +582,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
						dv *= ucl_lex_num_multiplier (*p, false);
					}
					else {
-
						lv *= ucl_lex_num_multiplier (*p, false);
+
						lv *= ucl_lex_num_multiplier (*p, number_bytes);
					}
					p ++;
					goto set_obj;
@@ -428,7 +608,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
					dv *= ucl_lex_num_multiplier (*p, false);
				}
				else {
-
					lv *= ucl_lex_num_multiplier (*p, false);
+
					lv *= ucl_lex_num_multiplier (*p, number_bytes);
				}
				p ++;
				goto set_obj;
@@ -502,7 +682,7 @@ ucl_lex_number (struct ucl_parser *parser,
	const unsigned char *pos;
	int ret;

-
	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true);
+
	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false);

	if (ret == 0) {
		chunk->remain -= pos - chunk->pos;
@@ -525,7 +705,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, bool *ucl_escape)
+
		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
{
	const unsigned char *p = chunk->pos;
	unsigned char c;
@@ -584,6 +764,9 @@ ucl_lex_json_string (struct ucl_parser *parser,
		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
			*ucl_escape = true;
		}
+
		else if (c == '$') {
+
			*var_expand = true;
+
		}
		ucl_chunk_skipc (chunk, p);
	}

@@ -603,7 +786,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, ucl_escape = false;
+
			need_unescape = false, ucl_escape = false, var_expand = false,
+
			got_content = false;
	ucl_object_t *nobj, *tobj;
	ucl_hash_t *container;
	ssize_t keylen;
@@ -632,11 +816,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
				/* The first symbol */
				c = p;
				ucl_chunk_skipc (chunk, p);
+
				got_content = true;
			}
			else if (*p == '"') {
				/* JSON style key */
				c = p + 1;
				got_quote = true;
+
				got_content = true;
				ucl_chunk_skipc (chunk, p);
			}
			else {
@@ -649,6 +835,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
			/* Parse the body of a key */
			if (!got_quote) {
				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
+
					got_content = true;
					ucl_chunk_skipc (chunk, p);
				}
				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
@@ -662,7 +849,7 @@ 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, &ucl_escape)) {
+
				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
					return false;
				}
				/* Always escape keys obtained via json */
@@ -673,10 +860,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
		}
	}

-
	if (p >= chunk->end) {
+
	if (p >= chunk->end && got_content) {
		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
		return false;
	}
+
	else if (!got_content) {
+
		return true;
+
	}

	/* We are now at the end of the key, need to parse the rest */
	while (p < chunk->end) {
@@ -716,7 +906,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
		}
	}

-
	if (p >= chunk->end) {
+
	if (p >= chunk->end && got_content) {
		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
		return false;
	}
@@ -724,7 +914,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_PARSER_KEY_LOWERCASE);
+
			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
	if (keylen == -1) {
		return false;
	}
@@ -764,7 +954,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk)
 */
static bool
ucl_parse_string_value (struct ucl_parser *parser,
-
		struct ucl_chunk *chunk)
+
		struct ucl_chunk *chunk, bool *var_expand)
{
	const unsigned char *p;
	enum {
@@ -802,6 +992,9 @@ ucl_parse_string_value (struct ucl_parser *parser,
				continue;
			}
		}
+
		else if (*p == '$') {
+
			*var_expand = true;
+
		}

		if (ucl_lex_is_atom_end (*p) || ucl_lex_is_comment (p[0], p[1])) {
			break;
@@ -828,7 +1021,8 @@ ucl_parse_string_value (struct ucl_parser *parser,
static int
ucl_parse_multiline_string (struct ucl_parser *parser,
		struct ucl_chunk *chunk, const unsigned char *term,
-
		int term_len, unsigned char const **beg)
+
		int term_len, unsigned char const **beg,
+
		bool *var_expand)
{
	const unsigned char *p, *c;
	bool newline = false;
@@ -856,6 +1050,9 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
			newline = true;
		}
		else {
+
			if (*p == '$') {
+
				*var_expand = true;
+
			}
			newline = false;
		}
		ucl_chunk_skipc (chunk, p);
@@ -878,7 +1075,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, ucl_escape = false;
+
	bool need_unescape = false, ucl_escape = false, var_expand = false;

	p = chunk->pos;

@@ -901,13 +1098,13 @@ 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, &ucl_escape)) {
+
			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
				return false;
			}
			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)) == -1) {
+
					&obj->value.sv, str_len, need_unescape, false, var_expand)) == -1) {
				return false;
			}
			obj->len = str_len;
@@ -959,13 +1156,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
						chunk->column = 0;
						chunk->line ++;
						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
-
								p - c, &c)) == 0) {
+
								p - c, &c, &var_expand)) == 0) {
							ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
							return false;
						}
						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)) == -1) {
+
							&obj->value.sv, str_len - 1, false, false, var_expand)) == -1) {
							return false;
						}
						obj->len = str_len;
@@ -1002,7 +1199,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
				/* Fallback to normal string */
			}

-
			if (!ucl_parse_string_value (parser, chunk)) {
+
			if (!ucl_parse_string_value (parser, chunk, &var_expand)) {
				return false;
			}
			/* Cut trailing spaces */
@@ -1016,11 +1213,14 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
				ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
				return false;
			}
-

-
			if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
+
			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
+
				obj->len = 0;
+
				obj->type = UCL_NULL;
+
			}
+
			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
				obj->type = UCL_STRING;
				if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
-
						&obj->value.sv, str_len, false, false)) == -1) {
+
						&obj->value.sv, str_len, false, false, var_expand)) == -1) {
					return false;
				}
				obj->len = str_len;
@@ -1124,7 +1324,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, ucl_escape = false;
+
	bool need_unescape = false, ucl_escape = false, var_expand = false;

	p = chunk->pos;

@@ -1133,7 +1333,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, &ucl_escape)) {
+
		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
			return false;
		}

@@ -1203,9 +1403,19 @@ ucl_state_machine (struct ucl_parser *parser)
	struct ucl_chunk *chunk = parser->chunks;
	struct ucl_stack *st;
	const unsigned char *p, *c = NULL, *macro_start = NULL;
+
	unsigned char *macro_escaped;
	size_t macro_len = 0;
	struct ucl_macro *macro = NULL;

+
	if (parser->top_obj == NULL) {
+
		obj = ucl_object_typed_new (UCL_OBJECT);
+
		parser->cur_obj = obj;
+
		parser->top_obj = obj;
+
		st = UCL_ALLOC (sizeof (struct ucl_stack));
+
		st->obj = obj;
+
		LL_PREPEND (parser->stack, st);
+
	}
+

	p = chunk->pos;
	while (chunk->pos < chunk->end) {
		switch (parser->state) {
@@ -1215,6 +1425,7 @@ ucl_state_machine (struct ucl_parser *parser)
			 * if we got [ or { correspondingly or can just treat new data as
			 * a key of newly created object
			 */
+
			obj = parser->top_obj;
			if (!ucl_skip_comments (parser)) {
				parser->prev_state = parser->state;
				parser->state = UCL_STATE_ERROR;
@@ -1222,7 +1433,6 @@ ucl_state_machine (struct ucl_parser *parser)
			}
			else {
				p = chunk->pos;
-
				obj = ucl_object_new ();
				if (*p == '[') {
					parser->state = UCL_STATE_VALUE;
					obj->type = UCL_ARRAY;
@@ -1235,12 +1445,7 @@ ucl_state_machine (struct ucl_parser *parser)
					if (*p == '{') {
						ucl_chunk_skipc (chunk, p);
					}
-
				};
-
				parser->cur_obj = obj;
-
				parser->top_obj = obj;
-
				st = UCL_ALLOC (sizeof (struct ucl_stack));
-
				st->obj = obj;
-
				LL_PREPEND (parser->stack, st);
+
				}
			}
			break;
		case UCL_STATE_KEY:
@@ -1305,7 +1510,8 @@ ucl_state_machine (struct ucl_parser *parser)
				/* We got macro name */
				HASH_FIND (hh, parser->macroes, c, (p - c), macro);
				if (macro == NULL) {
-
					ucl_set_err (chunk, UCL_EMACRO, "unknown macro", &parser->err);
+
					ucl_create_err (&parser->err, "error on line %d at column %d: unknown macro: '%.*s', character: '%c'",
+
								chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
					parser->state = UCL_STATE_ERROR;
					return false;
				}
@@ -1333,9 +1539,19 @@ ucl_state_machine (struct ucl_parser *parser)
				parser->state = UCL_STATE_ERROR;
				return false;
			}
-
			parser->state = parser->prev_state;
-
			if (!macro->handler (macro_start, macro_len, macro->ud)) {
-
				return false;
+
			macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
+
			parser->state = UCL_STATE_AFTER_VALUE;
+
			if (macro_escaped == macro_start) {
+
				if (!macro->handler (macro_start, macro_len, macro->ud)) {
+
					return false;
+
				}
+
			}
+
			else {
+
				if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
+
					UCL_FREE (macro_len + 1, macro_escaped);
+
					return false;
+
				}
+
				UCL_FREE (macro_len + 1, macro_escaped);
			}
			p = chunk->pos;
			break;
@@ -1381,6 +1597,22 @@ ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
}

+
void
+
ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
+
		const char *value)
+
{
+
	struct ucl_variable *new;
+

+
	new = UCL_ALLOC (sizeof (struct ucl_variable));
+
	memset (new, 0, sizeof (struct ucl_variable));
+
	new->var = strdup (var);
+
	new->var_len = strlen (var);
+
	new->value = strdup (value);
+
	new->value_len = strlen (value);
+

+
	LL_PREPEND (parser->variables, new);
+
}
+

bool
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
		size_t len)
modified external/libucl/src/ucl_util.c
@@ -224,7 +224,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
ucl_object_t*
ucl_parser_get_object (struct ucl_parser *parser)
{
-
	if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) {
+
	if (parser->state != UCL_STATE_ERROR) {
		return ucl_object_ref (parser->top_obj);
	}

@@ -238,6 +238,7 @@ ucl_parser_free (struct ucl_parser *parser)
	struct ucl_macro *macro, *mtmp;
	struct ucl_chunk *chunk, *ctmp;
	struct ucl_pubkey *key, *ktmp;
+
	struct ucl_variable *var, *vtmp;

	if (parser->top_obj != NULL) {
		ucl_object_unref (parser->top_obj);
@@ -257,6 +258,11 @@ ucl_parser_free (struct ucl_parser *parser)
	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
		UCL_FREE (sizeof (struct ucl_pubkey), key);
	}
+
	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
+
		free (var->value);
+
		free (var->var);
+
		UCL_FREE (sizeof (struct ucl_variable), var);
+
	}

	if (parser->err != NULL) {
		utstring_free(parser->err);
@@ -316,7 +322,7 @@ ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
	struct ucl_curl_cbdata *cbdata = ud;
	size_t realsize = size * nmemb;

-
	cbdata->buf = g_realloc (cbdata->buf, cbdata->buflen + realsize + 1);
+
	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
	if (cbdata->buf == NULL) {
		return 0;
	}
@@ -404,8 +410,8 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, UT
		ucl_create_err (err, "error fetching URL %s: %s",
				url, curl_easy_strerror (r));
		curl_easy_cleanup (curl);
-
		if (buf != NULL) {
-
			free (buf);
+
		if (cbdata.buf) {
+
			free (cbdata.buf);
		}
		return false;
	}
@@ -438,19 +444,26 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
				filename, strerror (errno));
		return false;
	}
-
	if ((fd = open (filename, O_RDONLY)) == -1) {
-
		ucl_create_err (err, "cannot open file %s: %s",
-
				filename, strerror (errno));
-
		return false;
+
	if (st.st_size == 0) {
+
		/* Do not map empty files */
+
		*buf = "";
+
		*buflen = 0;
	}
-
	if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+
	else {
+
		if ((fd = open (filename, O_RDONLY)) == -1) {
+
			ucl_create_err (err, "cannot open file %s: %s",
+
					filename, strerror (errno));
+
			return false;
+
		}
+
		if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+
			close (fd);
+
			ucl_create_err (err, "cannot mmap file %s: %s",
+
					filename, strerror (errno));
+
			return false;
+
		}
+
		*buflen = st.st_size;
		close (fd);
-
		ucl_create_err (err, "cannot mmap file %s: %s",
-
				filename, strerror (errno));
-
		return false;
	}
-
	*buflen = st.st_size;
-
	close (fd);

	return true;
}
@@ -542,10 +555,14 @@ ucl_include_url (const unsigned char *data, size_t len,
			ucl_create_err (&parser->err, "cannot verify url %s: %s",
							urlbuf,
							ERR_error_string (ERR_get_error (), NULL));
-
			munmap (sigbuf, siglen);
+
			if (siglen > 0) {
+
				munmap (sigbuf, siglen);
+
			}
			return false;
		}
-
		munmap (sigbuf, siglen);
+
		if (siglen > 0) {
+
			munmap (sigbuf, siglen);
+
		}
#endif
	}

@@ -606,10 +623,14 @@ ucl_include_file (const unsigned char *data, size_t len,
			ucl_create_err (&parser->err, "cannot verify file %s: %s",
							filebuf,
							ERR_error_string (ERR_get_error (), NULL));
-
			munmap (sigbuf, siglen);
+
			if (siglen > 0) {
+
				munmap (sigbuf, siglen);
+
			}
			return false;
		}
-
		munmap (sigbuf, siglen);
+
		if (siglen > 0) {
+
			munmap (sigbuf, siglen);
+
		}
#endif
	}

@@ -622,7 +643,9 @@ ucl_include_file (const unsigned char *data, size_t len,
			UCL_FREE (sizeof (struct ucl_chunk), chunk);
		}
	}
-
	munmap (buf, buflen);
+
	if (buflen > 0) {
+
		munmap (buf, buflen);
+
	}

	return res;
}
@@ -682,7 +705,9 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)

	ret = ucl_parser_add_chunk (parser, buf, len);

-
	munmap (buf, len);
+
	if (len > 0) {
+
		munmap (buf, len);
+
	}

	return ret;
}
@@ -845,12 +870,14 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags
			if (flags & UCL_STRING_PARSE_BOOLEAN) {
				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
-
							flags & UCL_STRING_PARSE_DOUBLE);
+
							flags & UCL_STRING_PARSE_DOUBLE,
+
							flags & UCL_STRING_PARSE_BYTES);
				}
			}
			else {
				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
-
						flags & UCL_STRING_PARSE_DOUBLE);
+
						flags & UCL_STRING_PARSE_DOUBLE,
+
						flags & UCL_STRING_PARSE_BYTES);
			}
		}
	}
@@ -875,6 +902,17 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
		top->type = UCL_OBJECT;
	}

+
	if (top->type != UCL_OBJECT) {
+
		/* It is possible to convert NULL type to an object */
+
		if (top->type == UCL_NULL) {
+
			top->type = UCL_OBJECT;
+
		}
+
		else {
+
			/* Refuse converting of other object types */
+
			return top;
+
		}
+
	}
+

	if (top->value.ov == NULL) {
		top->value.ov = ucl_hash_create ();
	}