Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Update libucl to latest version
Baptiste Daroussin committed 10 years ago
commit 3433197a8aea3a34fe0d46bb40bb471124d56156
parent 239a32f588bd033e414661fb477ac4481a76fd3e
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);