Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to latest version
Baptiste Daroussin committed 10 years ago
commit 3433197a8aea3a34fe0d46bb40bb471124d56156
parent 239a32f
57 files changed +2258 -314
modified external/libucl/Makefile.am
@@ -8,4 +8,74 @@ if LUA_SUB
  LUA_SUBDIR = lua
endif

-
SUBDIRS = src tests utils doc $(LUA_SUBDIR)

\ No newline at end of file
+
COVERAGE_INFO_FILE = $(top_builddir)/coverage.info
+
COVERAGE_REPORT_DIR = $(top_builddir)/coverage
+

+
.PHONY = coverage-requirement-check clean-coverage-report
+

+
coverage-requirement-check:
+
	@if test ! -e $(GCOV); then \
+
		echo "Cannot find $(GCOV). Please install gcov."; \
+
		exit 1; \
+
	fi
+

+
coverage: coverage-requirement-check clean-coverage coverage-build coverage-check coverage-report
+
	@echo "Please execute 'make clean' before 'make' or 'make check' to remove instrumented object files(compiled with -O0 etc.). Note that 'make clean' also remove coverage data."
+

+
coverage-build: coverage-requirement-check
+
	@if test `find $(top_builddir) -name "*.gcno" | wc -l` -eq 0; then \
+
		echo "Start to remove old non-instrumented object files..."; \
+
		$(MAKE) $(AM_MAKEFLAGS) clean; \
+
		echo "Successfully removed old non-instrumented object files."; \
+
	fi
+
	@echo "Start to build libraries with coverage options..."
+
	$(MAKE) $(AM_MAKEFLAGS) \
+
		CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \
+
		CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \
+
		LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \
+
		LIBS="$(LIBS) $(COVERAGE_LIBS)"
+
	@echo "Successfully built libraries with coverage options."
+

+
coverage-check: coverage-requirement-check
+
	@echo "Start to run tests with instrumented libraries..."
+
	$(MAKE) $(AM_MAKEFLAGS) check \
+
		CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \
+
		CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \
+
		LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \
+
		LIBS="$(LIBS) $(COVERAGE_LIBS)"
+
	@echo "Successfully run tests with instrumented libraries."
+

+
coverage-lcov: coverage-check coverage-requirement-check
+
	$(LCOV) --capture \
+
		--directory "$(top_builddir)/" \
+
		--output-file $(COVERAGE_INFO_FILE) \
+
		--gcov-tool $(GCOV) \
+
		--compat-libtool --checksum
+
	$(LCOV) --extract $(COVERAGE_INFO_FILE) `pwd`/src/ucl_\* \
+
		--output-file $(COVERAGE_INFO_FILE)
+

+
coverage-report: coverage-lcov
+
	@echo "Start to create coverage reports..."
+
	$(GENHTML) --prefix "$(top_srcdir)" \
+
		--output-directory $(COVERAGE_REPORT_DIR) \
+
		--title $(PACKAGE_NAME) \
+
		--legend --show-details \
+
		$(GENHTML_OPTIONS) \
+
		$(COVERAGE_INFO_FILE)
+
	@echo "Successfully created coverage reports into $(COVERAGE_REPORT_DIR) directory."
+

+
clean-coverage-report:
+
	-rm -rf $(COVERAGE_INFO_FILE)
+
	-rm -rf $(COVERAGE_REPORT_DIR)
+

+
clean-coverage: clean-coverage-report
+
	-$(LCOV) --gcov-tool $(GCOV) --zerocounters --directory $(top_builddir)
+
	@if xargs --version 2>/dev/null; then \
+
		find $(top_builddir) -name "*.gcno" | xargs --no-run-if-empty rm; \
+
	else \
+
		find $(top_builddir) -name "*.gcno" | xargs rm; \
+
	fi
+

+
clean-local: clean-coverage
+

+
SUBDIRS = src tests utils doc $(LUA_SUBDIR)
modified external/libucl/README.md
@@ -1,6 +1,6 @@
# LIBUCL

-
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)
+
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)

**Table of Contents**  *generated with [DocToc](http://doctoc.herokuapp.com/)*

modified external/libucl/configure.ac
@@ -1,7 +1,7 @@
m4_define([maj_ver], [0])
-
m4_define([med_ver], [7])
-
m4_define([min_ver], [3])
-
m4_define([so_version], [5:0:2])
+
m4_define([med_ver], [8])
+
m4_define([min_ver], [0])
+
m4_define([so_version], [6:0:0])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])

AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
@@ -173,6 +173,8 @@ AC_LINK_IFELSE([
	AC_MSG_WARN([Libucl references could be thread-unsafe because atomic builtins are missing])
])

+
AX_CODE_COVERAGE
+

AC_CONFIG_FILES(Makefile \
	src/Makefile \
	lua/Makefile
modified external/libucl/include/ucl.h
@@ -147,11 +147,13 @@ typedef enum ucl_emitter {
 * UCL still has to perform copying implicitly.
 */
typedef enum ucl_parser_flags {
-
	UCL_PARSER_DEFAULT = 0x0,       /**< No special flags */
-
	UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
-
	UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
-
	UCL_PARSER_NO_TIME = 0x4, /**< Do not parse time and treat time values as strings */
-
	UCL_PARSER_NO_IMPLICIT_ARRAYS = 0x8 /** Create explicit arrays instead of implicit ones */
+
	UCL_PARSER_DEFAULT = 0,       /**< No special flags */
+
	UCL_PARSER_KEY_LOWERCASE = (1 << 0), /**< Convert all keys to lower case */
+
	UCL_PARSER_ZEROCOPY = (1 << 1), /**< Parse input in zero-copy mode if possible */
+
	UCL_PARSER_NO_TIME = (1 << 2), /**< Do not parse time and treat time values as strings */
+
	UCL_PARSER_NO_IMPLICIT_ARRAYS = (1 << 3), /** Create explicit arrays instead of implicit ones */
+
	UCL_PARSER_SAVE_COMMENTS = (1 << 4), /** Save comments in the parser context */
+
	UCL_PARSER_DISABLE_MACRO = (1 << 5) /** Treat macros as comments */
} ucl_parser_flags_t;

/**
@@ -159,17 +161,17 @@ typedef enum ucl_parser_flags {
 */
typedef enum ucl_string_flags {
	UCL_STRING_RAW = 0x0,     /**< Treat string as is */
-
	UCL_STRING_ESCAPE = 0x1,  /**< Perform JSON escape */
-
	UCL_STRING_TRIM = 0x2,    /**< Trim leading and trailing whitespaces */
-
	UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< Parse passed string and detect boolean */
-
	UCL_STRING_PARSE_INT = 0x8,    /**< Parse passed string and detect integer number */
-
	UCL_STRING_PARSE_DOUBLE = 0x10,    /**< Parse passed string and detect integer or float number */
-
	UCL_STRING_PARSE_TIME = 0x20, /**< Parse time strings */
+
	UCL_STRING_ESCAPE = (1 << 0),  /**< Perform JSON escape */
+
	UCL_STRING_TRIM = (1 << 1),    /**< Trim leading and trailing whitespaces */
+
	UCL_STRING_PARSE_BOOLEAN = (1 << 2),    /**< Parse passed string and detect boolean */
+
	UCL_STRING_PARSE_INT = (1 << 3),    /**< Parse passed string and detect integer number */
+
	UCL_STRING_PARSE_DOUBLE = (1 << 4),    /**< Parse passed string and detect integer or float number */
+
	UCL_STRING_PARSE_TIME = (1 << 5), /**< Parse time strings */
	UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE|UCL_STRING_PARSE_TIME,  /**<
									Parse passed string and detect number */
	UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER,   /**<
									Parse passed string (and detect booleans and numbers) */
-
	UCL_STRING_PARSE_BYTES = 0x40  /**< Treat numbers as bytes */
+
	UCL_STRING_PARSE_BYTES = (1 << 6)  /**< Treat numbers as bytes */
} ucl_string_flags_t;

/**
@@ -286,10 +288,12 @@ UCL_EXTERN ucl_object_t* ucl_object_new_full (ucl_type_t type, unsigned priority
/**
 * Create new object with userdata dtor
 * @param dtor destructor function
+
 * @param emitter emitter for userdata
+
 * @param ptr opaque pointer
 * @return new object
 */
UCL_EXTERN ucl_object_t* ucl_object_new_userdata (ucl_userdata_dtor dtor,
-
		ucl_userdata_emitter emitter) UCL_WARN_UNUSED_RESULT;
+
		ucl_userdata_emitter emitter, void *ptr) UCL_WARN_UNUSED_RESULT;

/**
 * Perform deep copy of an object copying everything
@@ -306,6 +310,21 @@ UCL_EXTERN ucl_object_t * ucl_object_copy (const ucl_object_t *other)
UCL_EXTERN ucl_type_t ucl_object_type (const ucl_object_t *obj);

/**
+
 * Converts ucl object type to its string representation
+
 * @param type type of object
+
 * @return constant string describing type
+
 */
+
UCL_EXTERN const char * ucl_object_type_to_string (ucl_type_t type);
+

+
/**
+
 * Converts string that represents ucl type to real ucl type enum
+
 * @param input C string with name of type
+
 * @param res resulting target
+
 * @return true if `input` is a name of type stored in `res`
+
 */
+
UCL_EXTERN bool ucl_object_string_to_type (const char *input, ucl_type_t *res);
+

+
/**
 * 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)
@@ -735,6 +754,19 @@ UCL_EXTERN int ucl_object_compare (const ucl_object_t *o1,
		const ucl_object_t *o2);

/**
+
 * Compare objects `o1` and `o2` useful for sorting
+
 * @param o1 the first object
+
 * @param o2 the second object
+
 * @return values >0, 0 and <0 if `o1` is more than, equal and less than `o2`.
+
 * The order of comparison:
+
 * 1) Type of objects
+
 * 2) Size of objects
+
 * 3) Content of objects
+
 */
+
UCL_EXTERN int ucl_object_compare_qsort (const ucl_object_t **o1,
+
		const ucl_object_t **o2);
+

+
/**
 * Sort UCL array using `cmp` compare function
 * @param ar
 * @param cmp
@@ -1076,6 +1108,23 @@ UCL_EXTERN void ucl_parser_clear_error(struct ucl_parser *parser);
UCL_EXTERN void ucl_parser_free (struct ucl_parser *parser);

/**
+
 * Get constant opaque pointer to comments structure for this parser. Increase
+
 * refcount to prevent this object to be destroyed on parser's destruction
+
 * @param parser parser structure
+
 * @return ucl comments pointer or NULL
+
 */
+
UCL_EXTERN const ucl_object_t * ucl_parser_get_comments (struct ucl_parser *parser);
+

+
/**
+
 * Utility function to find a comment object for the specified object in the input
+
 * @param comments comments object
+
 * @param srch search object
+
 * @return string comment enclosed in ucl_object_t
+
 */
+
UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments,
+
		const ucl_object_t *srch);
+

+
/**
 * Add new public key to parser for signatures check
 * @param parser parser object
 * @param key PEM representation of a key
@@ -1156,8 +1205,8 @@ struct ucl_emitter_context {
	unsigned int indent;
	/** Top level object */
	const ucl_object_t *top;
-
	/** The rest of context */
-
	unsigned char data[1];
+
	/** Optional comments */
+
	const ucl_object_t *comments;
};

/**
@@ -1187,11 +1236,13 @@ UCL_EXTERN unsigned char *ucl_object_emit_len (const ucl_object_t *obj,
 * @param emit_type if type is #UCL_EMIT_JSON then emit json, if type is
 * #UCL_EMIT_CONFIG then emit config like object
 * @param emitter a set of emitter functions
+
 * @param comments optional comments for the parser
 * @return dump of an object (must be freed after using) or NULL in case of error
 */
UCL_EXTERN bool ucl_object_emit_full (const ucl_object_t *obj,
		enum ucl_emitter emit_type,
-
		struct ucl_emitter_functions *emitter);
+
		struct ucl_emitter_functions *emitter,
+
		const ucl_object_t *comments);

/**
 * Start streamlined UCL object emitter
@@ -1280,6 +1331,9 @@ enum ucl_schema_error_code {
	UCL_SCHEMA_MISSING_PROPERTY,/**< one or more missing properties */
	UCL_SCHEMA_CONSTRAINT,      /**< constraint found */
	UCL_SCHEMA_MISSING_DEPENDENCY, /**< missing dependency */
+
	UCL_SCHEMA_EXTERNAL_REF_MISSING, /**< cannot fetch external ref */
+
	UCL_SCHEMA_EXTERNAL_REF_INVALID, /**< invalid external ref */
+
	UCL_SCHEMA_INTERNAL_ERROR, /**< something bad happened */
	UCL_SCHEMA_UNKNOWN          /**< generic error */
};

@@ -1303,6 +1357,37 @@ struct ucl_schema_error {
UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
		const ucl_object_t *obj, struct ucl_schema_error *err);

+
/**
+
 * Validate object `obj` using schema object `schema` and root schema at `root`.
+
 * @param schema schema object
+
 * @param obj object to validate
+
 * @param root root schema object
+
 * @param err error pointer, if this parameter is not NULL and error has been
+
 * occured, then `err` is filled with the exact error definition.
+
 * @return true if `obj` is valid using `schema`
+
 */
+
UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
+
		const ucl_object_t *obj,
+
		const ucl_object_t *root,
+
		struct ucl_schema_error *err);
+

+
/**
+
 * Validate object `obj` using schema object `schema` and root schema at `root`
+
 * using some external references provided.
+
 * @param schema schema object
+
 * @param obj object to validate
+
 * @param root root schema object
+
 * @param ext_refs external references (might be modified during validation)
+
 * @param err error pointer, if this parameter is not NULL and error has been
+
 * occured, then `err` is filled with the exact error definition.
+
 * @return true if `obj` is valid using `schema`
+
 */
+
UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema,
+
		const ucl_object_t *obj,
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_refs,
+
		struct ucl_schema_error *err);
+

/** @} */

#ifdef  __cplusplus
modified external/libucl/lua/lua_ucl.c
@@ -29,6 +29,7 @@
#include "ucl_internal.h"
#include "lua_ucl.h"
#include <strings.h>
+
#include <zconf.h>

/***
 * @module ucl
@@ -421,9 +422,7 @@ ucl_object_lua_fromelt (lua_State *L, int idx)
					fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);

					obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
-
							lua_ucl_userdata_emitter);
-
					obj->type = UCL_USERDATA;
-
					obj->value.ud = (void *)fd;
+
							lua_ucl_userdata_emitter, (void *)fd);
				}
			}
		}
@@ -514,6 +513,17 @@ lua_ucl_object_get (lua_State *L, int index)
	return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
}

+
static void
+
lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
+
{
+
	ucl_object_t **pobj;
+

+
	pobj = lua_newuserdata (L, sizeof (*pobj));
+
	*pobj = obj;
+
	luaL_getmetatable (L, OBJECT_META);
+
	lua_setmetatable (L, -2);
+
}
+

/***
 * @method parser:parse_file(name)
 * Parse UCL object from file.
@@ -629,17 +639,14 @@ static int
lua_ucl_parser_get_object_wrapped (lua_State *L)
{
	struct ucl_parser *parser;
-
	ucl_object_t *obj, **pobj;
+
	ucl_object_t *obj;
	int ret = 1;

	parser = lua_ucl_parser_get (L, 1);
	obj = ucl_parser_get_object (parser);

	if (obj != NULL) {
-
		pobj = lua_newuserdata (L, sizeof (*pobj));
-
		*pobj = obj;
-
		luaL_getmetatable (L, OBJECT_META);
-
		lua_setmetatable (L, -2);
+
		lua_ucl_push_opaque (L, obj);
	}
	else {
		lua_pushnil (L);
@@ -806,19 +813,21 @@ lua_ucl_object_tostring (lua_State *L)
}

/***
-
 * @method object:validate(schema, path)
+
 * @method object:validate(schema[, path[, ext_refs]])
 * Validates the given ucl object using schema object represented as another
 * opaque ucl object. You can also specify path in the form `#/path/def` to
 * specify the specific schema element to perform validation.
 *
 * @param {ucl.object} schema schema object
 * @param {string} path optional path for validation procedure
-
 * @return {result,err} two values: boolean result and the corresponding error
+
 * @return {result,err} two values: boolean result and the corresponding
+
 * error, if `ext_refs` are also specified, then they are returned as opaque
+
 * ucl object as {result,err,ext_refs}
 */
static int
lua_ucl_object_validate (lua_State *L)
{
-
	ucl_object_t *obj, *schema;
+
	ucl_object_t *obj, *schema, *ext_refs = NULL;
	const ucl_object_t *schema_elt;
	bool res = false;
	struct ucl_schema_error err;
@@ -828,10 +837,25 @@ lua_ucl_object_validate (lua_State *L)
	schema = lua_ucl_object_get (L, 2);

	if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
-
		if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TSTRING) {
-
			path = lua_tostring (L, 3);
-
			if (path[0] == '#') {
-
				path ++;
+
		if (lua_gettop (L) > 2) {
+
			if (lua_type (L, 3) == LUA_TSTRING) {
+
				path = lua_tostring (L, 3);
+
				if (path[0] == '#') {
+
					path++;
+
				}
+
			}
+
			else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) ==
+
						LUA_TTABLE) {
+
				/* External refs */
+
				ext_refs = lua_ucl_object_get (L, 3);
+
			}
+

+
			if (lua_gettop (L) > 3) {
+
				if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) ==
+
						LUA_TTABLE) {
+
					/* External refs */
+
					ext_refs = lua_ucl_object_get (L, 4);
+
				}
			}
		}

@@ -844,26 +868,33 @@ lua_ucl_object_validate (lua_State *L)
		}

		if (schema_elt) {
-
			res = ucl_object_validate (schema_elt, obj, &err);
+
			res = ucl_object_validate_root_ext (schema_elt, obj, schema,
+
					ext_refs, &err);

			if (res) {
				lua_pushboolean (L, res);
				lua_pushnil (L);
+

+
				if (ext_refs) {
+
					lua_ucl_push_opaque (L, ext_refs);
+
				}
			}
			else {
				lua_pushboolean (L, res);
				lua_pushfstring (L, "validation error: %s", err.msg);
+

+
				if (ext_refs) {
+
					lua_ucl_push_opaque (L, ext_refs);
+
				}
			}
		}
		else {
			lua_pushboolean (L, res);

-
			if (path) {
-
				lua_pushfstring (L, "cannot find the requested path: %s", path);
-
			}
-
			else {
-
				/* Should not be reached */
-
				lua_pushstring (L, "unknown error");
+
			lua_pushfstring (L, "cannot find the requested path: %s", path);
+

+
			if (ext_refs) {
+
				lua_ucl_push_opaque (L, ext_refs);
			}
		}
	}
@@ -872,6 +903,10 @@ lua_ucl_object_validate (lua_State *L)
		lua_pushstring (L, "invalid object or schema");
	}

+
	if (ext_refs) {
+
		return 3;
+
	}
+

	return 2;
}

modified external/libucl/src/ucl_emitter.c
@@ -362,6 +362,7 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
	const struct ucl_emitter_functions *func = ctx->func;
	bool flag;
	struct ucl_object_userdata *ud;
+
	const ucl_object_t *comment = NULL, *cur_comment;
	const char *ud_out = "";

	if (ctx->id != UCL_EMIT_CONFIG && !first) {
@@ -379,6 +380,25 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,

	ucl_add_tabs (func, ctx->indent, compact);

+
	if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
+
		comment = ucl_object_find_keyl (ctx->comments, (const char *)&obj,
+
				sizeof (void *));
+

+
		if (comment) {
+
			if (!(comment->flags & UCL_OBJECT_INHERITED)) {
+
				DL_FOREACH (comment, cur_comment) {
+
					func->ucl_emitter_append_len (cur_comment->value.sv,
+
							cur_comment->len,
+
							func->ud);
+
					func->ucl_emitter_append_character ('\n', 1, func->ud);
+
					ucl_add_tabs (func, ctx->indent, compact);
+
				}
+

+
				comment = NULL;
+
			}
+
		}
+
	}
+

	switch (obj->type) {
	case UCL_INT:
		ucl_emitter_print_key (print_key, ctx, obj, compact);
@@ -438,6 +458,19 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
		ucl_emitter_finish_object (ctx, obj, compact, !print_key);
		break;
	}
+

+
	if (comment) {
+
		DL_FOREACH (comment, cur_comment) {
+
			func->ucl_emitter_append_len (cur_comment->value.sv,
+
					cur_comment->len,
+
					func->ud);
+
			func->ucl_emitter_append_character ('\n', 1, func->ud);
+

+
			if (cur_comment->next) {
+
				ucl_add_tabs (func, ctx->indent, compact);
+
			}
+
		}
+
	}
}

/*
@@ -605,10 +638,10 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
	}

	func = ucl_object_emit_memory_funcs ((void **)&res);
-
	s = func->ud;

	if (func != NULL) {
-
		ucl_object_emit_full (obj, emit_type, func);
+
		s = func->ud;
+
		ucl_object_emit_full (obj, emit_type, func, NULL);

		if (outlen != NULL) {
			*outlen = s->i;
@@ -622,7 +655,8 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,

bool
ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
-
		struct ucl_emitter_functions *emitter)
+
		struct ucl_emitter_functions *emitter,
+
		const ucl_object_t *comments)
{
	const struct ucl_emitter_context *ctx;
	struct ucl_emitter_context my_ctx;
@@ -634,6 +668,7 @@ ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
		my_ctx.func = emitter;
		my_ctx.indent = 0;
		my_ctx.top = obj;
+
		my_ctx.comments = comments;

		my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
		res = true;
modified external/libucl/src/ucl_emitter_streamline.c
@@ -38,12 +38,20 @@ struct ucl_emitter_streamline_stack {

struct ucl_emitter_context_streamline {
	/* Inherited from the main context */
+
	/** Name of emitter (e.g. json, compact_json) */
	const char *name;
+
	/** Unique id (e.g. UCL_EMIT_JSON for standard emitters */
	int id;
+
	/** A set of output functions */
	const struct ucl_emitter_functions *func;
+
	/** A set of output operations */
	const struct ucl_emitter_operations *ops;
-
	unsigned int ident;
+
	/** Current amount of indent tabs */
+
	unsigned int indent;
+
	/** Top level object */
	const ucl_object_t *top;
+
	/** Optional comments */
+
	const ucl_object_t *comments;

	/* Streamline specific fields */
	struct ucl_emitter_streamline_stack *containers;
modified external/libucl/src/ucl_hash.c
@@ -247,7 +247,7 @@ ucl_hash_create (bool ignore_case)
	return new;
}

-
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
+
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
{
	const ucl_object_t *cur, *tmp;

modified external/libucl/src/ucl_hash.h
@@ -31,8 +31,8 @@
struct ucl_hash_node_s;
typedef struct ucl_hash_node_s ucl_hash_node_t;

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


@@ -51,7 +51,7 @@ ucl_hash_t* ucl_hash_create (bool ignore_case);
/**
 * Deinitializes the hashtable.
 */
-
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
+
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func);

/**
 * Inserts an element in the the hashtable.
modified external/libucl/src/ucl_internal.h
@@ -211,6 +211,8 @@ struct ucl_parser {
	struct ucl_variable *variables;
	ucl_variable_handler var_handler;
	void *var_data;
+
	ucl_object_t *comments;
+
	ucl_object_t *last_comment;
	UT_string *err;
};

@@ -524,6 +526,34 @@ void ucl_emitter_print_key_msgpack (bool print_key,
		const ucl_object_t *obj);

/**
+
 * Fetch URL into a buffer
+
 * @param url url to fetch
+
 * @param buf pointer to buffer (must be freed by callee)
+
 * @param buflen pointer to buffer length
+
 * @param err pointer to error argument
+
 * @param must_exist fail if cannot find a url
+
 */
+
bool ucl_fetch_url (const unsigned char *url,
+
		unsigned char **buf,
+
		size_t *buflen,
+
		UT_string **err,
+
		bool must_exist);
+

+
/**
+
 * Fetch a file and save results to the memory buffer
+
 * @param filename filename to fetch
+
 * @param len length of filename
+
 * @param buf target buffer
+
 * @param buflen target length
+
 * @return
+
 */
+
bool ucl_fetch_file (const unsigned char *filename,
+
		unsigned char **buf,
+
		size_t *buflen,
+
		UT_string **err,
+
		bool must_exist);
+

+
/**
 * Add new element to an object using the current merge strategy and priority
 * @param parser
 * @param nobj
modified external/libucl/src/ucl_msgpack.c
@@ -113,19 +113,19 @@ ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, int64_t val)
			len = 1;
			buf[0] = mask_positive & val;
		}
-
		else if (val <= 0xff) {
+
		else if (val <= UINT8_MAX) {
			len = 2;
			buf[0] = uint8_ch;
			buf[1] = val & 0xff;
		}
-
		else if (val <= 0xffff) {
+
		else if (val <= UINT16_MAX) {
			uint16_t v = TO_BE16 (val);

			len = 3;
			buf[0] = uint16_ch;
			memcpy (&buf[1], &v, sizeof (v));
		}
-
		else if (val <= 0xffffffff) {
+
		else if (val <= UINT32_MAX) {
			uint32_t v = TO_BE32 (val);

			len = 5;
@@ -149,19 +149,20 @@ ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, int64_t val)
			len = 1;
			buf[0] = (mask_negative | uval) & 0xff;
		}
-
		else if (uval <= 0xff) {
+
		else if (uval <= INT8_MAX) {
+
			uint8_t v = (uint8_t)val;
			len = 2;
			buf[0] = int8_ch;
-
			buf[1] = (unsigned char)val;
+
			buf[1] = v;
		}
-
		else if (uval <= 0xffff) {
+
		else if (uval <= INT16_MAX) {
			uint16_t v = TO_BE16 (val);

			len = 3;
			buf[0] = int16_ch;
			memcpy (&buf[1], &v, sizeof (v));
		}
-
		else if (uval <= 0xffffffff) {
+
		else if (uval <= INT32_MAX) {
			uint32_t v = TO_BE32 (val);

			len = 5;
@@ -750,7 +751,7 @@ ucl_msgpack_get_parser_from_type (unsigned char t)
		shift = CHAR_BIT - parsers[i].prefixlen;
		mask = parsers[i].prefix >> shift;

-
		if (mask == (t >> shift)) {
+
		if (mask == (((unsigned int)t) >> shift)) {
			return &parsers[i];
		}
	}
@@ -969,8 +970,8 @@ ucl_msgpack_consume (struct ucl_parser *parser)
		finish_array_value,
		error_state
	} state = read_type, next_state = error_state;
-
	struct ucl_msgpack_parser *obj_parser;
-
	uint64_t len;
+
	struct ucl_msgpack_parser *obj_parser = NULL;
+
	uint64_t len = 0;
	ssize_t ret, remain, keylen = 0;
#ifdef MSGPACK_DEBUG_PARSER
	uint64_t i;
@@ -1418,6 +1419,10 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
		const unsigned char *pos, size_t remain)
{
	ucl_object_t *obj;
+
	int8_t iv8;
+
	int16_t iv16;
+
	int32_t iv32;
+
	int64_t iv64;

	if (len > remain) {
		return -1;
@@ -1439,11 +1444,14 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
		len = 1;
		break;
	case msgpack_int8:
-
		obj->value.iv = (signed char)*pos;
+
		memcpy (&iv8, pos, sizeof (iv8));
+
		obj->value.iv = iv8;
		len = 1;
		break;
	case msgpack_int16:
-
		obj->value.iv = FROM_BE16 (*(int16_t *)pos);
+
		memcpy (&iv16, pos, sizeof (iv16));
+
		iv16 = FROM_BE16 (iv16);
+
		obj->value.iv = iv16;
		len = 2;
		break;
	case msgpack_uint16:
@@ -1451,7 +1459,9 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
		len = 2;
		break;
	case msgpack_int32:
-
		obj->value.iv = FROM_BE32 (*(int32_t *)pos);
+
		memcpy (&iv32, pos, sizeof (iv32));
+
		iv32 = FROM_BE32 (iv32);
+
		obj->value.iv = iv32;
		len = 4;
		break;
	case msgpack_uint32:
@@ -1459,7 +1469,9 @@ ucl_msgpack_parse_int (struct ucl_parser *parser,
		len = 4;
		break;
	case msgpack_int64:
-
		obj->value.iv = FROM_BE64 (*(int64_t *)pos);
+
		memcpy (&iv64, pos, sizeof (iv64));
+
		iv64 = FROM_BE64 (iv64);
+
		obj->value.iv = iv64;
		len = 8;
		break;
	case msgpack_uint64:
modified external/libucl/src/ucl_parser.c
@@ -89,6 +89,39 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
	parser->err_code = code;
}

+
static void
+
ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
+
{
+
	ucl_object_t *nobj;
+

+
	if (len > 0 && begin != NULL) {
+
		nobj = ucl_object_fromstring_common (begin, len, 0);
+

+
		if (parser->last_comment) {
+
			/* We need to append data to an existing object */
+
			DL_APPEND (parser->last_comment, nobj);
+
		}
+
		else {
+
			parser->last_comment = nobj;
+
		}
+
	}
+
}
+

+
static void
+
ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
+
{
+
	if (parser->last_comment) {
+
		ucl_object_insert_key (parser->comments, parser->last_comment,
+
				(const char *)&obj, sizeof (void *), true);
+

+
		if (before) {
+
			parser->last_comment->flags |= UCL_OBJECT_INHERITED;
+
		}
+

+
		parser->last_comment = NULL;
+
	}
+
}
+

/**
 * Skip all comments from the current pos resolving nested and multiline comments
 * @param parser
@@ -98,7 +131,7 @@ static bool
ucl_skip_comments (struct ucl_parser *parser)
{
	struct ucl_chunk *chunk = parser->chunks;
-
	const unsigned char *p;
+
	const unsigned char *p, *beg = NULL;
	int comments_nested = 0;
	bool quoted = false;

@@ -108,9 +141,17 @@ start:
	if (chunk->remain > 0 && *p == '#') {
		if (parser->state != UCL_STATE_SCOMMENT &&
				parser->state != UCL_STATE_MCOMMENT) {
+
			beg = p;
+

			while (p < chunk->end) {
				if (*p == '\n') {
+
					if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+
						ucl_save_comment (parser, beg, p - beg);
+
						beg = NULL;
+
					}
+

					ucl_chunk_skipc (chunk, p);
+

					goto start;
				}
				ucl_chunk_skipc (chunk, p);
@@ -119,6 +160,7 @@ start:
	}
	else if (chunk->remain >= 2 && *p == '/') {
		if (p[1] == '*') {
+
			beg = p;
			ucl_chunk_skipc (chunk, p);
			comments_nested ++;
			ucl_chunk_skipc (chunk, p);
@@ -134,6 +176,11 @@ start:
						if (*p == '/') {
							comments_nested --;
							if (comments_nested == 0) {
+
								if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+
									ucl_save_comment (parser, beg, p - beg + 1);
+
									beg = NULL;
+
								}
+

								ucl_chunk_skipc (chunk, p);
								goto start;
							}
@@ -147,6 +194,7 @@ start:
						continue;
					}
				}
+

				ucl_chunk_skipc (chunk, p);
			}
			if (comments_nested != 0) {
@@ -157,6 +205,10 @@ start:
		}
	}

+
	if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
+
		ucl_save_comment (parser, beg, p - beg);
+
	}
+

	return true;
}

@@ -451,6 +503,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
	size_t out_len = 0;
	bool vars_found = false;

+
	if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+
		*dst = NULL;
+
		return in_len;
+
	}
+

	p = src;
	while (p != end) {
		if (*p == '$') {
@@ -590,12 +647,14 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
	}

	st = UCL_ALLOC (sizeof (struct ucl_stack));
+

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

	st->obj = obj;
	st->level = level;
	LL_PREPEND (parser->stack, st);
@@ -1092,6 +1151,7 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj

	parser->stack->obj->value.ov = container;
	parser->cur_obj = nobj;
+
	ucl_attach_comment (parser, nobj, false);

	return true;
}
@@ -1120,7 +1180,10 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,

	if (*p == '.') {
		/* It is macro actually */
-
		ucl_chunk_skipc (chunk, p);
+
		if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
+
			ucl_chunk_skipc (chunk, p);
+
		}
+

		parser->prev_state = parser->state;
		parser->state = UCL_STATE_MACRO_NAME;
		*end_of_object = false;
@@ -1461,6 +1524,7 @@ ucl_parser_get_container (struct ucl_parser *parser)
		}

		parser->cur_obj = obj;
+
		ucl_attach_comment (parser, obj, false);
	}
	else {
		/* Object has been already allocated */
@@ -1707,12 +1771,19 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
					parser->stack = st->next;
					UCL_FREE (sizeof (struct ucl_stack), st);

+
					if (parser->cur_obj) {
+
						ucl_attach_comment (parser, parser->cur_obj, true);
+
					}
+

					while (parser->stack != NULL) {
						st = parser->stack;
+

						if (st->next == NULL || st->next->level == st->level) {
							break;
						}
+

						parser->stack = st->next;
+
						parser->cur_obj = st->obj;
						UCL_FREE (sizeof (struct ucl_stack), st);
					}
				}
@@ -1752,6 +1823,109 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
	return true;
}

+
static bool
+
ucl_skip_macro_as_comment (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk)
+
{
+
	const unsigned char *p, *c;
+
	enum {
+
		macro_skip_start = 0,
+
		macro_has_symbols,
+
		macro_has_obrace,
+
		macro_has_quote,
+
		macro_has_backslash,
+
		macro_has_sqbrace,
+
		macro_save
+
	} state = macro_skip_start, prev_state = macro_skip_start;
+

+
	p = chunk->pos;
+
	c = chunk->pos;
+

+
	while (p < chunk->end) {
+
		switch (state) {
+
		case macro_skip_start:
+
			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
				state = macro_has_symbols;
+
			}
+
			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+
				state = macro_save;
+
				continue;
+
			}
+

+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_has_symbols:
+
			if (*p == '{') {
+
				state = macro_has_sqbrace;
+
			}
+
			else if (*p == '(') {
+
				state = macro_has_obrace;
+
			}
+
			else if (*p == '"') {
+
				state = macro_has_quote;
+
			}
+
			else if (*p == '\n') {
+
				state = macro_save;
+
				continue;
+
			}
+

+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_has_obrace:
+
			if (*p == '\\') {
+
				prev_state = state;
+
				state = macro_has_backslash;
+
			}
+
			else if (*p == ')') {
+
				state = macro_has_symbols;
+
			}
+

+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_has_sqbrace:
+
			if (*p == '\\') {
+
				prev_state = state;
+
				state = macro_has_backslash;
+
			}
+
			else if (*p == '}') {
+
				state = macro_save;
+
			}
+

+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_has_quote:
+
			if (*p == '\\') {
+
				prev_state = state;
+
				state = macro_has_backslash;
+
			}
+
			else if (*p == '"') {
+
				state = macro_save;
+
			}
+

+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_has_backslash:
+
			state = prev_state;
+
			ucl_chunk_skipc (chunk, p);
+
			break;
+

+
		case macro_save:
+
			if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+
				ucl_save_comment (parser, c, p - c);
+
			}
+

+
			return true;
+
		}
+
	}
+

+
	return false;
+
}
+

/**
 * Handle macro data
 * @param parser
@@ -2024,7 +2198,7 @@ ucl_state_machine (struct ucl_parser *parser)
			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
				ucl_chunk_skipc (chunk, p);
			}
-
			if (*p == '}') {
+
			if (p == chunk->end || *p == '}') {
				/* We have the end of an object */
				parser->state = UCL_STATE_AFTER_VALUE;
				continue;
@@ -2067,7 +2241,7 @@ ucl_state_machine (struct ucl_parser *parser)
			break;
		case UCL_STATE_VALUE:
			/* We need to check what we do have */
-
			if (!ucl_parse_value (parser, chunk)) {
+
			if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
				parser->prev_state = parser->state;
				parser->state = UCL_STATE_ERROR;
				return false;
@@ -2095,42 +2269,60 @@ ucl_state_machine (struct ucl_parser *parser)
				/* Skip everything at the end */
				return true;
			}
+

			p = chunk->pos;
			break;
		case UCL_STATE_MACRO_NAME:
-
			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
-
					*p != '(') {
-
				ucl_chunk_skipc (chunk, p);
+
			if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+
				if (!ucl_skip_macro_as_comment (parser, chunk)) {
+
					/* We have invalid macro */
+
					ucl_create_err (&parser->err,
+
							"error on line %d at column %d: invalid macro",
+
							chunk->line,
+
							chunk->column);
+
					parser->state = UCL_STATE_ERROR;
+
					return false;
+
				}
+
				else {
+
					p = chunk->pos;
+
					parser->state = parser->prev_state;
+
				}
			}
			else {
-
				if (p - c > 0) {
-
					/* We got macro name */
-
					macro_len = (size_t) (p - c);
-
					HASH_FIND (hh, parser->macroes, c, macro_len, macro);
-
					if (macro == NULL) {
+
				if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
+
						*p != '(') {
+
					ucl_chunk_skipc (chunk, p);
+
				}
+
				else {
+
					if (p - c > 0) {
+
						/* We got macro name */
+
						macro_len = (size_t) (p - c);
+
						HASH_FIND (hh, parser->macroes, c, macro_len, macro);
+
						if (macro == NULL) {
+
							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;
+
						}
+
						/* Now we need to skip all spaces */
+
						SKIP_SPACES_COMMENTS(parser, chunk, p);
+
						parser->state = UCL_STATE_MACRO;
+
					}
+
					else {
+
						/* We have invalid macro name */
						ucl_create_err (&parser->err,
-
								"error on line %d at column %d: "
-
										"unknown macro: '%.*s', character: '%c'",
+
								"error on line %d at column %d: invalid macro name",
								chunk->line,
-
								chunk->column,
-
								(int) (p - c),
-
								c,
-
								*chunk->pos);
+
								chunk->column);
						parser->state = UCL_STATE_ERROR;
						return false;
					}
-
					/* Now we need to skip all spaces */
-
					SKIP_SPACES_COMMENTS(parser, chunk, p);
-
					parser->state = UCL_STATE_MACRO;
-
				}
-
				else {
-
					/* We have invalid macro name */
-
					ucl_create_err (&parser->err,
-
							"error on line %d at column %d: invalid macro name",
-
							chunk->line,
-
							chunk->column);
-
					parser->state = UCL_STATE_ERROR;
-
					return false;
				}
			}
			break;
@@ -2154,6 +2346,7 @@ ucl_state_machine (struct ucl_parser *parser)
			macro_len = ucl_expand_variable (parser, &macro_escaped,
					macro_start, macro_len);
			parser->state = parser->prev_state;
+

			if (macro_escaped == NULL) {
				if (macro->is_context) {
					ret = macro->h.context_handler (macro_start, macro_len,
@@ -2194,7 +2387,6 @@ ucl_state_machine (struct ucl_parser *parser)
			}
			break;
		default:
-
			/* TODO: add all states */
			ucl_set_err (parser, UCL_EINTERNAL,
					"internal error: parser is in an unknown state", &parser->err);
			parser->state = UCL_STATE_ERROR;
@@ -2202,35 +2394,54 @@ ucl_state_machine (struct ucl_parser *parser)
		}
	}

+
	if (parser->last_comment) {
+
		if (parser->cur_obj) {
+
			ucl_attach_comment (parser, parser->cur_obj, true);
+
		}
+
		else if (parser->stack && parser->stack->obj) {
+
			ucl_attach_comment (parser, parser->stack->obj, true);
+
		}
+
		else if (parser->top_obj) {
+
			ucl_attach_comment (parser, parser->top_obj, true);
+
		}
+
		else {
+
			ucl_object_unref (parser->last_comment);
+
		}
+
	}
+

	return true;
}

struct ucl_parser*
ucl_parser_new (int flags)
{
-
	struct ucl_parser *new;
+
	struct ucl_parser *parser;

-
	new = UCL_ALLOC (sizeof (struct ucl_parser));
-
	if (new == NULL) {
+
	parser = UCL_ALLOC (sizeof (struct ucl_parser));
+
	if (parser == NULL) {
		return NULL;
	}

-
	memset (new, 0, sizeof (struct ucl_parser));
+
	memset (parser, 0, sizeof (struct ucl_parser));

-
	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
-
	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
-
	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
-
	ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
-
	ucl_parser_register_macro (new, "load", ucl_load_handler, new);
-
	ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
+
	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);

-
	new->flags = flags;
-
	new->includepaths = NULL;
+
	parser->flags = flags;
+
	parser->includepaths = NULL;
+

+
	if (flags & UCL_PARSER_SAVE_COMMENTS) {
+
		parser->comments = ucl_object_typed_new (UCL_OBJECT);
+
	}

	/* Initial assumption about filevars */
-
	ucl_parser_set_filevars (new, NULL, false);
+
	ucl_parser_set_filevars (parser, NULL, false);

-
	return new;
+
	return parser;
}

bool
modified external/libucl/src/ucl_schema.c
@@ -43,72 +43,8 @@
static bool ucl_schema_validate (const ucl_object_t *schema,
		const ucl_object_t *obj, bool try_array,
		struct ucl_schema_error *err,
-
		const ucl_object_t *root);
-

-
static bool
-
ucl_string_to_type (const char *input, ucl_type_t *res)
-
{
-
	if (strcasecmp (input, "object") == 0) {
-
		*res = UCL_OBJECT;
-
	}
-
	else if (strcasecmp (input, "array") == 0) {
-
		*res = UCL_ARRAY;
-
	}
-
	else if (strcasecmp (input, "integer") == 0) {
-
		*res = UCL_INT;
-
	}
-
	else if (strcasecmp (input, "number") == 0) {
-
		*res = UCL_FLOAT;
-
	}
-
	else if (strcasecmp (input, "string") == 0) {
-
		*res = UCL_STRING;
-
	}
-
	else if (strcasecmp (input, "boolean") == 0) {
-
		*res = UCL_BOOLEAN;
-
	}
-
	else if (strcasecmp (input, "null") == 0) {
-
		*res = UCL_NULL;
-
	}
-
	else {
-
		return false;
-
	}
-

-
	return true;
-
}
-

-
static const char *
-
ucl_object_type_to_string (ucl_type_t type)
-
{
-
	const char *res = "unknown";
-

-
	switch (type) {
-
	case UCL_OBJECT:
-
		res = "object";
-
		break;
-
	case UCL_ARRAY:
-
		res = "array";
-
		break;
-
	case UCL_INT:
-
		res = "integer";
-
		break;
-
	case UCL_FLOAT:
-
	case UCL_TIME:
-
		res = "number";
-
		break;
-
	case UCL_STRING:
-
		res = "string";
-
		break;
-
	case UCL_BOOLEAN:
-
		res = "boolean";
-
		break;
-
	case UCL_NULL:
-
	case UCL_USERDATA:
-
		res = "null";
-
		break;
-
	}
-

-
	return res;
-
}
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_ref);

/*
 * Create validation error
@@ -160,7 +96,8 @@ ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern)
static bool
ucl_schema_validate_dependencies (const ucl_object_t *deps,
		const ucl_object_t *obj, struct ucl_schema_error *err,
-
		const ucl_object_t *root)
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_ref)
{
	const ucl_object_t *elt, *cur, *cur_dep;
	ucl_object_iter_t iter = NULL, piter;
@@ -183,7 +120,7 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
				}
			}
			else if (cur->type == UCL_OBJECT) {
-
				ret = ucl_schema_validate (cur, obj, true, err, root);
+
				ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
			}
		}
	}
@@ -197,7 +134,8 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
static bool
ucl_schema_validate_object (const ucl_object_t *schema,
		const ucl_object_t *obj, struct ucl_schema_error *err,
-
		const ucl_object_t *root)
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_ref)
{
	const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
			*required = NULL, *pat, *pelt;
@@ -212,7 +150,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
			while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
				found = ucl_object_find_key (obj, ucl_object_key (prop));
				if (found) {
-
					ret = ucl_schema_validate (prop, found, true, err, root);
+
					ret = ucl_schema_validate (prop, found, true, err, root,
+
							ext_ref);
				}
			}
		}
@@ -270,13 +209,15 @@ ucl_schema_validate_object (const ucl_object_t *schema,
			while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
				found = ucl_schema_test_pattern (obj, ucl_object_key (prop));
				if (found) {
-
					ret = ucl_schema_validate (prop, found, true, err, root);
+
					ret = ucl_schema_validate (prop, found, true, err, root,
+
							ext_ref);
				}
			}
		}
		else if (elt->type == UCL_OBJECT &&
				strcmp (ucl_object_key (elt), "dependencies") == 0) {
-
			ret = ucl_schema_validate_dependencies (elt, obj, err, root);
+
			ret = ucl_schema_validate_dependencies (elt, obj, err, root,
+
					ext_ref);
		}
	}

@@ -308,7 +249,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
						break;
					}
					else if (additional_schema != NULL) {
-
						if (!ucl_schema_validate (additional_schema, elt, true, err, root)) {
+
						if (!ucl_schema_validate (additional_schema, elt,
+
								true, err, root, ext_ref)) {
							ret = false;
							break;
						}
@@ -518,7 +460,8 @@ ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *er
static bool
ucl_schema_validate_array (const ucl_object_t *schema,
		const ucl_object_t *obj, struct ucl_schema_error *err,
-
		const ucl_object_t *root)
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_ref)
{
	const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
			*first_unvalidated = NULL;
@@ -533,7 +476,8 @@ ucl_schema_validate_array (const ucl_object_t *schema,
				found = ucl_array_head (obj);
				while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) {
					if (found) {
-
						ret = ucl_schema_validate (it, found, false, err, root);
+
						ret = ucl_schema_validate (it, found, false, err,
+
								root, ext_ref);
						found = ucl_array_find_index (obj, ++idx);
					}
				}
@@ -545,7 +489,8 @@ ucl_schema_validate_array (const ucl_object_t *schema,
			else if (elt->type == UCL_OBJECT) {
				/* Validate all items using the specified schema */
				while (ret && (it = ucl_iterate_object (obj, &piter, true)) != NULL) {
-
					ret = ucl_schema_validate (elt, it, false, err, root);
+
					ret = ucl_schema_validate (elt, it, false, err, root,
+
							ext_ref);
				}
			}
			else {
@@ -612,7 +557,7 @@ ucl_schema_validate_array (const ucl_object_t *schema,
					elt = ucl_array_find_index (obj, idx);
					while (elt) {
						if (!ucl_schema_validate (additional_schema, elt, false,
-
								err, root)) {
+
								err, root, ext_ref)) {
							ret = false;
							break;
						}
@@ -657,7 +602,7 @@ ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
	}
	else if (type->type == UCL_STRING) {
		type_str = ucl_object_tostring (type);
-
		if (!ucl_string_to_type (type_str, &t)) {
+
		if (!ucl_object_string_to_type (type_str, &t)) {
			ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
					"Type attribute is invalid in schema");
			return false;
@@ -771,31 +716,114 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur,
 */
static const ucl_object_t *
ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
-
		struct ucl_schema_error *err)
+
		struct ucl_schema_error *err, ucl_object_t *ext_ref,
+
		ucl_object_t const ** nroot)
{
-
	const char *p, *c;
-
	const ucl_object_t *res = NULL;
-

+
	UT_string *url_err = NULL;
+
	struct ucl_parser *parser;
+
	const ucl_object_t *res = NULL, *ext_obj = NULL;
+
	ucl_object_t *url_obj;
+
	const char *p, *c, *hash_ptr = NULL;
+
	char *url_copy = NULL;
+
	unsigned char *url_buf;
+
	size_t url_buflen;

	if (ref[0] != '#') {
-
		ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
-
				"reference %s is invalid, not started with #", ref);
-
		return NULL;
+
		hash_ptr = strrchr (ref, '#');
+

+
		if (hash_ptr) {
+
			url_copy = malloc (hash_ptr - ref + 1);
+

+
			if (url_copy == NULL) {
+
				ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
+
						"cannot allocate memory");
+
				return NULL;
+
			}
+

+
			ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
+
			p = url_copy;
+
		}
+
		else {
+
			/* Full URL */
+
			p = ref;
+
		}
+

+
		ext_obj = ucl_object_find_key (ext_ref, p);
+

+
		if (ext_obj == NULL) {
+
			if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
+
				if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
+

+
					ucl_schema_create_error (err,
+
							UCL_SCHEMA_INVALID_SCHEMA,
+
							root,
+
							"cannot fetch reference %s: %s",
+
							p,
+
							url_err != NULL ? utstring_body (url_err)
+
											: "unknown");
+
					free (url_copy);
+

+
					return NULL;
+
				}
+
			}
+
			else {
+
				if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
+
						true)) {
+
					ucl_schema_create_error (err,
+
							UCL_SCHEMA_INVALID_SCHEMA,
+
							root,
+
							"cannot fetch reference %s: %s",
+
							p,
+
							url_err != NULL ? utstring_body (url_err)
+
											: "unknown");
+
					free (url_copy);
+

+
					return NULL;
+
				}
+
			}
+

+
			parser = ucl_parser_new (0);
+

+
			if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
+
				ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
+
						"cannot fetch reference %s: %s", p,
+
						ucl_parser_get_error (parser));
+
				ucl_parser_free (parser);
+
				free (url_copy);
+

+
				return NULL;
+
			}
+

+
			url_obj = ucl_parser_get_object (parser);
+
			ext_obj = url_obj;
+
			ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
+
			free (url_buf);
+
		}
+

+
		free (url_copy);
+

+
		if (hash_ptr) {
+
			p = hash_ptr + 1;
+
		}
+
		else {
+
			p = "";
+
		}
	}
-
	if (ref[1] == '/') {
-
		p = &ref[2];
+
	else {
+
		p = ref + 1;
	}
-
	else if (ref[1] == '\0') {
-
		return root;
+

+
	res = ext_obj != NULL ? ext_obj : root;
+
	*nroot = res;
+

+
	if (*p == '/') {
+
		p++;
	}
-
	else {
-
		ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
-
				"reference %s is invalid, not started with #/", ref);
-
		return NULL;
+
	else if (*p == '\0') {
+
		return res;
	}

	c = p;
-
	res = root;

	while (*p != '\0') {
		if (*p == '/') {
@@ -878,15 +906,17 @@ static bool
ucl_schema_validate (const ucl_object_t *schema,
		const ucl_object_t *obj, bool try_array,
		struct ucl_schema_error *err,
-
		const ucl_object_t *root)
+
		const ucl_object_t *root,
+
		ucl_object_t *external_refs)
{
-
	const ucl_object_t *elt, *cur;
+
	const ucl_object_t *elt, *cur, *ref_root;
	ucl_object_iter_t iter = NULL;
	bool ret;

	if (schema->type != UCL_OBJECT) {
		ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
-
				"schema is %s instead of object", ucl_object_type_to_string (schema->type));
+
				"schema is %s instead of object",
+
				ucl_object_type_to_string (schema->type));
		return false;
	}

@@ -898,7 +928,7 @@ ucl_schema_validate (const ucl_object_t *schema,
			return false;
		}
		LL_FOREACH (obj, cur) {
-
			if (!ucl_schema_validate (schema, cur, false, err, root)) {
+
			if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
				return false;
			}
		}
@@ -916,7 +946,7 @@ ucl_schema_validate (const ucl_object_t *schema,
	if (elt != NULL && elt->type == UCL_ARRAY) {
		iter = NULL;
		while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
-
			ret = ucl_schema_validate (cur, obj, true, err, root);
+
			ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
			if (!ret) {
				return false;
			}
@@ -927,7 +957,7 @@ ucl_schema_validate (const ucl_object_t *schema,
	if (elt != NULL && elt->type == UCL_ARRAY) {
		iter = NULL;
		while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
-
			ret = ucl_schema_validate (cur, obj, true, err, root);
+
			ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
			if (ret) {
				break;
			}
@@ -947,9 +977,9 @@ ucl_schema_validate (const ucl_object_t *schema,
		ret = false;
		while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
			if (!ret) {
-
				ret = ucl_schema_validate (cur, obj, true, err, root);
+
				ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
			}
-
			else if (ucl_schema_validate (cur, obj, true, err, root)) {
+
			else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
				ret = false;
				break;
			}
@@ -961,7 +991,7 @@ ucl_schema_validate (const ucl_object_t *schema,

	elt = ucl_object_find_key (schema, "not");
	if (elt != NULL && elt->type == UCL_OBJECT) {
-
		if (ucl_schema_validate (elt, obj, true, err, root)) {
+
		if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
			return false;
		}
		else {
@@ -972,11 +1002,15 @@ ucl_schema_validate (const ucl_object_t *schema,

	elt = ucl_object_find_key (schema, "$ref");
	if (elt != NULL) {
-
		cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), err);
+
		ref_root = root;
+
		cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
+
				err, external_refs, &ref_root);
+

		if (cur == NULL) {
			return false;
		}
-
		if (!ucl_schema_validate (cur, obj, try_array, err, root)) {
+
		if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
+
				external_refs)) {
			return false;
		}
	}
@@ -988,10 +1022,10 @@ ucl_schema_validate (const ucl_object_t *schema,

	switch (obj->type) {
	case UCL_OBJECT:
-
		return ucl_schema_validate_object (schema, obj, err, root);
+
		return ucl_schema_validate_object (schema, obj, err, root, external_refs);
		break;
	case UCL_ARRAY:
-
		return ucl_schema_validate_array (schema, obj, err, root);
+
		return ucl_schema_validate_array (schema, obj, err, root, external_refs);
		break;
	case UCL_INT:
	case UCL_FLOAT:
@@ -1011,5 +1045,37 @@ bool
ucl_object_validate (const ucl_object_t *schema,
		const ucl_object_t *obj, struct ucl_schema_error *err)
{
-
	return ucl_schema_validate (schema, obj, true, err, schema);
+
	return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
+
}
+

+
bool
+
ucl_object_validate_root (const ucl_object_t *schema,
+
		const ucl_object_t *obj,
+
		const ucl_object_t *root,
+
		struct ucl_schema_error *err)
+
{
+
	return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
+
}
+

+
bool
+
ucl_object_validate_root_ext (const ucl_object_t *schema,
+
		const ucl_object_t *obj,
+
		const ucl_object_t *root,
+
		ucl_object_t *ext_refs,
+
		struct ucl_schema_error *err)
+
{
+
	bool ret, need_unref = false;
+

+
	if (ext_refs == NULL) {
+
		ext_refs = ucl_object_typed_new (UCL_OBJECT);
+
		need_unref = true;
+
	}
+

+
	ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
+

+
	if (need_unref) {
+
		ucl_object_unref (ext_refs);
+
	}
+

+
	return ret;
}
modified external/libucl/src/ucl_sexp.c
@@ -108,6 +108,7 @@ ucl_parse_csexp (struct ucl_parser *parser)
			if (st->obj == NULL) {
				ucl_create_err (&parser->err, "no memory");
				state = parse_err;
+
				free (st);
				continue;
			}

@@ -205,6 +206,7 @@ ucl_parse_csexp (struct ucl_parser *parser)
			}

			free (st);
+
			st = NULL;
			p++;
			NEXT_STATE;
			break;
@@ -221,4 +223,4 @@ ucl_parse_csexp (struct ucl_parser *parser)
	}

	return true;
-
}

\ No newline at end of file
+
}
modified external/libucl/src/ucl_util.c
@@ -27,6 +27,7 @@
#include "ucl_chartable.h"
#include "kvec.h"
#include <stdarg.h>
+
#include <stdio.h> /* for asprintf */

#ifndef _WIN32
#include <glob.h>
@@ -236,7 +237,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dto
		}
		else if (obj->type == UCL_OBJECT) {
			if (obj->value.ov != NULL) {
-
				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
+
				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
			}
			obj->value.ov = NULL;
		}
@@ -306,6 +307,9 @@ ucl_unescape_json_string (char *str, size_t len)
			case 'u':
				/* Unicode escape */
				uval = 0;
+
				h ++; /* u character */
+
				len --;
+

				if (len > 3) {
					for (i = 0; i < 4; i++) {
						uval <<= 4;
@@ -322,8 +326,7 @@ ucl_unescape_json_string (char *str, size_t len)
							break;
						}
					}
-
					h += 3;
-
					len -= 3;
+

					/* Encode */
					if(uval < 0x80) {
						t[0] = (char)uval;
@@ -340,6 +343,8 @@ ucl_unescape_json_string (char *str, size_t len)
						t[2] = 0x80 + ((uval & 0x003F));
						t += 3;
					}
+
#if 0
+
					/* It's not actually supported now */
					else if(uval <= 0x10FFFF) {
						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
@@ -347,9 +352,19 @@ ucl_unescape_json_string (char *str, size_t len)
						t[3] = 0x80 + ((uval & 0x00003F));
						t += 4;
					}
+
#endif
					else {
						*t++ = '?';
					}
+

+
					/* Consume 4 characters of source */
+
					h += 4;
+
					len -= 4;
+

+
					if (len > 0) {
+
						len --; /* for '\' character */
+
					}
+
					continue;
				}
				else {
					*t++ = 'u';
@@ -437,7 +452,7 @@ ucl_copy_value_trash (const ucl_object_t *obj)
		}
		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
	}
-
	
+

	return obj->trash_stack[UCL_TRASH_VALUE];
}

@@ -504,6 +519,10 @@ ucl_parser_free (struct ucl_parser *parser)
		free (parser->cur_file);
	}

+
	if (parser->comments) {
+
		ucl_object_unref (parser->comments);
+
	}
+

	UCL_FREE (sizeof (struct ucl_parser), parser);
}

@@ -628,7 +647,7 @@ ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
 * @param buflen target length
 * @return
 */
-
static bool
+
bool
ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
		UT_string **err, bool must_exist)
{
@@ -690,8 +709,8 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
		return false;
	}
	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
-
	cbdata.buf = *buf;
-
	cbdata.buflen = *buflen;
+
	cbdata.buf = NULL;
+
	cbdata.buflen = 0;
	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);

	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
@@ -723,7 +742,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
 * @param buflen target length
 * @return
 */
-
static bool
+
bool
ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
		UT_string **err, bool must_exist)
{
@@ -739,7 +758,7 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
	}
	if (st.st_size == 0) {
		/* Do not map empty files */
-
		*buf = "";
+
		*buf = NULL;
		*buflen = 0;
	}
	else {
@@ -848,7 +867,7 @@ ucl_include_url (const unsigned char *data, size_t len,
	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);

	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
-
		return (!params->must_exist || false);
+
		return !params->must_exist;
	}

	if (params->check_signature) {
@@ -1037,6 +1056,16 @@ ucl_include_file_single (const unsigned char *data, size_t len,
		else if (old_obj == NULL) {
			/* Create an object with key: prefix */
			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+

+
			if (nest_obj == NULL) {
+
				ucl_create_err (&parser->err, "cannot allocate memory for an object");
+
				if (buflen > 0) {
+
					ucl_munmap (buf, buflen);
+
				}
+

+
				return false;
+
			}
+

			nest_obj->key = params->prefix;
			nest_obj->keylen = strlen (params->prefix);
			ucl_copy_key_trash(nest_obj);
@@ -1052,6 +1081,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
			if (ucl_object_type(old_obj) == UCL_ARRAY) {
				/* Append to the existing array */
				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
				if (nest_obj == NULL) {
+
					ucl_create_err (&parser->err, "cannot allocate memory for an object");
+
					if (buflen > 0) {
+
						ucl_munmap (buf, buflen);
+
					}
+

+
					return false;
+
				}
				nest_obj->prev = nest_obj;
				nest_obj->next = NULL;

@@ -1060,6 +1097,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
			else {
				/* Convert the object to an array */
				new_obj = ucl_object_typed_new (UCL_ARRAY);
+
				if (new_obj == NULL) {
+
					ucl_create_err (&parser->err, "cannot allocate memory for an object");
+
					if (buflen > 0) {
+
						ucl_munmap (buf, buflen);
+
					}
+

+
					return false;
+
				}
				new_obj->key = old_obj->key;
				new_obj->keylen = old_obj->keylen;
				new_obj->flags |= UCL_OBJECT_MULTIVALUE;
@@ -1067,6 +1112,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
				new_obj->next = NULL;

				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
				if (nest_obj == NULL) {
+
					ucl_create_err (&parser->err, "cannot allocate memory for an object");
+
					if (buflen > 0) {
+
						ucl_munmap (buf, buflen);
+
					}
+

+
					return false;
+
				}
				nest_obj->prev = nest_obj;
				nest_obj->next = NULL;

@@ -1085,6 +1138,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,
				ucl_create_err (&parser->err,
						"Conflicting type for key: %s",
						params->prefix);
+
				if (buflen > 0) {
+
					ucl_munmap (buf, buflen);
+
				}
+

				return false;
			}
		}
@@ -1097,7 +1154,11 @@ ucl_include_file_single (const unsigned char *data, size_t len,
			if (st == NULL) {
				ucl_create_err (&parser->err, "cannot allocate memory for an object");
				ucl_object_unref (nest_obj);
-
				return NULL;
+
				if (buflen > 0) {
+
					ucl_munmap (buf, buflen);
+
				}
+

+
				return false;
			}
			st->obj = nest_obj;
			st->level = parser->stack->level;
@@ -1232,7 +1293,7 @@ ucl_include_file (const unsigned char *data, size_t len,
	   treat allow_glob/need_glob as a NOOP and just return */
	return ucl_include_file_single (data, len, parser, params);
#endif
-
	
+

	return true;
}

@@ -1252,7 +1313,7 @@ ucl_include_common (const unsigned char *data, size_t len,
		bool default_try,
		bool default_sign)
{
-
	bool allow_url, search;
+
	bool allow_url = false, search = false;
	const char *duplicate;
	const ucl_object_t *param;
	ucl_object_iter_t it = NULL, ip = NULL;
@@ -1271,8 +1332,6 @@ ucl_include_common (const unsigned char *data, size_t len,
	params.strat = UCL_DUPLICATE_APPEND;
	params.must_exist = !default_try;

-
	search = false;
-

	/* Process arguments */
	if (args != NULL && args->type == UCL_OBJECT) {
		while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
@@ -1506,7 +1565,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
	size_t buflen;
	unsigned priority;
	int64_t iv;
-
	ucl_hash_t *container = NULL;
+
	ucl_object_t *container = NULL;
	enum ucl_string_flags flags;

	/* Default values */
@@ -1566,21 +1625,38 @@ ucl_load_handler (const unsigned char *data, size_t len,
		}
	}

-
	if (prefix == NULL || strlen(prefix) == 0) {
+
	if (prefix == NULL || strlen (prefix) == 0) {
		ucl_create_err (&parser->err, "No Key specified in load macro");
		return false;
	}

	if (len > 0) {
		asprintf (&load_file, "%.*s", (int)len, data);
-
		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, !try_load)) {
+

+
		if (!load_file) {
+
			ucl_create_err (&parser->err, "cannot allocate memory for suffix");
+

+
			return false;
+
		}
+

+
		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
+
				!try_load)) {
+
			free (load_file);
+

			return (try_load || false);
		}

-
		container = parser->stack->obj->value.ov;
-
		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix)));
+
		free (load_file);
+
		container = parser->stack->obj;
+
		old_obj = __DECONST (ucl_object_t *, ucl_object_find_key (container,
+
				prefix));
+

		if (old_obj != NULL) {
			ucl_create_err (&parser->err, "Key %s already exists", prefix);
+
			if (buflen > 0) {
+
				ucl_munmap (buf, buflen);
+
			}
+

			return false;
		}

@@ -1594,7 +1670,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
		else if (strcasecmp (target, "int") == 0) {
			asprintf(&tmp, "%.*s", (int)buflen, buf);
			iv = strtoll(tmp, NULL, 10);
-
			obj = ucl_object_fromint(iv);
+
			obj = ucl_object_fromint (iv);
		}

		if (buflen > 0) {
@@ -1604,14 +1680,13 @@ ucl_load_handler (const unsigned char *data, size_t len,
		if (obj != NULL) {
			obj->key = prefix;
			obj->keylen = strlen (prefix);
-
			ucl_copy_key_trash(obj);
+
			ucl_copy_key_trash (obj);
			obj->prev = obj;
			obj->next = NULL;
			ucl_object_set_priority (obj, priority);
-
			container = ucl_hash_insert_object (container, obj,
-
					parser->flags & UCL_PARSER_KEY_LOWERCASE);
-
			parser->stack->obj->value.ov = container;
+
			ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
		}
+

		return true;
	}

@@ -2527,7 +2602,7 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
		}
	}
	else {
-
		new = ucl_object_new_userdata (NULL, NULL);
+
		new = ucl_object_new_userdata (NULL, NULL, NULL);
		ucl_object_set_priority (new, priority);
	}

@@ -2535,7 +2610,9 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
}

ucl_object_t*
-
ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
+
ucl_object_new_userdata (ucl_userdata_dtor dtor,
+
		ucl_userdata_emitter emitter,
+
		void *ptr)
{
	struct ucl_object_userdata *new;
	size_t nsize = sizeof (*new);
@@ -2549,6 +2626,7 @@ ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
		new->obj.prev = (ucl_object_t *)new;
		new->dtor = dtor;
		new->emitter = emitter;
+
		new->obj.value.ud = ptr;
	}

	return (ucl_object_t *)new;
@@ -3217,6 +3295,13 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
	return ret;
}

+
int
+
ucl_object_compare_qsort (const ucl_object_t **o1,
+
		const ucl_object_t **o2)
+
{
+
	return ucl_object_compare (*o1, *o2);
+
}
+

void
ucl_object_array_sort (ucl_object_t *ar,
		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
@@ -3255,3 +3340,95 @@ ucl_object_set_priority (ucl_object_t *obj,
		obj->flags = priority;
	}
}
+

+
bool
+
ucl_object_string_to_type (const char *input, ucl_type_t *res)
+
{
+
	if (strcasecmp (input, "object") == 0) {
+
		*res = UCL_OBJECT;
+
	}
+
	else if (strcasecmp (input, "array") == 0) {
+
		*res = UCL_ARRAY;
+
	}
+
	else if (strcasecmp (input, "integer") == 0) {
+
		*res = UCL_INT;
+
	}
+
	else if (strcasecmp (input, "number") == 0) {
+
		*res = UCL_FLOAT;
+
	}
+
	else if (strcasecmp (input, "string") == 0) {
+
		*res = UCL_STRING;
+
	}
+
	else if (strcasecmp (input, "boolean") == 0) {
+
		*res = UCL_BOOLEAN;
+
	}
+
	else if (strcasecmp (input, "null") == 0) {
+
		*res = UCL_NULL;
+
	}
+
	else if (strcasecmp (input, "userdata") == 0) {
+
		*res = UCL_USERDATA;
+
	}
+
	else {
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
const char *
+
ucl_object_type_to_string (ucl_type_t type)
+
{
+
	const char *res = "unknown";
+

+
	switch (type) {
+
	case UCL_OBJECT:
+
		res = "object";
+
		break;
+
	case UCL_ARRAY:
+
		res = "array";
+
		break;
+
	case UCL_INT:
+
		res = "integer";
+
		break;
+
	case UCL_FLOAT:
+
	case UCL_TIME:
+
		res = "number";
+
		break;
+
	case UCL_STRING:
+
		res = "string";
+
		break;
+
	case UCL_BOOLEAN:
+
		res = "boolean";
+
		break;
+
	case UCL_USERDATA:
+
		res = "userdata";
+
		break;
+
	case UCL_NULL:
+
		res = "null";
+
		break;
+
	}
+

+
	return res;
+
}
+

+
const ucl_object_t *
+
ucl_parser_get_comments (struct ucl_parser *parser)
+
{
+
	if (parser && parser->comments) {
+
		return parser->comments;
+
	}
+

+
	return NULL;
+
}
+

+
const ucl_object_t *
+
ucl_comments_find (const ucl_object_t *comments,
+
		const ucl_object_t *srch)
+
{
+
	if (comments && srch) {
+
		return ucl_object_find_keyl (comments, (const char *)&srch,
+
				sizeof (void *));
+
	}
+

+
	return NULL;
+
}
modified external/libucl/tests/basic.test
@@ -21,6 +21,18 @@ for _tin in ${TEST_DIR}/basic/*.in ; do
		fi
	fi
	rm $_out
+
	# Use FD interface
+
	$PROG -f $_t.in > /dev/null
+
	# JSON output
+
	$PROG -j $_t.in > /dev/null
+
	$PROG -c -j $_t.in > /dev/null
+
	# YAML output
+
	$PROG -y $_t.in > /dev/null
+
	# Save comments mode
+
	$PROG -C $_t.in > /dev/null
+
	# Save macro mode
+
	$PROG -M $_t.in > /dev/null
+
	$PROG -M -C $_t.in > /dev/null
done


added external/libucl/tests/basic/14.in
@@ -0,0 +1,8 @@
+
# Bad comments case
+

+
section {
+
# key = value;
+
}
+
.include(try=true) "./1.in"
+

+
key = value;
added external/libucl/tests/basic/14.res
@@ -0,0 +1,4 @@
+
section {
+
}
+
key = "value";
+

added external/libucl/tests/basic/15.in
@@ -0,0 +1,24 @@
+
# In this test we test include override bug
+

+
.include(priority = 1) "${CURDIR}/15.inc"
+

+
section = {
+
	value = "test";
+
}
+

+
overrided = {
+
	value = "not-to-be-shown";
+
}
+

+
/*
+
 BUGGED UCL:
+
 overrided {
+
	    key = "overrided";
+
 }
+
 !!! So overrided has actually rewritten the previous key
+
 section {
+
	    value {
+
			        value = "not-to-be-shown";
+
	    }
+
 }
+
*/
added external/libucl/tests/basic/15.inc
@@ -0,0 +1,3 @@
+
overrided {
+
	key = "overrided";	
+
}
added external/libucl/tests/basic/15.res
@@ -0,0 +1,7 @@
+
overrided {
+
    key = "overrided";
+
}
+
section {
+
    value = "test";
+
}
+

added external/libucl/tests/basic/16.in
@@ -0,0 +1,12 @@
+
.include(priority = 1) "${CURDIR}/16.inc"
+

+
section = {
+
	value = "test";
+
}
+

+
overrided = {
+
	value = "not-to-be-shown";
+
}
+
overrided = {
+
	value2 = "implicit-array";
+
}
added external/libucl/tests/basic/16.inc
@@ -0,0 +1,3 @@
+
overrided {
+
	key = "overrided";
+
}
added external/libucl/tests/basic/16.res
@@ -0,0 +1,7 @@
+
overrided {
+
    key = "overrided";
+
}
+
section {
+
    value = "test";
+
}
+

added external/libucl/tests/basic/17.in
@@ -0,0 +1,2 @@
+
# issue 74
+
string that ends in slash\

\ No newline at end of file
added external/libucl/tests/basic/17.res
@@ -0,0 +1,2 @@
+
string = "that ends in slash\\";
+

added external/libucl/tests/basic/18.in
@@ -0,0 +1,31 @@
+
defaults {
+
	key = "val"
+
	foo = "bar"
+
	many = "values here"
+
}
+

+
mything {
+
	.inherit "defaults"
+
	key = "newval"
+
	key = "newval1"
+
}
+
mything {
+
	.inherit "mything"
+
	key = "newval"
+
}
+
.priority 3
+

+
defaults {
+
	key = "val1"
+
	foo = "bar1"
+
	many = "values here"
+
}
+
mything1 {
+
	key2 = "wtf??"
+
	.priority 1
+
	.inherit "defaults"
+
	.inherit "mything"
+
	.inherit "mything1"
+
	key1 = "newval"
+
	key2 = "OMG" # low priority
+
}
added external/libucl/tests/basic/18.res
@@ -0,0 +1,24 @@
+
defaults {
+
    key = "val1";
+
    foo = "bar1";
+
    many = "values here";
+
}
+
mything {
+
    key = "newval";
+
    key = "newval1";
+
    foo = "bar";
+
    many = "values here";
+
}
+
mything {
+
    key = "newval";
+
    foo = "bar";
+
    many = "values here";
+
}
+
mything1 {
+
    key2 = "wtf??";
+
    key = "val1";
+
    foo = "bar1";
+
    many = "values here";
+
    key1 = "newval";
+
}
+

added external/libucl/tests/basic/19-append.inc
@@ -0,0 +1,8 @@
+
okey_append = {
+
	    key = value1;
+
		key1 = value2
+
}
+

+
akey_append = ["value3"];
+

+
skey_append = "value4";
added external/libucl/tests/basic/19-merge.inc
@@ -0,0 +1,8 @@
+
okey_merge = {
+
	    key = value1;
+
	    key1 = value2;
+
}
+

+
akey_merge = ["value3"];
+

+
skey_merge = "value4";
added external/libucl/tests/basic/19-rewrite.inc
@@ -0,0 +1,8 @@
+
okey_rewrite = {
+
	    key = value1;
+
	    key1 = value2;
+
}
+

+
akey_rewrite = ["value3"];
+

+
skey_rewrite = "value4";
added external/libucl/tests/basic/19.in
@@ -0,0 +1,28 @@
+
okey_append = {
+
	key = value;
+
}
+

+
akey_append = ["value"];
+

+
skey_append = "value";
+

+
okey_merge = {
+
	key = value;
+
	source = original;
+
}
+

+
akey_merge = ["value"];
+

+
skey_merge = "value";
+

+
okey_rewrite = {
+
	key = value;
+
}
+

+
akey_rewrite = ["value"];
+

+
skey_rewrite = "value";
+

+
.include(duplicate="append") "${CURDIR}/19-append.inc" 
+
.include(duplicate="merge") "${CURDIR}/19-merge.inc" 
+
.include(duplicate="rewrite") "${CURDIR}/19-rewrite.inc" 
added external/libucl/tests/basic/19.res
@@ -0,0 +1,36 @@
+
okey_append {
+
    key = "value";
+
}
+
okey_append {
+
    key = "value1";
+
    key1 = "value2";
+
}
+
akey_append [
+
    "value",
+
]
+
akey_append [
+
    "value3",
+
]
+
skey_append = "value";
+
skey_append = "value4";
+
okey_merge {
+
    key = "value";
+
    key = "value1";
+
    source = "original";
+
    key1 = "value2";
+
}
+
akey_merge [
+
    "value",
+
    "value3",
+
]
+
skey_merge = "value";
+
skey_merge = "value4";
+
okey_rewrite {
+
    key = "value1";
+
    key1 = "value2";
+
}
+
akey_rewrite [
+
    "value3",
+
]
+
skey_rewrite = "value4";
+

added external/libucl/tests/basic/20.in
@@ -0,0 +1,2 @@
+
# issue 112
+
[[0

\ No newline at end of file
added external/libucl/tests/basic/20.res
@@ -0,0 +1,5 @@
+
[
+
    [
+
        0,
+
    ]
+
]
added external/libucl/tests/basic/21.in
@@ -0,0 +1,2 @@
+
 [9
+
{0 [[0

\ No newline at end of file
added external/libucl/tests/basic/21.res
@@ -0,0 +1,10 @@
+
[
+
    9,
+
    {
+
        0 [
+
            [
+
                0,
+
            ]
+
        ]
+
    }
+
]
added external/libucl/tests/basic/22.in
@@ -0,0 +1,2 @@
+
# issue 113
+
�=1

\ No newline at end of file
added external/libucl/tests/basic/22.res
@@ -0,0 +1,2 @@
+
� = 1;
+

modified external/libucl/tests/basic/9.in
@@ -6,7 +6,18 @@
key = value;
.include "$CURDIR/9.inc"

-
.try_include "/non/existent"
#.try_include "$CURDIR/9.incorrect.inc"
# 9.incorrect.inc contains '{}}'
#key = value;
+
prefix1 = {
+
	key = value	
+
}
+
array = [10]
+
array1 = [10]
+
.include(prefix=true; key="prefix") "$CURDIR/9.inc"
+
.include(prefix=true; key="prefix2"; target="array"; glob=true) "$CURDIR/9.inc"
+
.include(prefix=true; key="prefix1"; target="array"; glob=true) "$CURDIR/9.inc"
+
.include(prefix=true; key="array"; target="array"; glob=true) "$CURDIR/9.inc"
+
.include(prefix=true; key="array1"; glob=true) "$CURDIR/9.inc"
+
.include(prefix=true; key="prefix"; glob=true) "$CURDIR/9.inc"
+
.try_include "/non/existent"
modified external/libucl/tests/basic/9.res
@@ -2,4 +2,33 @@ key1 = "value";
key1 = "value";
key1 = "value";
key = "value";
+
prefix1 [
+
    {
+
        key = "value";
+
    }
+
    {
+
        key1 = "value";
+
    }
+
]
+
array [
+
    10,
+
    {
+
        key1 = "value";
+
    }
+
]
+
array1 [
+
    10,
+
    {
+
        key1 = "value";
+
    }
+
]
+
prefix {
+
    key1 = "value";
+
    key1 = "value";
+
}
+
prefix2 [
+
    {
+
        key1 = "value";
+
    }
+
]

added external/libucl/tests/basic/escapes.in
@@ -0,0 +1,2 @@
+
# Checks for escapes in strings
+
str = "\r\n\b\t\f\\\"\u03B4\u0B90\u1F640\uFFFFsome text"
added external/libucl/tests/basic/escapes.res
@@ -0,0 +1,2 @@
+
str = "\r\n\b\t\f\\\"δஐὤ0￿some text";
+

added external/libucl/tests/basic/load.in
@@ -0,0 +1,14 @@
+
# Load macro tests
+
section {
+

+
.load(try=false, multiline=false, trim=false, escape=false, key="key1", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=true, trim=false, escape=false, key="key2", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=true, trim=true, escape=false, key="key3", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=true, trim=true, escape=true, key="key4", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=false, trim=true, escape=false, key="key5", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=false, trim=false, escape=true, key="key6", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=false, trim=true, escape=true, key="key7", target="string", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=false, trim=false, escape=false, key="key8", target="int", priority=1) "${CURDIR}/load.inc"
+
.load(try=false, multiline=false, trim=false, escape=false, key="key9", target="int", priority=4) "${CURDIR}/load.inc"
+
.load(try=true, multiline=false, trim=false, escape=false, key="key10", target="string", priority=1) "load_bad.inc"
+
};
added external/libucl/tests/basic/load.inc
@@ -0,0 +1,2 @@
+
   123
+
   321\n    
added external/libucl/tests/basic/load.res
@@ -0,0 +1,19 @@
+
section {
+
    key1 = "   123\n   321\\n    \n";
+
    key2 = <<EOD
+
   123
+
   321\n    
+

+
EOD;
+
    key3 = <<EOD
+
123
+
   321\n
+
EOD;
+
    key4 = "123\\n   321\\\\n";
+
    key5 = "123\n   321\\n";
+
    key6 = "   123\\n   321\\\\n    \\n";
+
    key7 = "123\\n   321\\\\n";
+
    key8 = 123;
+
    key9 = 123;
+
}
+

modified external/libucl/tests/generate.res
@@ -1,6 +1,6 @@
key0 = 0.100000;
key1 = "test string";
-
key2 = "test \\nstring";
+
key2 = "test \\nstring\\n\\r\\n\\b\\t\\f\\\\\\\"";
key3 = "  test string    \n";
key4 [
    9.999000,
@@ -18,4 +18,27 @@ key11 = false;
key12 = "gslin@gslin.org";
key13 = "#test";
"k=3" = true;
+
key14 [
+
    10,
+
    9.999000,
+
    10.100000,
+
    "abc",
+
    "cde",
+
    "😎",
+
    "Ебв",
+
    "абв",
+
]
+
key15 = "test userdata emit";
+
key16 = "tes";
+
key17 [
+
    "test",
+
    10,
+
    9.999000,
+
    10.100000,
+
    "abc",
+
    "cde",
+
    "😎",
+
    "Ебв",
+
    "абв",
+
]

added external/libucl/tests/msgpack.test
@@ -0,0 +1,3 @@
+
#!/bin/sh
+

+
${TEST_BINARY_DIR}/test_msgpack

\ No newline at end of file
modified external/libucl/tests/schema.test
@@ -2,8 +2,21 @@

PROG=${TEST_BINARY_DIR}/test_schema
rm /tmp/_ucl_test_schema.out ||true
+
_succeed=0
+
_tests=0
for i in ${TEST_DIR}/schema/*.json ; do
	_name=`basename $i`
	printf "running schema test suite $_name... "
-
	$PROG >> /tmp/_ucl_test_schema.out < $i && ( echo "OK" ) || ( echo "Fail" ; exit 1 )
+
	$PROG >> /tmp/_ucl_test_schema.out < $i
+
	if [ $? -eq 0 ] ; then
+
	    echo "OK"
+
	    _succeed=$(($_succeed + 1))
+
	else
+
	    echo "Fail"
+
	fi
+
	_tests=$(($_tests + 1))
done
+

+
if [ $_tests -ne $_succeed ] ; then
+
    exit 1
+
fi
modified external/libucl/tests/schema/definitions.json
@@ -1,7 +1,7 @@
[
    {
        "description": "valid definition",
-
        "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
+
        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"},
        "tests": [
            {
                "description": "valid definition schema",
@@ -16,7 +16,7 @@
    },
    {
        "description": "invalid definition",
-
        "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
+
        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"},
        "tests": [
            {
                "description": "invalid definition schema",
modified external/libucl/tests/schema/ref.json
@@ -125,10 +125,9 @@
            }
        ]
    },
-
/*
    {
        "description": "remote ref, containing refs itself",
-
        "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
+
        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"},
        "tests": [
            {
                "description": "remote ref valid",
@@ -142,5 +141,4 @@
            }
        ]
    }
-
*/
]
modified external/libucl/tests/schema/refRemote.json
@@ -1,7 +1,7 @@
[
    {
        "description": "remote ref",
-
        "schema": {"$ref": "http://localhost:1234/integer.json"},
+
        "schema": {"$ref": "http://highsecure.ru/ucl-schema/remotes/integer.json"},
        "tests": [
            {
                "description": "remote ref valid",
@@ -17,7 +17,7 @@
    },
    {
        "description": "fragment within remote ref",
-
        "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"},
+
        "schema": {"$ref": "http://highsecure.ru/ucl-schema/remotes/subSchemas.json#/integer"},
        "tests": [
            {
                "description": "remote fragment valid",
@@ -34,7 +34,7 @@
    {
        "description": "ref within remote ref",
        "schema": {
-
            "$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
+
            "$ref": "http://highsecure.ru/ucl-schema/remotes/subSchemas.json#/refToInteger"
        },
        "tests": [
            {
@@ -49,10 +49,11 @@
            }
        ]
    },
+
/*
    {
        "description": "change resolution scope",
        "schema": {
-
            "id": "http://localhost:1234/",
+
            "id": "http://highsecure.ru/ucl-schema/remotes/",
            "items": {
                "id": "folder/",
                "items": {"$ref": "folderInteger.json"}
@@ -71,4 +72,5 @@
            }
        ]
    }
+
*/
]
modified external/libucl/tests/test_basic.c
@@ -23,20 +23,27 @@

#include "ucl.h"
#include "ucl_internal.h"
+
#include <sys/types.h>
+
#include <fcntl.h>
+
#include <unistd.h>
+


int
main (int argc, char **argv)
{
-
	char *inbuf;
+
	char *inbuf = NULL;
	struct ucl_parser *parser = NULL, *parser2 = NULL;
-
	ucl_object_t *obj;
+
	ucl_object_t *obj, *comments = NULL;
	ssize_t bufsize, r;
	FILE *in, *out;
	unsigned char *emitted = NULL;
	const char *fname_in = NULL, *fname_out = NULL;
-
	int ret = 0, opt, json = 0, compact = 0, yaml = 0;
+
	int ret = 0, opt, json = 0, compact = 0, yaml = 0,
+
			save_comments = 0, skip_macro = 0,
+
			flags, fd_out, fd_in, use_fd = 0;
+
	struct ucl_emitter_functions *func;

-
	while ((opt = getopt(argc, argv, "jcy")) != -1) {
+
	while ((opt = getopt(argc, argv, "fjcyCM")) != -1) {
		switch (opt) {
		case 'j':
			json = 1;
@@ -44,11 +51,20 @@ main (int argc, char **argv)
		case 'c':
			compact = 1;
			break;
+
		case 'C':
+
			save_comments = 1;
+
			break;
		case 'y':
			yaml = 1;
			break;
+
		case 'M':
+
			skip_macro = true;
+
			break;
+
		case 'f':
+
			use_fd = true;
+
			break;
		default: /* '?' */
-
			fprintf (stderr, "Usage: %s [-jcy] [in] [out]\n",
+
			fprintf (stderr, "Usage: %s [-jcy] [-CM] [-f] [in] [out]\n",
					argv[0]);
			exit (EXIT_FAILURE);
		}
@@ -67,64 +83,113 @@ main (int argc, char **argv)
		break;
	}

-
	if (fname_in != NULL) {
-
		in = fopen (fname_in, "r");
-
		if (in == NULL) {
-
			exit (-errno);
+
	if (!use_fd) {
+
		if (fname_in != NULL) {
+
			in = fopen (fname_in, "r");
+
			if (in == NULL) {
+
				exit (-errno);
+
			}
+
		}
+
		else {
+
			in = stdin;
		}
	}
	else {
-
		in = stdin;
+
		if (fname_in != NULL) {
+
			fd_in = open (fname_in, O_RDONLY);
+
			if (fd_in == -1) {
+
				exit (-errno);
+
			}
+
		}
+
		else {
+
			fd_in = STDIN_FILENO;
+
		}
	}
-
	parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
+

+
	flags = UCL_PARSER_KEY_LOWERCASE;
+

+
	if (save_comments) {
+
		flags |= UCL_PARSER_SAVE_COMMENTS;
+
	}
+

+
	if (skip_macro) {
+
		flags |= UCL_PARSER_DISABLE_MACRO;
+
	}
+

+
	parser = ucl_parser_new (flags);
	ucl_parser_register_variable (parser, "ABI", "unknown");

	if (fname_in != NULL) {
		ucl_parser_set_filevars (parser, fname_in, true);
	}

-
	inbuf = malloc (BUFSIZ);
-
	bufsize = BUFSIZ;
-
	r = 0;
+
	if (!use_fd) {
+
		inbuf = malloc (BUFSIZ);
+
		bufsize = BUFSIZ;
+
		r = 0;

-
	while (!feof (in) && !ferror (in)) {
-
		if (r == bufsize) {
-
			inbuf = realloc (inbuf, bufsize * 2);
-
			bufsize *= 2;
-
			if (inbuf == NULL) {
-
				perror ("realloc");
-
				exit (EXIT_FAILURE);
+
		while (!feof (in) && !ferror (in)) {
+
			if (r == bufsize) {
+
				inbuf = realloc (inbuf, bufsize * 2);
+
				bufsize *= 2;
+
				if (inbuf == NULL) {
+
					perror ("realloc");
+
					exit (EXIT_FAILURE);
+
				}
			}
+
			r += fread (inbuf + r, 1, bufsize - r, in);
		}
-
		r += fread (inbuf + r, 1, bufsize - r, in);
-
	}

-
	if (ferror (in)) {
-
		fprintf (stderr, "Failed to read the input file.\n");
-
		exit (EXIT_FAILURE);
-
	}
+
		if (ferror (in)) {
+
			fprintf (stderr, "Failed to read the input file.\n");
+
			exit (EXIT_FAILURE);
+
		}

-
	ucl_parser_add_chunk (parser, (const unsigned char *)inbuf, r);
-
	fclose (in);
+
		ucl_parser_add_chunk (parser, (const unsigned char *)inbuf, r);
+
		fclose (in);
+
	}
+
	else {
+
		ucl_parser_add_fd (parser, fd_in);
+
		close (fd_in);
+
	}

-
	if (fname_out != NULL) {
-
		out = fopen (fname_out, "w");
-
		if (out == NULL) {
-
			exit (-errno);
+
	if (!use_fd) {
+
		if (fname_out != NULL) {
+
			out = fopen (fname_out, "w");
+
			if (out == NULL) {
+
				exit (-errno);
+
			}
+
		}
+
		else {
+
			out = stdout;
		}
	}
	else {
-
		out = stdout;
+
		if (fname_out != NULL) {
+
			fd_out = open (fname_out, O_WRONLY | O_CREAT, 00644);
+
			if (fd_out == -1) {
+
				exit (-errno);
+
			}
+
		}
+
		else {
+
			fd_out = STDOUT_FILENO;
+
		}
	}

+

	if (ucl_parser_get_error (parser) != NULL) {
-
		fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser));
+
		fprintf (out, "Error occurred (phase 1): %s\n",
+
						ucl_parser_get_error(parser));
		ret = 1;
		goto end;
	}

	obj = ucl_parser_get_object (parser);

+
	if (save_comments) {
+
		comments = ucl_object_ref (ucl_parser_get_comments (parser));
+
	}
+

	if (json) {
		if (compact) {
			emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT);
@@ -137,16 +202,27 @@ main (int argc, char **argv)
		emitted = ucl_object_emit (obj, UCL_EMIT_YAML);
	}
	else {
-
		emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
+
		emitted = NULL;
+
		func = ucl_object_emit_memory_funcs ((void **)&emitted);
+

+
		if (func != NULL) {
+
			ucl_object_emit_full (obj, UCL_EMIT_CONFIG, func, comments);
+
			ucl_object_emit_funcs_free (func);
+
		}
	}

+
#if 0
+
	fprintf (out, "%s\n****\n", emitted);
+
#endif
+

	ucl_parser_free (parser);
	ucl_object_unref (obj);
-
	parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
+
	parser2 = ucl_parser_new (flags);
	ucl_parser_add_string (parser2, (const char *)emitted, 0);

	if (ucl_parser_get_error(parser2) != NULL) {
-
		fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser2));
+
		fprintf (out, "Error occurred (phase 2): %s\n",
+
				ucl_parser_get_error(parser2));
		fprintf (out, "%s\n", emitted);
		ret = 1;
		goto end;
@@ -155,38 +231,68 @@ main (int argc, char **argv)
	if (emitted != NULL) {
		free (emitted);
	}
+
	if (comments) {
+
		ucl_object_unref (comments);
+
		comments = NULL;
+
	}
+

+
	if (save_comments) {
+
		comments = ucl_object_ref (ucl_parser_get_comments (parser2));
+
	}

	obj = ucl_parser_get_object (parser2);
-
	if (json) {
-
		if (compact) {
-
			emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT);
+

+
	if (!use_fd) {
+
		func = ucl_object_emit_file_funcs (out);
+
	}
+
	else {
+
		func = ucl_object_emit_fd_funcs (fd_out);
+
	}
+

+
	if (func != NULL) {
+
		if (json) {
+
			if (compact) {
+
				ucl_object_emit_full (obj, UCL_EMIT_JSON_COMPACT,
+
						func, comments);
+
			}
+
			else {
+
				ucl_object_emit_full (obj, UCL_EMIT_JSON,
+
						func, comments);
+
			}
+
		}
+
		else if (yaml) {
+
			ucl_object_emit_full (obj, UCL_EMIT_YAML,
+
					func, comments);
		}
		else {
-
			emitted = ucl_object_emit (obj, UCL_EMIT_JSON);
+
			ucl_object_emit_full (obj, UCL_EMIT_CONFIG,
+
					func, comments);
		}
+

+
		ucl_object_emit_funcs_free (func);
	}
-
	else if (yaml) {
-
		emitted = ucl_object_emit (obj, UCL_EMIT_YAML);
+

+
	if (!use_fd) {
+
		fprintf (out, "\n");
+
		fclose (out);
	}
	else {
-
		emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
+
		write (fd_out, "\n", 1);
+
		close (fd_out);
	}

-
	fprintf (out, "%s\n", emitted);
	ucl_object_unref (obj);

end:
-
	if (emitted != NULL) {
-
		free (emitted);
-
	}
	if (parser2 != NULL) {
		ucl_parser_free (parser2);
	}
+
	if (comments) {
+
		ucl_object_unref (comments);
+
	}
	if (inbuf != NULL) {
		free (inbuf);
	}

-
	fclose (out);
-

	return ret;
}
modified external/libucl/tests/test_generate.c
@@ -26,15 +26,28 @@
#include <assert.h>
#include "ucl.h"

+
static void
+
ud_dtor (void *ptr)
+
{
+
	assert (ptr == NULL);
+
}
+

+
static const char *
+
ud_emit (void *ptr)
+
{
+
	return "test userdata emit";
+
}
+

int
main (int argc, char **argv)
{
-
	ucl_object_t *obj, *cur, *ar, *ref;
+
	ucl_object_t *obj, *cur, *ar, *ar1, *ref, *test_obj;
	ucl_object_iter_t it;
-
	const ucl_object_t *found, *it_obj;
+
	const ucl_object_t *found, *it_obj, *test;
	FILE *out;
	unsigned char *emitted;
	const char *fname_out = NULL;
+
	struct ucl_parser *parser;
	int ret = 0;

	switch (argc) {
@@ -65,7 +78,8 @@ main (int argc, char **argv)
	/* Create some strings */
	cur = ucl_object_fromstring_common ("  test string    ", 0, UCL_STRING_TRIM);
	ucl_object_insert_key (obj, cur, "key1", 0, false);
-
	cur = ucl_object_fromstring_common ("  test \nstring\n    ", 0, UCL_STRING_TRIM | UCL_STRING_ESCAPE);
+
	cur = ucl_object_fromstring_common ("  test \nstring\n\r\n\b\t\f\\\"    ", 0,
+
			UCL_STRING_TRIM | UCL_STRING_ESCAPE);
	ucl_object_insert_key (obj, cur, "key2", 0, false);
	cur = ucl_object_fromstring_common ("  test string    \n", 0, 0);
	ucl_object_insert_key (obj, cur, "key3", 0, false);
@@ -73,10 +87,34 @@ main (int argc, char **argv)
	ar = ucl_object_typed_new (UCL_ARRAY);
	cur = ucl_object_fromint (10);
	ucl_array_append (ar, cur);
+
	assert (ucl_array_index_of (ar, cur) == 0);
	cur = ucl_object_fromdouble (10.1);
	ucl_array_append (ar, cur);
+
	assert (ucl_array_index_of (ar, cur) == 1);
	cur = ucl_object_fromdouble (9.999);
	ucl_array_prepend (ar, cur);
+
	assert (ucl_array_index_of (ar, cur) == 0);
+

+
	ar1 = ucl_object_copy (ar);
+
	cur = ucl_object_fromstring ("abc");
+
	ucl_array_prepend (ar1, cur);
+
	cur = ucl_object_fromstring ("cde");
+
	ucl_array_prepend (ar1, cur);
+
	cur = ucl_object_fromstring ("абв"); /* UTF8 */
+
	ucl_array_prepend (ar1, cur);
+
	cur = ucl_object_fromstring ("Ебв"); /* UTF8 */
+
	ucl_array_prepend (ar1, cur);
+
/*
+
 * This is ususally broken or fragile as utf collate is far from perfect
+
	cur = ucl_object_fromstring ("ёбв");
+
	ucl_array_prepend (ar1, cur);
+
	cur = ucl_object_fromstring ("Ёбв"); // hello to @bapt
+
	ucl_array_prepend (ar1, cur);
+
*/
+
	cur = ucl_object_fromstring ("😎"); /* everybody likes emoji in the code */
+
	ucl_array_prepend (ar1, cur);
+

+
	ucl_object_array_sort (ar1, ucl_object_compare_qsort);

	/* Removing from an array */
	cur = ucl_object_fromdouble (1.0);
@@ -122,6 +160,46 @@ main (int argc, char **argv)
	ucl_object_insert_key (obj, cur, "key13", 0, false);
	cur = ucl_object_frombool (true);
	ucl_object_insert_key (obj, cur, "k=3", 0, false);
+
	ucl_object_insert_key (obj, ar1, "key14", 0, false);
+
	cur = ucl_object_new_userdata (ud_dtor, ud_emit, NULL);
+
	ucl_object_insert_key (obj, cur, "key15", 0, false);
+

+
	/* More tests for keys */
+
	cur = ucl_object_fromlstring ("test", 3);
+
	ucl_object_insert_key (obj, cur, "key16", 0, false);
+
	test = ucl_object_find_any_key (obj, "key100", "key200", "key300", "key16", NULL);
+
	assert (test == cur);
+
	test = ucl_object_find_keyl (obj, "key160", 5);
+
	assert (test == cur);
+
	cur = ucl_object_pop_key (obj, "key16");
+
	assert (test == cur);
+
	test = ucl_object_pop_key (obj, "key16");
+
	assert (test == NULL);
+
	test = ucl_object_find_keyl (obj, "key160", 5);
+
	assert (test == NULL);
+
	/* Objects merging tests */
+
	test_obj = ucl_object_new_full (UCL_OBJECT, 2);
+
	ucl_object_insert_key (test_obj, cur, "key16", 0, true);
+
	ucl_object_merge (obj, test_obj, true);
+
	ucl_object_unref (test_obj);
+
	/* Array merging test */
+
	test_obj = ucl_object_new_full (UCL_ARRAY, 3);
+
	ucl_array_append (test_obj, ucl_object_fromstring ("test"));
+
	ucl_array_merge (test_obj, ar1, false);
+
	ucl_object_insert_key (obj, test_obj, "key17", 0, true);
+
	/* Object deletion */
+
	cur = ucl_object_fromstring ("test");
+
	ucl_object_insert_key (obj, cur, "key18", 0, true);
+
	assert (ucl_object_delete_key (obj, "key18"));
+
	assert (!ucl_object_delete_key (obj, "key18"));
+

+
	/* Array replace */
+
	ar1 = ucl_object_typed_new (UCL_ARRAY);
+
	cur = ucl_object_fromstring ("test");
+
	cur = ucl_elt_append (cur, ucl_object_fromstring ("test1"));
+
	ucl_array_append (ar1, cur);
+
	test = ucl_array_replace_index (ar1, ucl_object_fromstring ("test2"), 0);
+
	assert (test == cur);

	/* Try to find using path */
	/* Should exist */
@@ -172,6 +250,30 @@ main (int argc, char **argv)
	fprintf (out, "%s\n", emitted);
	ucl_object_unref (obj);

+
	parser = ucl_parser_new (UCL_PARSER_NO_IMPLICIT_ARRAYS);
+

+
	if (ucl_parser_add_chunk_full (parser, emitted, strlen (emitted),
+
			3, UCL_DUPLICATE_ERROR, UCL_PARSE_UCL)) {
+
		/* Should fail due to duplicate */
+
		assert (0);
+
	}
+
	else {
+
		assert (ucl_parser_get_error (parser) != NULL);
+
		ucl_parser_clear_error (parser);
+
		ucl_parser_free (parser);
+
		parser = ucl_parser_new (0);
+
		ucl_parser_add_chunk_full (parser, emitted, strlen (emitted),
+
					3, UCL_DUPLICATE_MERGE, UCL_PARSE_UCL);
+
	}
+

+
	assert (ucl_parser_get_column (parser) == 0);
+
	assert (ucl_parser_get_linenum (parser) != 0);
+
	ucl_parser_clear_error (parser);
+
	assert (ucl_parser_get_error_code (parser) == 0);
+
	obj = ucl_parser_get_object (parser);
+
	ucl_parser_free (parser);
+
	ucl_object_free (obj);
+

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

+
#include "ucl.h"
+
#include "ucl_internal.h"
+
#include <ctype.h>
+

+
static const int niter = 20;
+
static const int ntests = 10;
+
static const int nelt = 20;
+

+
static int recursion = 0;
+

+
typedef ucl_object_t* (*ucl_msgpack_test)(void);
+

+
static ucl_object_t* ucl_test_integer (void);
+
static ucl_object_t* ucl_test_string (void);
+
static ucl_object_t* ucl_test_boolean (void);
+
static ucl_object_t* ucl_test_map (void);
+
static ucl_object_t* ucl_test_array (void);
+
static ucl_object_t* ucl_test_large_map (void);
+
static ucl_object_t* ucl_test_large_array (void);
+
static ucl_object_t* ucl_test_large_string (void);
+
static ucl_object_t* ucl_test_null (void);
+

+
ucl_msgpack_test tests[] = {
+
		ucl_test_integer,
+
		ucl_test_string,
+
		ucl_test_boolean,
+
		ucl_test_map,
+
		ucl_test_array,
+
		ucl_test_null
+
};
+

+
#define NTESTS (sizeof(tests) / sizeof(tests[0]))
+

+
typedef struct
+
{
+
	uint64_t state;
+
	uint64_t inc;
+
} pcg32_random_t;
+

+
pcg32_random_t rng;
+

+
/*
+
 * From http://www.pcg-random.org/
+
 */
+
static uint32_t
+
pcg32_random (void)
+
{
+
	uint64_t oldstate = rng.state;
+

+
	rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
+
	uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
+
	uint32_t rot = oldstate >> 59u;
+
	return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+
}
+

+
static const char *
+
random_key (size_t *lenptr)
+
{
+
	static char keybuf[512];
+
	int keylen, i;
+
	char c;
+

+
	keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1;
+

+
	for (i = 0; i < keylen; i ++) {
+
		do {
+
			c = pcg32_random () & 0xFF;
+
		} while (!isgraph (c));
+

+
		keybuf[i] = c;
+
	}
+

+
	*lenptr = keylen;
+
	return keybuf;
+
}
+

+
int
+
main (int argc, char **argv)
+
{
+
	int fd, i, j;
+
	uint32_t sel;
+
	ucl_object_t *obj, *elt;
+
	struct ucl_parser *parser;
+
	size_t klen, elen, elen2;
+
	const char *key;
+
	unsigned char *emitted, *emitted2;
+
	FILE *out;
+
	const char *fname_out = NULL;
+

+
	switch (argc) {
+
	case 2:
+
		fname_out = argv[1];
+
		break;
+
	}
+

+
	/* Seed prng */
+
	fd = open ("/dev/urandom", O_RDONLY);
+
	assert (fd != -1);
+
	assert (read (fd, &rng, sizeof (rng)) == sizeof (rng));
+
	close (fd);
+

+
	for (i = 0; i < niter; i ++) {
+
		if (fname_out != NULL) {
+
			out = fopen (fname_out, "w");
+
			if (out == NULL) {
+
				exit (-errno);
+
			}
+
		}
+
		else {
+
			out = NULL;
+
		}
+

+
		/* Generate phase */
+
		obj = ucl_object_typed_new (UCL_OBJECT);
+

+
		for (j = 0; j < ntests; j ++) {
+
			sel = pcg32_random () % NTESTS;
+

+
			key = random_key (&klen);
+
			recursion = 0;
+
			elt = tests[sel]();
+
			assert (elt != NULL);
+
			assert (klen != 0);
+

+
			ucl_object_insert_key (obj, elt, key, klen, true);
+
		}
+

+
		key = random_key (&klen);
+
		elt = ucl_test_large_array ();
+
		ucl_object_insert_key (obj, elt, key, klen, true);
+

+
		key = random_key (&klen);
+
		elt = ucl_test_large_map ();
+
		ucl_object_insert_key (obj, elt, key, klen, true);
+

+
		key = random_key (&klen);
+
		elt = ucl_test_large_string ();
+
		ucl_object_insert_key (obj, elt, key, klen, true);
+

+
		emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen);
+

+
		assert (emitted != NULL);
+

+
		if (out) {
+
			fprintf (out, "%*.s\n", (int)elen, emitted);
+

+
			fclose (out);
+
		}
+
		ucl_object_unref (obj);
+

+
		parser = ucl_parser_new (0);
+

+
		if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0,
+
				UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) {
+
			fprintf (stderr, "error parsing input: %s",
+
					ucl_parser_get_error (parser));
+
			assert (0);
+
		}
+

+
		obj = ucl_parser_get_object (parser);
+
		assert (obj != NULL);
+

+
		emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2);
+

+
		assert (emitted2 != NULL);
+
		assert (elen2 == elen);
+
		assert (memcmp (emitted, emitted2, elen) == 0);
+

+
		ucl_parser_free (parser);
+
		ucl_object_unref (obj);
+
		free (emitted);
+
		free (emitted2);
+
	}
+

+
	return 0;
+
}
+

+

+
static ucl_object_t*
+
ucl_test_integer (void)
+
{
+
	ucl_object_t *res;
+
	int count, i;
+
	uint64_t cur;
+
	double curf;
+

+
	res = ucl_object_typed_new (UCL_ARRAY);
+
	count = pcg32_random () % nelt;
+

+
	for (i = 0; i < count; i ++) {
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		ucl_array_append (res, ucl_object_fromint (cur % 128));
+
		ucl_array_append (res, ucl_object_fromint (-(cur % 128)));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		ucl_array_append (res, ucl_object_fromint (cur % UINT16_MAX));
+
		ucl_array_append (res, ucl_object_fromint (-(cur % INT16_MAX)));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		ucl_array_append (res, ucl_object_fromint (cur % UINT32_MAX));
+
		ucl_array_append (res, ucl_object_fromint (-(cur % INT32_MAX)));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		ucl_array_append (res, ucl_object_fromint (cur));
+
		ucl_array_append (res, ucl_object_fromint (-cur));
+
		/* Double version */
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		curf = (cur % 128) / 19 * 16;
+
		ucl_array_append (res, ucl_object_fromdouble (curf));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		curf = -(cur % 128) / 19 * 16;
+
		ucl_array_append (res, ucl_object_fromdouble (curf));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		curf = (cur % 65536) / 19 * 16;
+
		ucl_array_append (res, ucl_object_fromdouble (curf));
+
		ucl_array_append (res, ucl_object_fromdouble (-curf));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		curf = (cur % INT32_MAX) / 19 * 16;
+
		ucl_array_append (res, ucl_object_fromdouble (curf));
+
		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
+
		memcpy (&curf, &cur, sizeof (curf));
+
		ucl_array_append (res, ucl_object_fromint (cur));
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_string (void)
+
{
+
	ucl_object_t *res, *elt;
+
	int count, i;
+
	uint32_t cur_len;
+
	char *str;
+

+
	res = ucl_object_typed_new (UCL_ARRAY);
+
	count = pcg32_random () % nelt;
+

+
	for (i = 0; i < count; i ++) {
+
		while ((cur_len = pcg32_random ()) % 128 == 0);
+

+
		str = malloc (cur_len % 128);
+
		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128,
+
				UCL_STRING_RAW));
+
		free (str);
+

+
		while ((cur_len = pcg32_random ()) % 512 == 0);
+
		str = malloc (cur_len % 512);
+
		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512,
+
				UCL_STRING_RAW));
+
		free (str);
+

+
		while ((cur_len = pcg32_random ()) % 128 == 0);
+
		str = malloc (cur_len % 128);
+
		elt = ucl_object_fromstring_common (str, cur_len % 128,
+
				UCL_STRING_RAW);
+
		elt->flags |= UCL_OBJECT_BINARY;
+
		ucl_array_append (res, elt);
+
		free (str);
+

+
		while ((cur_len = pcg32_random ()) % 512 == 0);
+
		str = malloc (cur_len % 512);
+
		elt = ucl_object_fromstring_common (str, cur_len % 512,
+
				UCL_STRING_RAW);
+
		elt->flags |= UCL_OBJECT_BINARY;
+
		ucl_array_append (res, elt);
+
		free (str);
+
	}
+

+
	/* One large string */
+
	str = malloc (65537);
+
	elt = ucl_object_fromstring_common (str, 65537,
+
			UCL_STRING_RAW);
+
	elt->flags |= UCL_OBJECT_BINARY;
+
	ucl_array_append (res, elt);
+
	free (str);
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_boolean (void)
+
{
+
	ucl_object_t *res;
+
	int count, i;
+

+
	res = ucl_object_typed_new (UCL_ARRAY);
+
	count = pcg32_random () % nelt;
+

+
	for (i = 0; i < count; i ++) {
+
		ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2));
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_map (void)
+
{
+
	ucl_object_t *res, *cur;
+
	int count, i;
+
	uint32_t cur_len, sel;
+
	size_t klen;
+
	const char *key;
+

+
	res = ucl_object_typed_new (UCL_OBJECT);
+
	count = pcg32_random () % nelt;
+

+
	recursion ++;
+

+
	for (i = 0; i < count; i ++) {
+

+
		if (recursion > 10) {
+
			for (;;) {
+
				sel = pcg32_random () % NTESTS;
+
				if (tests[sel] != ucl_test_map &&
+
						tests[sel] != ucl_test_array) {
+
					break;
+
				}
+
			}
+
		}
+
		else {
+
			sel = pcg32_random () % NTESTS;
+
		}
+

+
		key = random_key (&klen);
+
		cur = tests[sel]();
+
		assert (cur != NULL);
+
		assert (klen != 0);
+

+
		ucl_object_insert_key (res, cur, key, klen, true);
+

+
		/* Multi value key */
+
		cur = tests[sel]();
+
		assert (cur != NULL);
+

+
		ucl_object_insert_key (res, cur, key, klen, true);
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_large_map (void)
+
{
+
	ucl_object_t *res, *cur;
+
	int count, i;
+
	uint32_t cur_len;
+
	size_t klen;
+
	const char *key;
+

+
	res = ucl_object_typed_new (UCL_OBJECT);
+
	count = 65537;
+

+
	recursion ++;
+

+
	for (i = 0; i < count; i ++) {
+
		key = random_key (&klen);
+
		cur = ucl_test_boolean ();
+
		assert (cur != NULL);
+
		assert (klen != 0);
+

+
		ucl_object_insert_key (res, cur, key, klen, true);
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_array (void)
+
{
+
	ucl_object_t *res, *cur;
+
	int count, i;
+
	uint32_t cur_len, sel;
+

+
	res = ucl_object_typed_new (UCL_ARRAY);
+
	count = pcg32_random () % nelt;
+

+
	recursion ++;
+

+
	for (i = 0; i < count; i ++) {
+
		if (recursion > 10) {
+
			for (;;) {
+
				sel = pcg32_random () % NTESTS;
+
				if (tests[sel] != ucl_test_map &&
+
						tests[sel] != ucl_test_array) {
+
					break;
+
				}
+
			}
+
		}
+
		else {
+
			sel = pcg32_random () % NTESTS;
+
		}
+

+
		cur = tests[sel]();
+
		assert (cur != NULL);
+

+
		ucl_array_append (res, cur);
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_large_array (void)
+
{
+
	ucl_object_t *res, *cur;
+
	int count, i;
+
	uint32_t cur_len;
+

+
	res = ucl_object_typed_new (UCL_ARRAY);
+
	count = 65537;
+

+
	recursion ++;
+

+
	for (i = 0; i < count; i ++) {
+
		cur = ucl_test_boolean ();
+
		assert (cur != NULL);
+

+
		ucl_array_append (res, cur);
+
	}
+

+
	return res;
+
}
+

+
static ucl_object_t*
+
ucl_test_large_string (void)
+
{
+
	ucl_object_t *res;
+
	char *str;
+
	uint32_t cur_len;
+

+
	while ((cur_len = pcg32_random ()) % 100000 == 0);
+
	str = malloc (cur_len % 100000);
+
	res = ucl_object_fromstring_common (str, cur_len % 100000,
+
				UCL_STRING_RAW);
+
	res->flags |= UCL_OBJECT_BINARY;
+

+
	return res;
+
}
+

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

+
#include <stdio.h>
+
#include <getopt.h>
+
#include <stdlib.h>
+

+
#include "ucl.h"
+

+
static struct option opts[] = {
+
    {"help", no_argument, NULL, 'h'},
+
    {"in", required_argument, NULL, 'i' },
+
    {"out", required_argument, NULL, 'o' },
+
    {"schema", required_argument, NULL, 's'},
+
    {"format", required_argument, NULL, 'f'},
+
    {0, 0, 0, 0}
+
};
+

+
void usage(const char *name, FILE *out) {
+
  fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name);
+
  fprintf(out, "    [-s|--schema file] [-f|--format format]\n\n");
+
  fprintf(out, "  --help   - print this message and exit\n");
+
  fprintf(out, "  --in     - specify input filename "
+
          "(default: standard input)\n");
+
  fprintf(out, "  --out    - specify output filename "
+
          "(default: standard output)\n");
+
  fprintf(out, "  --schema - specify schema file for validation\n");
+
  fprintf(out, "  --format - output format. Options: ucl (default), "
+
          "json, compact_json, yaml, msgpack\n");
+
}
+

+
int main(int argc, char **argv) {
+
  char ch;
+
  FILE *in = stdin, *out = stdout;
+
  const char *schema = NULL;
+
  unsigned char *buf = NULL;
+
  size_t size = 0, r = 0;
+
  struct ucl_parser *parser = NULL;
+
  ucl_object_t *obj = NULL;
+
  ucl_emitter_t emitter = UCL_EMIT_CONFIG;
+

+
  while((ch = getopt_long(argc, argv, "hi:o:s:f:", opts, NULL)) != -1) {
+
    switch (ch) {
+
    case 'i':
+
      in = fopen(optarg, "r");
+
      if (in == NULL) {
+
        perror("fopen on input file");
+
        exit(EXIT_FAILURE);
+
      }
+
      break;
+
    case 'o':
+
      out = fopen(optarg, "w");
+
      if (out == NULL) {
+
        perror("fopen on output file");
+
        exit(EXIT_FAILURE);
+
      }
+
      break;
+
    case 's':
+
      schema = optarg;
+
      break;
+
    case 'f':
+
      if (strcmp(optarg, "ucl") == 0) {
+
        emitter = UCL_EMIT_CONFIG;
+
      } else if (strcmp(optarg, "json") == 0) {
+
        emitter = UCL_EMIT_JSON;
+
      } else if (strcmp(optarg, "yaml") == 0) {
+
        emitter = UCL_EMIT_YAML;
+
      } else if (strcmp(optarg, "compact_json") == 0) {
+
        emitter = UCL_EMIT_JSON_COMPACT;
+
      } else if (strcmp(optarg, "msgpack") == 0) {
+
        emitter = UCL_EMIT_MSGPACK;
+
      } else {
+
        fprintf(stderr, "Unknown output format: %s\n", optarg);
+
        exit(EXIT_FAILURE);
+
      }
+
      break;
+
    case 'h':
+
      usage(argv[0], stdout);
+
      exit(0);
+
    default:
+
      usage(argv[0], stderr);
+
      exit(EXIT_FAILURE);
+
      break;
+
    }
+
  }
+

+
  parser = ucl_parser_new(0);
+
  buf = malloc(BUFSIZ);
+
  size = BUFSIZ;
+
  while(!feof(in) && !ferror(in)) {
+
    if (r == size) {
+
      buf = realloc(buf, size*2);
+
      size *= 2;
+
      if (buf == NULL) {
+
        perror("realloc");
+
        exit(EXIT_FAILURE);
+
      }
+
    }
+
    r += fread(buf + r, 1, size - r, in);
+
  }
+
  if (ferror(in)) {
+
    fprintf(stderr, "Failed to read the input file.\n");
+
    exit(EXIT_FAILURE);
+
  }
+
  fclose(in);
+
  if (!ucl_parser_add_chunk(parser, buf, r)) {
+
    fprintf(stderr, "Failed to parse input file: %s\n",
+
            ucl_parser_get_error(parser));
+
    exit(EXIT_FAILURE);
+
  }
+
  if ((obj = ucl_parser_get_object(parser)) == NULL) {
+
    fprintf(stderr, "Failed to get root object: %s\n",
+
            ucl_parser_get_error(parser));
+
    exit(EXIT_FAILURE);
+
  }
+
  if (schema != NULL) {
+
    struct ucl_parser *schema_parser = ucl_parser_new(0);
+
    ucl_object_t *schema_obj = NULL;
+
    struct ucl_schema_error error;
+

+
    if (!ucl_parser_add_file(schema_parser, schema)) {
+
      fprintf(stderr, "Failed to parse schema file: %s\n",
+
              ucl_parser_get_error(schema_parser));
+
      exit(EXIT_FAILURE);
+
    }
+
    if ((schema_obj = ucl_parser_get_object(schema_parser)) == NULL) {
+
      fprintf(stderr, "Failed to get root object: %s\n",
+
              ucl_parser_get_error(schema_parser));
+
      exit(EXIT_FAILURE);
+
    }
+
    if (!ucl_object_validate(schema_obj, obj, &error)) {
+
      fprintf(stderr, "Validation failed: %s\n", error.msg);
+
      exit(EXIT_FAILURE);
+
    }
+
  }
+

+
  if (emitter != UCL_EMIT_MSGPACK) {
+
    fprintf(out, "%s\n", ucl_object_emit(obj, emitter));
+
  }
+
  else {
+
    size_t len;
+
    unsigned char *res;
+

+
    res = ucl_object_emit_len(obj, emitter, &len);
+
    fwrite(res, 1, len, out);
+
  }
+

+
  return 0;
+
}
modified libpkg/utils.c
@@ -622,7 +622,7 @@ ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,

	func.ud = out;

-
	return (ucl_object_emit_full(obj, emit_type, &func));
+
	return (ucl_object_emit_full(obj, emit_type, &func, NULL));


}
@@ -646,7 +646,7 @@ ucl_object_emit_sbuf(const ucl_object_t *obj, enum ucl_emitter emit_type,

	func.ud = *buf;

-
	ret = ucl_object_emit_full(obj, emit_type, &func);
+
	ret = ucl_object_emit_full(obj, emit_type, &func, NULL);
	sbuf_finish(*buf);

	return (ret);