Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to latest version
Baptiste Daroussin committed 7 years ago
commit 85a7ab45577466b400e08dd4da85e36826716138
parent 6167cb7
36 files changed +1823 -436
modified external/libucl/ChangeLog.md
@@ -35,7 +35,7 @@

### Libucl 0.7.3

-
- Fixed a bug with macroes that come after an empty object
+
- Fixed a bug with macros that come after an empty object
- Fixed a bug in include processing when an incorrect variable has been destroyed (use-after-free)

### Libucl 0.8.0
@@ -64,4 +64,40 @@

**Incompatible changes**:

-
- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output

\ No newline at end of file
+
- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output
+

+
### Libucl 0.8.1
+

+
- Create ucl_parser_add_file_full() to be able to specify merge mode and parser type (by Allan Jude)
+
- C++ wrapper improvements (by @ftilde)
+
- C++ wrapper: add convenience method at() and lookup() (by Yonghee Kim)
+
- C++ wrapper: add assignment operator to Ucl class (by Yonghee Kim)
+
- C++ wrapper: support variables in parser (by Yonghee Kim)
+
- C++ wrapper: refactoring C++ interface (by Yonghee Kim):
+
    - use auto variables (if possible)
+
    - remove dangling expressions
+
    - use std::set::emplace instead of std::set::insert
+
    - not use std::move in return statement; considering copy elision
+
- C++ wrapper: fix compilation error and warnings (by Zhe Wang)
+
- C++ wrapper: fix iteration over objects in which the first value is `false` (by Zhe Wang)
+
- C++ wrapper: Macro helper functions (by Chris Meacham)
+
- C++ wrapper: Changing the duplicate strategy in the C++ API (by Chris Meacham)
+
- C++ wrapper: Added access functions for the size of a UCL_ARRAY (by Chris Meacham)
+
- Fix caseless comparison
+
- Fix include when EPERM is issued
+
- Fix Windows build
+
- Allow to reserve space in arrays and hashes
+
- Fix bug with including of empty files
+
- Move to mum_hash from xxhash
+
- Fix msgpack on non-x86
+
- python: Add support to Python 3 (by Denis Volpato Martins)
+
- python: Add support for Python 2.6 tests (by Denis Volpato Martins)
+
- python: Implement validation function and tests (by Denis Volpato Martins)
+
- python: Added UCL_NULL handling and tests (by Denis Volpato Martins)
+
- Fix schema validation for patternProperties with object data (by Denis Volpato Martins)
+
- Remove the dependency on NBBY, add missing <strings.h> include (by Ed Schouten)
+
- Allow to emit msgpack from Lua
+
- Performance improvements in Lua API
+
- Allow to pass opaque objects in Lua API for transparent C passthrough
+
- Various bugs fixed
+
- Couple of memory leaks plugged

\ No newline at end of file
modified external/libucl/Makefile.unix
@@ -1,7 +1,7 @@
CC ?= gcc
DESTDIR ?= /usr/local
LD ?= gcc
-
C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src
+
C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src -I./klib
MAJOR_VERSION = 0
MINOR_VERSION = 2
PATCH_VERSION = 9
@@ -25,13 +25,12 @@ HDEPS = $(SRCDIR)/ucl_hash.h \
		$(SRCDIR)/ucl_chartable.h \
		$(SRCDIR)/ucl_internal.h \
		$(INCLUDEDIR)/ucl.h \
-
		$(SRCDIR)/xxhash.h
+
		$(SRCDIR)/mum.h
OBJECTS = $(OBJDIR)/ucl_hash.o \
		$(OBJDIR)/ucl_util.o \
		$(OBJDIR)/ucl_parser.o \
		$(OBJDIR)/ucl_emitter.o \
-
		$(OBJDIR)/ucl_schema.o \
-
		$(OBJDIR)/xxhash.o
+
		$(OBJDIR)/ucl_schema.o

all: $(OBJDIR) $(OBJDIR)/$(SONAME)

@@ -55,8 +54,6 @@ $(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
	$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
	$(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c
-
$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
-
	$(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c

clean:
	$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME_FULL) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate $(OBJDIR)/test_schema || true
modified external/libucl/Makefile.w32
@@ -28,14 +28,13 @@ HDEPS = $(SRCDIR)/ucl_hash.h \
		$(SRCDIR)/ucl_chartable.h \
		$(SRCDIR)/ucl_internal.h \
		$(INCLUDEDIR)/ucl.h \
-
		$(SRCDIR)/xxhash.h
+
		$(SRCDIR)/mum.h
OBJECTS = $(OBJDIR)/ucl_hash.o \
		$(OBJDIR)/ucl_util.o \
		$(OBJDIR)/ucl_parser.o \
		$(OBJDIR)/ucl_emitter.o \
		$(OBJDIR)/ucl_emitter_utils.o \
-
		$(OBJDIR)/ucl_schema.o \
-
		$(OBJDIR)/xxhash.o
+
		$(OBJDIR)/ucl_schema.o

all: $(OBJDIR) $(OBJDIR)/$(SONAME)

modified external/libucl/README.md
@@ -1,6 +1,8 @@
# 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)[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)
+
[![CircleCI](https://circleci.com/gh/vstakhov/libucl.svg?style=svg)](https://circleci.com/gh/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/)*

@@ -12,16 +14,17 @@
	- [Named keys hierarchy](#named-keys-hierarchy)
	- [Convenient numbers and booleans](#convenient-numbers-and-booleans)
- [General improvements](#general-improvements)
-
	- [Commments](#commments)
+
	- [Comments](#comments)
	- [Macros support](#macros-support)
	- [Variables support](#variables-support)
	- [Multiline strings](#multiline-strings)
+
	- [Single quoted strings](#single-quoted-strings)
- [Emitter](#emitter)
- [Validation](#validation)
- [Performance](#performance)
- [Conclusion](#conclusion)

-
## Introduction 
+
## Introduction

This document describes the main features and principles of the configuration
language called `UCL` - universal configuration language.
@@ -47,7 +50,7 @@ section {
    string = "something";
    subsection {
        host = {
-
            host = "hostname"; 
+
            host = "hostname";
            port = 900;
        }
        host = {
@@ -163,9 +166,9 @@ section {
	}
}
```
-
    
+

Plain definitions may be more complex and contain more than a single level of nested objects:
-
   
+

```nginx
section "blah" "foo" {
	key = value;
@@ -174,7 +177,7 @@ section "blah" "foo" {

is presented as:

-
```nginx    
+
```nginx
section {
	blah {
		foo {
@@ -196,17 +199,17 @@ section {

## General improvements

-
### Commments
+
### Comments

UCL supports different style of comments:

-
* single line: `#` 
+
* single line: `#`
* multiline: `/* ... */`

Multiline comments may be nested:
```c
# Sample single line comment
-
/* 
+
/*
 some comment
 /* nested comment */
 end of comment
@@ -217,8 +220,8 @@ Multiline comments may be nested:

UCL supports external macros both multiline and single line ones:
```nginx
-
.macro "sometext";
-
.macro {
+
.macro_name "sometext";
+
.macro_name {
    Some long text
    ....
};
@@ -229,12 +232,12 @@ arguments themselves are the UCL object that is parsed and passed to a macro as
options:

```nginx
-
.macro(param=value) "something";
-
.macro(param={key=value}) "something";
-
.macro(.include "params.conf") "something";
-
.macro(#this is multiline macro
+
.macro_name(param=value) "something";
+
.macro_name(param={key=value}) "something";
+
.macro_name(.include "params.conf") "something";
+
.macro_name(#this is multiline macro
param = [value1, value2]) "something";
-
.macro(key="()") "something";
+
.macro_name(key="()") "something";
```

UCL also provide a convenient `include` macro to load content from another files
@@ -263,7 +266,7 @@ all files that matches the specified pattern (normally the format of patterns is
for your operating system). This option is meaningless for URL includes.
* `url` (default: **true**) - allow URL includes.
* `path` (default: empty) - A UCL_ARRAY of directories to search for the include file.
-
Search ends after the first patch, unless `glob` is true, then all matches are included.
+
Search ends after the first match, unless `glob` is true, then all matches are included.
* `prefix` (default false) - Put included contents inside an object, instead
of loading them into the root. If no `key` is provided, one is automatically generated based on each files basename()
* `key` (default: <empty string>) - Key to load contents of include into. If
@@ -273,7 +276,7 @@ object or an array.
* `priority` (default: 0) - specify priority for the include (see below).
* `duplicate` (default: 'append') - specify policy of duplicates resolving:
	- `append` - default strategy, if we have new object of higher priority then it replaces old one, if we have new object with less priority it is ignored completely, and if we have two duplicate objects with the same priority then we have a multi-value key (implicit array)
-
	- `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardeless of priorities)
+
	- `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardless of priorities)
	- `error` - create error on duplicate keys and stop parsing
	- `rewrite` - always rewrite an old value with new one (ignoring priorities)

@@ -320,7 +323,7 @@ Here are some rules for this syntax:
* Multiline terminator must start just after `<<` symbols and it must consist of capital letters only (e.g. `<<eof` or `<< EOF` won't work);
* Terminator must end with a single newline character (and no spaces are allowed between terminator and newline character);
* To finish multiline string you need to include a terminator string just after newline and followed by a newline (no spaces or other characters are allowed as well);
-
* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the begin and at the end of a value, for example:
+
* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the beginning and at the end of a value, for example:

```
key <<EOD
@@ -331,6 +334,18 @@ text
EOD
```

+
### Single quoted strings
+

+
It is possible to use single quoted strings to simplify escaping rules. All values passed in single quoted strings are *NOT* escaped, with two exceptions: a single `'` character just before `\` character, and a newline character just after `\` character that is ignored.
+

+
```
+
key = 'value'; # Read as value
+
key = 'value\n\'; # Read as  value\n\
+
key = 'value\''; # Read as value'
+
key = 'value\
+
bla'; # Read as valuebla
+
```
+

## Emitter

Each UCL object can be serialized to one of the three supported formats:
@@ -347,7 +362,7 @@ UCL allows validation of objects. It uses the same schema that is used for json:
## Performance

Are UCL parser and emitter fast enough? Well, there are some numbers.
-
I got a 19Mb file that consist of ~700 thousands lines of json (obtained via
+
I got a 19Mb file that consist of ~700 thousand lines of json (obtained via
http://www.json-generator.com/). Then I checked jansson library that performs json
parsing and emitting and compared it with UCL. Here are results:

@@ -377,6 +392,6 @@ You can do your own benchmarks by running `make check` in libucl top directory.
## Conclusion

UCL has clear design that should be very convenient for reading and writing. At the same time it is compatible with
-
JSON language and therefore can be used as a simple JSON parser. Macroes logic provides an ability to extend configuration
-
language (for example by including some lua code) and comments allows to disable or enable the parts of a configuration
+
JSON language and therefore can be used as a simple JSON parser. Macro logic provides an ability to extend configuration
+
language (for example by including some lua code) and comments allow to disable or enable the parts of a configuration
quickly.
modified external/libucl/configure.ac
@@ -1,7 +1,7 @@
m4_define([maj_ver], [0])
m4_define([med_ver], [8])
-
m4_define([min_ver], [0])
-
m4_define([so_version], [6:0:0])
+
m4_define([min_ver], [1])
+
m4_define([so_version], [6:0:1])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])

AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
@@ -39,6 +39,7 @@ AC_CHECK_HEADERS_ONCE([stdarg.h])
AC_CHECK_HEADERS_ONCE([stdbool.h])
AC_CHECK_HEADERS_ONCE([stdint.h])
AC_CHECK_HEADERS_ONCE([string.h])
+
AC_CHECK_HEADERS_ONCE([strings.h])
AC_CHECK_HEADERS_ONCE([unistd.h])
AC_CHECK_HEADERS_ONCE([ctype.h])
AC_CHECK_HEADERS_ONCE([errno.h])
modified external/libucl/doc/api.md
@@ -349,7 +349,7 @@ This object should be released by caller.
Libucl provides the functions similar to inverse conversion functions called with the specific C type:
- `ucl_object_fromint` - converts `int64_t` to UCL object
- `ucl_object_fromdouble` - converts `double` to UCL object
-
- `ucl_object_fromboolean` - converts `bool` to UCL object
+
- `ucl_object_frombool` - converts `bool` to UCL object
- `ucl_object_fromstring` - converts `const char *` to UCL object (this string should be NULL terminated)
- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string does not need to be NULL terminated)

modified external/libucl/doc/lua_api.md
@@ -38,7 +38,7 @@ func = "huh";
--]]
~~~

-
### Brief content:
+
###Brief content:

**Functions**:

@@ -69,8 +69,8 @@ converts `obj` to lua representation using the following conversions:
- *scalar* values are directly presented by lua objects
- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
this can be used to pass functions from lua to c and vice-versa
-
- *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
-
- *objects* are converted to lua tables with string indicies
+
- *arrays* are converted to lua tables with numeric indices suitable for `ipairs` iterations
+
- *objects* are converted to lua tables with string indices

**Parameters:**

modified external/libucl/include/lua_ucl.h
@@ -55,6 +55,14 @@ UCL_EXTERN int luaopen_ucl (lua_State *L);
UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);

/**
+
 * Import UCL object from lua state, escaping JSON strings
+
 * @param L lua state
+
 * @param idx index of object at the lua stack to convert to UCL
+
 * @return new UCL object or NULL, the caller should unref object after using
+
 */
+
UCL_EXTERN ucl_object_t* ucl_object_lua_import_escape (lua_State *L, int idx);
+

+
/**
 * Push an object to lua
 * @param L lua state
 * @param obj object to push
modified external/libucl/include/ucl++.h
@@ -29,6 +29,7 @@
#include <set>
#include <memory>
#include <iostream>
+
#include <tuple>

#include "ucl.h"

@@ -106,7 +107,7 @@ private:
	static bool ucl_variable_getter(const unsigned char *data, size_t len,
			unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
	{
-
        *need_free = false;
+
		*need_free = false;

		auto vars = reinterpret_cast<std::set<std::string> *>(ud);
		if (vars && data && len != 0) {
@@ -123,17 +124,17 @@ private:
		auto replacer = reinterpret_cast<variable_replacer *>(ud);
		if (!replacer) {
			return false;
-
        }
+
		}

		std::string var_name (data, data + len);
		if (!replacer->is_variable (var_name)) {
			return false;
-
        }
+
		}

		std::string var_value = replacer->replace (var_name);
		if (var_value.empty ()) {
			return false;
-
        }
+
 		}

		*replace = (unsigned char *)UCL_ALLOC (var_value.size ());
		memcpy (*replace, var_value.data (), var_value.size ());
@@ -152,7 +153,8 @@ private:
		config_func (parser);

		if (!parse_func (parser)) {
-
			err.assign (ucl_parser_get_error (parser));
+
			const char *error = ucl_parser_get_error (parser); //Assigning here without checking result first causes a
+
			if( error != NULL ) err.assign(error);             //	crash if ucl_parser_get_error returns NULL
			ucl_parser_free (parser);

			return nullptr;
@@ -168,6 +170,16 @@ private:
	std::unique_ptr<ucl_object_t, ucl_deleter> obj;

public:
+
	struct macro_handler_s {
+
		ucl_macro_handler         handler;
+
		ucl_context_macro_handler ctx_handler;
+
	};
+

+
	struct macro_userdata_s {
+
		ucl_parser    *parser;
+
		void          *userdata;
+
	};
+

	class const_iterator {
	private:
		struct ucl_iter_deleter {
@@ -184,7 +196,7 @@ public:
			it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
				ucl_iter_deleter());
			cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
-
			if (cur->type() == UCL_NULL) {
+
			if (!cur->obj) {
				it.reset ();
				cur.reset ();
			}
@@ -218,7 +230,7 @@ public:
				cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
			}

-
			if (cur && cur->type() == UCL_NULL) {
+
			if (cur && !cur->obj) {
				it.reset ();
				cur.reset ();
			}
@@ -330,7 +342,7 @@ public:
		return UCL_NULL;
	}

-
	const std::string key () const {
+
	std::string key () const {
		std::string res;

		if (obj->key) {
@@ -373,7 +385,7 @@ public:
		return default_val;
	}

-
	const std::string string_value (const std::string& default_val = "") const
+
	std::string string_value (const std::string& default_val = "") const
	{
		const char* res = nullptr;

@@ -384,7 +396,16 @@ public:
		return default_val;
	}

-
	const Ucl at (size_t i) const
+
	size_t size () const
+
	{
+
		if (type () == UCL_ARRAY) {
+
			return ucl_array_size (obj.get());
+
		}
+

+
		return 0;
+
	}
+

+
	Ucl at (size_t i) const
	{
		if (type () == UCL_ARRAY) {
			return Ucl (ucl_array_find_index (obj.get(), i));
@@ -393,7 +414,7 @@ public:
		return Ucl (nullptr);
	}

-
	const Ucl lookup (const std::string &key) const
+
	Ucl lookup (const std::string &key) const
	{
		if (type () == UCL_OBJECT) {
			return Ucl (ucl_object_lookup_len (obj.get(),
@@ -403,12 +424,12 @@ public:
		return Ucl (nullptr);
	}

-
	inline const Ucl operator[] (size_t i) const
+
	inline Ucl operator[] (size_t i) const
	{
		return at(i);
	}

-
	inline const Ucl operator[](const std::string &key) const
+
	inline Ucl operator[](const std::string &key) const
	{
		return lookup(key);
	}
@@ -432,43 +453,116 @@ public:
		return out;
	}

-
	static Ucl parse (const std::string &in, std::string &err)
+
	static Ucl parse (const std::string &in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
	{
-
		return parse (in, std::map<std::string, std::string>(), err);
+
		return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
	}

-
	static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars, std::string &err)
+
	static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
	{
-
		auto config_func = [&vars] (ucl_parser *parser) {
+
		std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
+
		return parse ( in, vars, emptyVector, err, duplicate_strategy );
+
	}
+

+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const std::string &in,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
+
	}
+

+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
+
		std::vector<macro_userdata_s> userdata_list;
+
		userdata_list.reserve (macros.size());
+
		auto config_func = [&userdata_list, &vars, &macros] (ucl_parser *parser) {
			for (const auto & item : vars) {
				ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
-
            }
+
			}
+
			for (auto & macro : macros) {
+
				userdata_list.push_back ({parser, std::get<2>(macro)});
+
				if (std::get<1>(macro).handler != NULL) {
+
					ucl_parser_register_macro (parser,
+
								std::get<0>(macro).c_str(),
+
								std::get<1>(macro).handler,
+
								reinterpret_cast<void*>(&userdata_list.back()));
+
				}
+
				else if (std::get<1>(macro).ctx_handler != NULL) {
+
					ucl_parser_register_context_macro (parser,
+
									std::get<0>(macro).c_str(),
+
									std::get<1>(macro).ctx_handler,
+
									reinterpret_cast<void*>(&userdata_list.back()));
+
				}
+
			}
		};

-
		auto parse_func = [&in] (ucl_parser *parser) {
-
			return ucl_parser_add_chunk (parser, (unsigned char *)in.data (), in.size ());
+
		auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
+
			return ucl_parser_add_chunk_full (parser,
+
							(unsigned char *) in.data (),
+
							in.size (),
+
							(unsigned int)ucl_parser_get_default_priority (parser),
+
							duplicate_strategy,
+
							UCL_PARSE_UCL);
		};

		return parse_with_strategy_function (config_func, parse_func, err);
	}

-
	static Ucl parse (const std::string &in, const variable_replacer &replacer, std::string &err)
-
	{
-
		auto config_func = [&replacer] (ucl_parser *parser) {
-
			ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
-
				&const_cast<variable_replacer &>(replacer));
+
	static Ucl parse (const std::string &in, const variable_replacer &replacer,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
+
		return parse ( in, replacer, emptyVector, err, duplicate_strategy );
+
	}
+

+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const std::string &in, const variable_replacer &replacer,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
+
		std::vector<macro_userdata_s> userdata_list;
+
		userdata_list.reserve (macros.size());
+
		auto config_func = [&userdata_list, &replacer, &macros] (ucl_parser *parser) {
+
			ucl_parser_set_variables_handler (parser, ucl_variable_replacer, &const_cast<variable_replacer &>(replacer));
+
			for (auto & macro : macros) {
+
				userdata_list.push_back ({parser, std::get<2>(macro)});
+
				if (std::get<1>(macro).handler != NULL) {
+
					ucl_parser_register_macro (parser,
+
								std::get<0>(macro).c_str(),
+
								std::get<1>(macro).handler,
+
								reinterpret_cast<void*>(&userdata_list.back()));
+
				}
+
				else if (std::get<1>(macro).ctx_handler != NULL) {
+
					ucl_parser_register_context_macro (parser,
+
									std::get<0>(macro).c_str(),
+
									std::get<1>(macro).ctx_handler,
+
									reinterpret_cast<void*>(&userdata_list.back()));
+
				}
+
			}
		};

-
		auto parse_func = [&in] (ucl_parser *parser) {
-
			return ucl_parser_add_chunk (parser, (unsigned char *) in.data (), in.size ());
+
		auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
+
			return ucl_parser_add_chunk_full (parser,
+
							(unsigned char *) in.data (),
+
							in.size (),
+
							(unsigned int)ucl_parser_get_default_priority (parser),
+
							duplicate_strategy,
+
							UCL_PARSE_UCL);
		};

		return parse_with_strategy_function (config_func, parse_func, err);
	}

-
	static Ucl parse (const char *in, std::string &err)
+
	static Ucl parse (const char *in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
	{
-
		return parse (in, std::map<std::string, std::string>(), err);
+
		return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
	}

	static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
@@ -480,13 +574,46 @@ public:
		return parse (std::string (in), vars, err);
	}

-
	static Ucl parse (const char *in, const variable_replacer &replacer, std::string &err)
+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const char *in,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
+
	}
+

+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const char *in, const std::map<std::string, std::string> &vars,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
	{
		if (!in) {
			err = "null input";
			return nullptr;
		}
-
		return parse (std::string(in), replacer, err);
+
		return parse (std::string (in), vars, macros, err, duplicate_strategy);
+
	}
+

+
	static Ucl parse (const char *in, const variable_replacer &replacer,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		if (!in) {
+
			err = "null input";
+
			return nullptr;
+
		}
+
		return parse (std::string(in), replacer, err, duplicate_strategy);
+
	}
+

+
	//Macro handler will receive a macro_userdata_s as void *ud
+
	static Ucl parse (const char *in, const variable_replacer &replacer,
+
			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
+
			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
+
	{
+
		if (!in) {
+
			err = "null input";
+
			return nullptr;
+
		}
+
		return parse (std::string (in), replacer, macros, err, duplicate_strategy);
	}

	static Ucl parse_from_file (const std::string &filename, std::string &err)
@@ -556,7 +683,7 @@ public:

		std::vector<std::string> result;
		std::move (vars.begin (), vars.end (), std::back_inserter (result));
-
		return std::move (result);
+
		return result;
	}

	Ucl& operator= (Ucl rhs)
modified external/libucl/include/ucl.h
@@ -105,10 +105,11 @@ typedef enum ucl_error {
	UCL_EIO, /**< IO error occurred during parsing */
	UCL_ESTATE, /**< Invalid state machine state */
	UCL_ENESTED, /**< Input has too many recursion levels */
+
	UCL_EUNPAIRED, /**< Input has too many recursion levels */
	UCL_EMACRO, /**< Error processing a macro */
	UCL_EINTERNAL, /**< Internal unclassified error */
	UCL_ESSL, /**< SSL error */
-
	UCL_EMERGE /**< A merge error occured */
+
	UCL_EMERGE /**< A merge error occurred */
} ucl_error_t;

/**
@@ -177,7 +178,8 @@ typedef enum ucl_string_flags {
} ucl_string_flags_t;

/**
-
 * Basic flags for an object
+
 * Basic flags for an object (can use up to 12 bits as higher 4 bits are used
+
 * for priorities)
 */
typedef enum ucl_object_flags {
	UCL_OBJECT_ALLOCATED_KEY = (1 << 0), /**< An object has key allocated internally */
@@ -187,7 +189,8 @@ typedef enum ucl_object_flags {
	UCL_OBJECT_MULTILINE = (1 << 4), /**< String should be displayed as multiline string */
	UCL_OBJECT_MULTIVALUE = (1 << 5), /**< Object is a key with multiple values */
	UCL_OBJECT_INHERITED = (1 << 6), /**< Object has been inherited from another */
-
	UCL_OBJECT_BINARY = (1 << 7) /**< Object contains raw binary data */
+
	UCL_OBJECT_BINARY = (1 << 7), /**< Object contains raw binary data */
+
	UCL_OBJECT_SQUOTED = (1 << 8) /**< Object has been enclosed in single quotes */
} ucl_object_flags_t;

/**
@@ -463,6 +466,13 @@ UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *e
		const char *key, size_t keylen, bool copy_key);

/**
+
 * Reserve space in ucl array or object for `elt` elements
+
 * @param obj object to reserve
+
 * @param reserved size to reserve in an object
+
 */
+
UCL_EXTERN void ucl_object_reserve (ucl_object_t *obj, size_t reserved);
+

+
/**
 * Append an element to the end of array object
 * @param top destination object (must NOT be NULL)
 * @param elt element to append (must NOT be NULL)
@@ -534,6 +544,13 @@ UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);

/**
+
 * Return size of the array `top`
+
 * @param top object to get size from (must be of type UCL_ARRAY)
+
 * @return size of the array
+
 */
+
UCL_EXTERN unsigned int ucl_array_size (const ucl_object_t *top);
+

+
/**
 * Return object identified by index of the array `top`
 * @param top object to get a key from (must be of type UCL_ARRAY)
 * @param index array index to return
@@ -830,7 +847,7 @@ UCL_EXTERN ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it,
		const ucl_object_t *obj);

/**
-
 * Get the next object from the `obj`. This fucntion iterates over arrays, objects
+
 * Get the next object from the `obj`. This function iterates over arrays, objects
 * and implicit arrays
 * @param iter safe iterator
 * @param expand_values expand explicit arrays and objects
@@ -848,7 +865,7 @@ enum ucl_iterate_type {
};

/**
-
 * Get the next object from the `obj`. This fucntion iterates over arrays, objects
+
 * Get the next object from the `obj`. This function iterates over arrays, objects
 * and implicit arrays if needed
 * @param iter safe iterator
 * @param
@@ -912,7 +929,7 @@ struct ucl_parser;
UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);

/**
-
 * Sets the default priority for the parser applied to chunks that does not
+
 * Sets the default priority for the parser applied to chunks that do not
 * specify priority explicitly
 * @param parser parser object
 * @param prio default priority (0 .. 16)
@@ -921,6 +938,14 @@ UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
UCL_EXTERN bool ucl_parser_set_default_priority (struct ucl_parser *parser,
		unsigned prio);
/**
+
 * Gets the default priority for the parser applied to chunks that do not
+
 * specify priority explicitly
+
 * @param parser parser object
+
 * @return true default priority (0 .. 16), -1 for failure
+
 */
+
UCL_EXTERN int ucl_parser_get_default_priority (struct ucl_parser *parser);
+

+
/**
 * Register new handler for a macro
 * @param parser parser object
 * @param macro macro name (without leading dot)
@@ -997,6 +1022,16 @@ UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
		const unsigned char *data, size_t len, unsigned priority);

/**
+
 * Insert new chunk to a parser (must have previously processed data with an existing top object)
+
 * @param parser parser structure
+
 * @param data the pointer to the beginning of a chunk
+
 * @param len the length of a chunk
+
 * @return true if chunk has been added and false in case of error
+
 */
+
UCL_EXTERN bool ucl_parser_insert_chunk (struct ucl_parser *parser,
+
		const unsigned char *data, size_t len);
+

+
/**
 * Full version of ucl_add_chunk with priority and duplicate strategy
 * @param parser parser structure
 * @param data the pointer to the beginning of a chunk
@@ -1019,7 +1054,7 @@ UCL_EXTERN bool ucl_parser_add_chunk_full (struct ucl_parser *parser,
 * @return true if string has been added and false in case of error
 */
UCL_EXTERN bool ucl_parser_add_string (struct ucl_parser *parser,
-
		const char *data,size_t len);
+
		const char *data, size_t len);

/**
 * Load ucl object from a string
@@ -1125,6 +1160,29 @@ UCL_EXTERN bool ucl_set_include_path (struct ucl_parser *parser,
UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);

/**
+
 * Get the current stack object as stack accessor function for use in macro
+
 * functions (refcount is increased)
+
 * @param parser parser object
+
 * @param depth depth of stack to retrieve (top is 0)
+
 * @return current stack object or NULL
+
 */
+
UCL_EXTERN ucl_object_t* ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth);
+

+
/**
+
 * Peek at the character at the current chunk position
+
 * @param parser parser structure
+
 * @return current chunk position character
+
 */
+
UCL_EXTERN unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser);
+

+
/**
+
 * Skip the character at the current chunk position
+
 * @param parser parser structure
+
 * @return success boolean
+
 */
+
UCL_EXTERN bool ucl_parser_chunk_skip (struct ucl_parser *parser);
+

+
/**
 * Get the error string if parsing has been failed
 * @param parser parser object
 * @return error description
@@ -1185,7 +1243,7 @@ UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments,
 * Move comment from `from` object to `to` object
 * @param comments comments object
 * @param what source object
-
 * @param whith destination object
+
 * @param with destination object
 * @return `true` if `from` has comment and it has been moved to `to`
 */
UCL_EXTERN bool ucl_comments_move (ucl_object_t *comments,
@@ -1221,6 +1279,34 @@ UCL_EXTERN bool ucl_parser_pubkey_add (struct ucl_parser *parser,
UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename,
		bool need_expand);

+
/**
+
 * Defines special handler for certain types of data (identified by magic)
+
 */
+
typedef bool (*ucl_parser_special_handler_t) (struct ucl_parser *parser,
+
		const unsigned char *source, size_t source_len,
+
		unsigned char **destination, size_t *dest_len,
+
		void *user_data);
+

+
/**
+
 * Special handler structure
+
 */
+
struct ucl_parser_special_handler {
+
	const unsigned char *magic;
+
	size_t magic_len;
+
	ucl_parser_special_handler_t handler;
+
	void (*free_function) (unsigned char *data, size_t len, void *user_data);
+
	void *user_data;
+
	struct ucl_parser_special_handler *next; /* Used internally */
+
};
+

+
/**
+
 * Add special handler for a parser
+
 * @param parser parser structure
+
 * @param handler handler structure
+
 */
+
UCL_EXTERN void ucl_parser_add_special_handler (struct ucl_parser *parser,
+
		struct ucl_parser_special_handler *handler);
+

/** @} */

/**
@@ -1420,7 +1506,7 @@ enum ucl_schema_error_code {
struct ucl_schema_error {
	enum ucl_schema_error_code code;	/**< error code */
	char msg[128];						/**< error message */
-
	const ucl_object_t *obj;			/**< object where error occured */
+
	const ucl_object_t *obj;			/**< object where error occurred */
};

/**
@@ -1428,7 +1514,7 @@ struct ucl_schema_error {
 * @param schema schema object
 * @param obj object to validate
 * @param err error pointer, if this parameter is not NULL and error has been
-
 * occured, then `err` is filled with the exact error definition.
+
 * occurred, then `err` is filled with the exact error definition.
 * @return true if `obj` is valid using `schema`
 */
UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
@@ -1440,7 +1526,7 @@ UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
 * @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.
+
 * occurred, 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,
@@ -1456,7 +1542,7 @@ UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
 * @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.
+
 * occurred, 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,
modified external/libucl/lua/lua_ucl.c
@@ -68,13 +68,16 @@ func = "huh";

#define PARSER_META "ucl.parser.meta"
#define EMITTER_META "ucl.emitter.meta"
-
#define NULL_META "null.emitter.meta"
+
#define NULL_META "ucl.null.meta"
#define OBJECT_META "ucl.object.meta"
+
#define UCL_OBJECT_TYPE_META "ucl.type.object"
+
#define UCL_ARRAY_TYPE_META "ucl.type.array"
+
#define UCL_IMPL_ARRAY_TYPE_META "ucl.type.impl_array"

static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
-
static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
-
static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
+
static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags);
+
static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags);

static void *ucl_null;

@@ -141,25 +144,22 @@ ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
{
	const ucl_object_t *cur;
	ucl_object_iter_t it = NULL;
-
	int nelt = 0;

	if (allow_array && obj->next != NULL) {
		/* Actually we need to push this as an array */
		return ucl_object_lua_push_array (L, obj);
	}

-
	/* Optimize allocation by preallocation of table */
-
	while (ucl_object_iterate (obj, &it, true) != NULL) {
-
		nelt ++;
-
	}
-

-
	lua_createtable (L, 0, nelt);
+
	lua_createtable (L, 0, obj->len);
	it = NULL;

	while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
		ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
	}

+
	luaL_getmetatable (L, UCL_OBJECT_TYPE_META);
+
	lua_setmetatable (L, -2);
+

	return 1;
}

@@ -187,6 +187,9 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
			i ++;
		}

+
		luaL_getmetatable (L, UCL_ARRAY_TYPE_META);
+
		lua_setmetatable (L, -2);
+

		ucl_object_iterate_free (it);
	}
	else {
@@ -202,6 +205,9 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
			lua_rawseti (L, -2, i);
			i ++;
		}
+

+
		luaL_getmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
+
		lua_setmetatable (L, -2);
	}

	return 1;
@@ -289,55 +295,101 @@ ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
 * @param idx
 */
static ucl_object_t *
-
ucl_object_lua_fromtable (lua_State *L, int idx)
+
ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)
{
-
	ucl_object_t *obj, *top = NULL;
+
	ucl_object_t *obj, *top = NULL, *cur;
	size_t keylen;
	const char *k;
-
	bool is_array = true;
-
	int max = INT_MIN;
+
	bool is_array = true, is_implicit = false, found_mt = false;
+
	size_t max = 0, nelts = 0;

	if (idx < 0) {
		/* For negative indicies we want to invert them */
		idx = lua_gettop (L) + idx + 1;
	}
-
	/* Check for array */
-
	lua_pushnil (L);
-
	while (lua_next (L, idx) != 0) {
-
		if (lua_type (L, -2) == LUA_TNUMBER) {
-
			double num = lua_tonumber (L, -2);
-
			if (num == (int)num) {
-
				if (num > max) {
-
					max = num;
-
				}
-
			}
-
			else {
-
				/* Keys are not integer */
-
				lua_pop (L, 2);
+

+
	/* First, we check from metatable */
+
	if (luaL_getmetafield (L, idx, "class") != 0) {
+

+
		if (lua_type (L, -1) == LUA_TSTRING) {
+
			const char *classname = lua_tostring (L, -1);
+

+
			if (strcmp (classname, UCL_OBJECT_TYPE_META) == 0) {
				is_array = false;
-
				break;
+
				found_mt = true;
+
			} else if (strcmp (classname, UCL_ARRAY_TYPE_META) == 0) {
+
				is_array = true;
+
				found_mt = true;
+
#if LUA_VERSION_NUM >= 502
+
				max = lua_rawlen (L, idx);
+
#else
+
				max = lua_objlen (L, idx);
+
#endif
+
				nelts = max;
+
			} else if (strcmp (classname, UCL_IMPL_ARRAY_TYPE_META) == 0) {
+
				is_array = true;
+
				is_implicit = true;
+
				found_mt = true;
+
#if LUA_VERSION_NUM >= 502
+
				max = lua_rawlen (L, idx);
+
#else
+
				max = lua_objlen (L, idx);
+
#endif
+
				nelts = max;
			}
		}
-
		else {
-
			/* Keys are not numeric */
-
			lua_pop (L, 2);
-
			is_array = false;
-
			break;
-
		}
+

		lua_pop (L, 1);
	}

+
	if (!found_mt) {
+
		/* Check for array */
+
		lua_pushnil (L);
+
		while (lua_next (L, idx) != 0) {
+
			if (lua_type (L, -2) == LUA_TNUMBER) {
+
				double num = lua_tonumber (L, -2);
+
				if (num == (int) num) {
+
					if (num > max) {
+
						max = num;
+
					}
+
				} else {
+
					/* Keys are not integer */
+
					is_array = false;
+
				}
+
			} else {
+
				/* Keys are not numeric */
+
				is_array = false;
+
			}
+
			lua_pop (L, 1);
+
			nelts ++;
+
		}
+
	}
+

	/* Table iterate */
	if (is_array) {
		int i;

-
		top = ucl_object_typed_new (UCL_ARRAY);
+
		if (!is_implicit) {
+
			top = ucl_object_typed_new (UCL_ARRAY);
+
			ucl_object_reserve (top, nelts);
+
		}
+
		else {
+
			top = NULL;
+
		}
+

		for (i = 1; i <= max; i ++) {
			lua_pushinteger (L, i);
			lua_gettable (L, idx);
-
			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
+

+
			obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags);
+

			if (obj != NULL) {
-
				ucl_array_append (top, obj);
+
				if (is_implicit) {
+
					DL_APPEND (top, obj);
+
				}
+
				else {
+
					ucl_array_append (top, obj);
+
				}
			}
			lua_pop (L, 1);
		}
@@ -345,15 +397,25 @@ ucl_object_lua_fromtable (lua_State *L, int idx)
	else {
		lua_pushnil (L);
		top = ucl_object_typed_new (UCL_OBJECT);
+
		ucl_object_reserve (top, nelts);
+

		while (lua_next (L, idx) != 0) {
			/* copy key to avoid modifications */
-
			k = lua_tolstring (L, -2, &keylen);
-
			obj = ucl_object_lua_fromelt (L, lua_gettop (L));
+
			lua_pushvalue (L, -2);
+
			k = lua_tolstring (L, -1, &keylen);
+
			obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags);

			if (obj != NULL) {
				ucl_object_insert_key (top, obj, k, keylen, true);
+

+
				DL_FOREACH (obj, cur) {
+
					if (cur->keylen == 0) {
+
						cur->keylen = obj->keylen;
+
						cur->key = obj->key;
+
					}
+
				}
			}
-
			lua_pop (L, 1);
+
			lua_pop (L, 2);
		}
	}

@@ -367,18 +429,27 @@ ucl_object_lua_fromtable (lua_State *L, int idx)
 * @param idx
 */
static ucl_object_t *
-
ucl_object_lua_fromelt (lua_State *L, int idx)
+
ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)
{
	int type;
	double num;
	ucl_object_t *obj = NULL;
	struct ucl_lua_funcdata *fd;
+
	const char *str;
+
	size_t sz;

	type = lua_type (L, idx);

	switch (type) {
	case LUA_TSTRING:
-
		obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
+
		str = lua_tolstring (L, idx, &sz);
+

+
		if (str) {
+
			obj = ucl_object_fromstring_common (str, sz, flags);
+
		}
+
		else {
+
			obj = ucl_object_typed_new (UCL_NULL);
+
		}
		break;
	case LUA_TNUMBER:
		num = lua_tonumber (L, idx);
@@ -406,13 +477,13 @@ ucl_object_lua_fromelt (lua_State *L, int idx)
				lua_insert (L, 1); /* func, gen, obj */
				lua_insert (L, 2); /* func, obj, gen */
				lua_call(L, 2, 1);
-
				obj = ucl_object_lua_fromelt (L, 1);
+
				obj = ucl_object_lua_fromelt (L, 1, flags);
			}
			lua_pop (L, 2);
		}
		else {
			if (type == LUA_TTABLE) {
-
				obj = ucl_object_lua_fromtable (L, idx);
+
				obj = ucl_object_lua_fromtable (L, idx, flags);
			}
			else if (type == LUA_TFUNCTION) {
				fd = malloc (sizeof (*fd));
@@ -451,10 +522,38 @@ ucl_object_lua_import (lua_State *L, int idx)
	t = lua_type (L, idx);
	switch (t) {
	case LUA_TTABLE:
-
		obj = ucl_object_lua_fromtable (L, idx);
+
		obj = ucl_object_lua_fromtable (L, idx, 0);
		break;
	default:
-
		obj = ucl_object_lua_fromelt (L, idx);
+
		obj = ucl_object_lua_fromelt (L, idx, 0);
+
		break;
+
	}
+

+
	return obj;
+
}
+

+
/**
+
 * @function ucl_object_lua_import_escape(L, idx)
+
 * Extracts ucl object from lua variable at `idx` position escaping JSON strings
+
 * @see ucl_object_push_lua for conversion definitions
+
 * @param {lua_state} L lua state machine pointer
+
 * @param {int} idx index where the source variable is placed
+
 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
+
 * this object thus needs to be unref'ed after usage.
+
 */
+
ucl_object_t *
+
ucl_object_lua_import_escape (lua_State *L, int idx)
+
{
+
	ucl_object_t *obj;
+
	int t;
+

+
	t = lua_type (L, idx);
+
	switch (t) {
+
	case LUA_TTABLE:
+
		obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);
+
		break;
+
	default:
+
		obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);
		break;
	}

@@ -590,6 +689,76 @@ lua_ucl_parser_parse_file (lua_State *L)
}

/***
+
 * @method parser:register_variable(name, value)
+
 * Register parser variable
+
 * @param {string} name name of variable
+
 * @param {string} value value of variable
+
 * @return {bool} success
+
@example
+
local parser = ucl.parser()
+
local res = parser:register_variable('CONFDIR', '/etc/foo')
+
 */
+
static int
+
lua_ucl_parser_register_variable (lua_State *L)
+
{
+
	struct ucl_parser *parser;
+
	const char *name, *value;
+
	int ret = 2;
+

+
	parser = lua_ucl_parser_get (L, 1);
+
	name = luaL_checkstring (L, 2);
+
	value = luaL_checkstring (L, 3);
+

+
	if (parser != NULL && name != NULL && value != NULL) {
+
		ucl_parser_register_variable (parser, name, value);
+
		lua_pushboolean (L, true);
+
		ret = 1;
+
	}
+
	else {
+
		return luaL_error (L, "invalid arguments");
+
	}
+

+
	return ret;
+
}
+

+
/***
+
 * @method parser:register_variables(vars)
+
 * Register parser variables
+
 * @param {table} vars names/values of variables
+
 * @return {bool} success
+
@example
+
local parser = ucl.parser()
+
local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'})
+
 */
+
static int
+
lua_ucl_parser_register_variables (lua_State *L)
+
{
+
	struct ucl_parser *parser;
+
	const char *name, *value;
+
	int ret = 2;
+

+
	parser = lua_ucl_parser_get (L, 1);
+

+
	if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) {
+
		for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
+
			lua_pushvalue (L, -2);
+
			name = luaL_checkstring (L, -1);
+
			value = luaL_checkstring (L, -2);
+
			ucl_parser_register_variable (parser, name, value);
+
			lua_pop (L, 1);
+
		}
+

+
		lua_pushboolean (L, true);
+
		ret = 1;
+
	}
+
	else {
+
		return luaL_error (L, "invalid arguments");
+
	}
+

+
	return ret;
+
}
+

+
/***
 * @method parser:parse_string(input)
 * Parse UCL object from file.
 * @param {string} input string to parse
@@ -630,6 +799,52 @@ lua_ucl_parser_parse_string (lua_State *L)
	return ret;
}

+
struct _rspamd_lua_text {
+
	const char *start;
+
	unsigned int len;
+
	unsigned int flags;
+
};
+

+
/***
+
 * @method parser:parse_text(input)
+
 * Parse UCL object from file.
+
 * @param {string} input string to parse
+
 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
+
 */
+
static int
+
lua_ucl_parser_parse_text (lua_State *L)
+
{
+
	struct ucl_parser *parser;
+
	struct _rspamd_lua_text *t;
+
	enum ucl_parse_type type = UCL_PARSE_UCL;
+
	int ret = 2;
+

+
	parser = lua_ucl_parser_get (L, 1);
+
	t = luaL_checkudata (L, 2, "rspamd{text}");
+

+
	if (lua_type (L, 3) == LUA_TSTRING) {
+
		type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
+
	}
+

+
	if (parser != NULL && t != NULL) {
+
		if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start,
+
				t->len, 0, UCL_DUPLICATE_APPEND, type)) {
+
			lua_pushboolean (L, true);
+
			ret = 1;
+
		}
+
		else {
+
			lua_pushboolean (L, false);
+
			lua_pushstring (L, ucl_parser_get_error (parser));
+
		}
+
	}
+
	else {
+
		lua_pushboolean (L, false);
+
		lua_pushstring (L, "invalid arguments");
+
	}
+

+
	return ret;
+
}
+

/***
 * @method parser:get_object()
 * Get top object from parser and export it to lua representation.
@@ -977,6 +1192,15 @@ lua_ucl_parser_mt (lua_State *L)
	lua_pushcfunction (L, lua_ucl_parser_parse_string);
	lua_setfield (L, -2, "parse_string");

+
	lua_pushcfunction (L, lua_ucl_parser_parse_text);
+
	lua_setfield (L, -2, "parse_text");
+

+
	lua_pushcfunction (L, lua_ucl_parser_register_variable);
+
	lua_setfield (L, -2, "register_variable");
+

+
	lua_pushcfunction (L, lua_ucl_parser_register_variables);
+
	lua_setfield (L, -2, "register_variables");
+

	lua_pushcfunction (L, lua_ucl_parser_get_object);
	lua_setfield (L, -2, "get_object");

@@ -1021,6 +1245,49 @@ lua_ucl_object_mt (lua_State *L)
	lua_pop (L, 1);
}

+
static void
+
lua_ucl_types_mt (lua_State *L)
+
{
+
	luaL_newmetatable (L, UCL_OBJECT_TYPE_META);
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "__tostring");
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "tostring");
+

+
	lua_pushstring (L, UCL_OBJECT_TYPE_META);
+
	lua_setfield (L, -2, "class");
+

+
	lua_pop (L, 1);
+

+
	luaL_newmetatable (L, UCL_ARRAY_TYPE_META);
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "__tostring");
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "tostring");
+

+
	lua_pushstring (L, UCL_ARRAY_TYPE_META);
+
	lua_setfield (L, -2, "class");
+

+
	lua_pop (L, 1);
+

+
	luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "__tostring");
+

+
	lua_pushcfunction (L, lua_ucl_object_tostring);
+
	lua_setfield (L, -2, "tostring");
+

+
	lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META);
+
	lua_setfield (L, -2, "class");
+

+
	lua_pop (L, 1);
+
}
+

static int
lua_ucl_to_json (lua_State *L)
{
@@ -1073,7 +1340,7 @@ lua_ucl_to_config (lua_State *L)
 * - `yaml` - embedded yaml
 *
 * If `var` contains function, they are called during output formatting and if
-
 * they return string value, then this value is used for ouptut.
+
 * they return string value, then this value is used for output.
 * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
 * @param {string} format any available format
 * @return {string} string representation of `var` in the specific `format`.
@@ -1168,6 +1435,7 @@ luaopen_ucl (lua_State *L)
	lua_ucl_parser_mt (L);
	lua_ucl_null_mt (L);
	lua_ucl_object_mt (L);
+
	lua_ucl_types_mt (L);

	/* Create the refs weak table: */
	lua_createtable (L, 0, 2);
modified external/libucl/src/mum.h
@@ -35,7 +35,7 @@
   Random and Pseudorandom Number Generators for Cryptographic
   Applications (version 2.2.1) with 1000 bitstreams each containing
   1M bits.  MUM hashing is also faster Spooky64 and City64 on small
-
   strings (at least upto 512-bit) on Haswell and Power7.  The MUM bulk
+
   strings (at least up to 512-bit) on Haswell and Power7.  The MUM bulk
   speed (speed on very long data) is bigger than Spooky and City on
   Power7.  On Haswell the bulk speed is bigger than Spooky one and
   close to City speed.  */
@@ -172,7 +172,7 @@ _mum_le (uint64_t v) {
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  return _mum_bswap64 (v);
#else
-
#error "Unknown endianess"
+
#error "Unknown endianness"
#endif
}

@@ -183,7 +183,7 @@ _mum_le32 (uint32_t v) {
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  return _mum_bswap32 (v);
#else
-
#error "Unknown endianess"
+
#error "Unknown endianness"
#endif
}

@@ -396,7 +396,7 @@ mum_hash64 (uint64_t key, uint64_t seed) {
}

/* Hash data KEY of length LEN and SEED.  The hash depends on the
-
   target endianess and the unroll factor.  */
+
   target endianness and the unroll factor.  */
static inline uint64_t
mum_hash (const void *key, size_t len, uint64_t seed) {
#if defined(__x86_64__) && defined(_MUM_FRESH_GCC)
modified external/libucl/src/ucl_emitter.c
@@ -424,8 +424,16 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
		break;
	case UCL_STRING:
		ucl_emitter_print_key (print_key, ctx, obj, compact);
-
		if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
-
			ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
+
		if (ctx->id == UCL_EMIT_CONFIG) {
+
			if (ucl_maybe_long_string (obj)) {
+
				ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
+
			} else {
+
				if (obj->flags & UCL_OBJECT_SQUOTED) {
+
					ucl_elt_string_write_squoted (obj->value.sv, obj->len, ctx);
+
				} else {
+
					ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
+
				}
+
			}
		}
		else {
			ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
modified external/libucl/src/ucl_emitter_utils.c
@@ -71,6 +71,13 @@ static const struct ucl_emitter_context ucl_standard_emitters[] = {
	}
};

+
static inline void
+
_ucl_emitter_free(void *p)
+
{
+

+
    free(p);
+
}
+

/**
 * Get standard emitter context for a specified emit_type
 * @param emit_type type of emitter
@@ -102,7 +109,9 @@ ucl_elt_string_write_json (const char *str, size_t size,
	func->ucl_emitter_append_character ('"', 1, func->ud);

	while (size) {
-
		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_DENIED)) {
+
		if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|
+
				UCL_CHARACTER_DENIED|
+
				UCL_CHARACTER_WHITESPACE_UNSAFE))) {
			if (len > 0) {
				func->ucl_emitter_append_len (c, len, func->ud);
			}
@@ -122,15 +131,21 @@ ucl_elt_string_write_json (const char *str, size_t size,
			case '\f':
				func->ucl_emitter_append_len ("\\f", 2, func->ud);
				break;
+
			case '\v':
+
				func->ucl_emitter_append_len ("\\u000B", 6, func->ud);
+
				break;
			case '\\':
				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
				break;
+
			case ' ':
+
				func->ucl_emitter_append_character (' ', 1, func->ud);
+
				break;
			case '"':
				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
				break;
			default:
				/* Emit unicode unknown character */
-
				func->ucl_emitter_append_len ("\\uFFFD", 5, func->ud);
+
				func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);
				break;
			}
			len = 0;
@@ -151,6 +166,40 @@ ucl_elt_string_write_json (const char *str, size_t size,
}

void
+
ucl_elt_string_write_squoted (const char *str, size_t size,
+
		struct ucl_emitter_context *ctx)
+
{
+
	const char *p = str, *c = str;
+
	size_t len = 0;
+
	const struct ucl_emitter_functions *func = ctx->func;
+

+
	func->ucl_emitter_append_character ('\'', 1, func->ud);
+

+
	while (size) {
+
		if (*p == '\'') {
+
			if (len > 0) {
+
				func->ucl_emitter_append_len (c, len, func->ud);
+
			}
+

+
			len = 0;
+
			c = ++p;
+
			func->ucl_emitter_append_len ("\\\'", 2, func->ud);
+
		}
+
		else {
+
			p ++;
+
			len ++;
+
		}
+
		size --;
+
	}
+

+
	if (len > 0) {
+
		func->ucl_emitter_append_len (c, len, func->ud);
+
	}
+

+
	func->ucl_emitter_append_character ('\'', 1, func->ud);
+
}
+

+
void
ucl_elt_string_write_multiline (const char *str, size_t size,
		struct ucl_emitter_context *ctx)
{
@@ -363,7 +412,7 @@ ucl_object_emit_memory_funcs (void **pmem)
		f->ucl_emitter_append_double = ucl_utstring_append_double;
		f->ucl_emitter_append_int = ucl_utstring_append_int;
		f->ucl_emitter_append_len = ucl_utstring_append_len;
-
		f->ucl_emitter_free_func = free;
+
		f->ucl_emitter_free_func = _ucl_emitter_free;
		utstring_new (s);
		f->ud = s;
		*pmem = s->d;
@@ -412,7 +461,7 @@ ucl_object_emit_fd_funcs (int fd)
		f->ucl_emitter_append_double = ucl_fd_append_double;
		f->ucl_emitter_append_int = ucl_fd_append_int;
		f->ucl_emitter_append_len = ucl_fd_append_len;
-
		f->ucl_emitter_free_func = free;
+
		f->ucl_emitter_free_func = _ucl_emitter_free;
		f->ud = ip;
	}

modified external/libucl/src/ucl_hash.c
@@ -143,10 +143,10 @@ ucl_hash_caseless_func (const ucl_object_t *o)
		u.c.c2 = lc_map[u.c.c2];
		u.c.c3 = lc_map[u.c.c3];
		u.c.c4 = lc_map[u.c.c4];
-
		u.c.c1 = lc_map[u.c.c5];
-
		u.c.c2 = lc_map[u.c.c6];
-
		u.c.c3 = lc_map[u.c.c7];
-
		u.c.c4 = lc_map[u.c.c8];
+
		u.c.c5 = lc_map[u.c.c5];
+
		u.c.c6 = lc_map[u.c.c6];
+
		u.c.c7 = lc_map[u.c.c7];
+
		u.c.c8 = lc_map[u.c.c8];
		r = mum_hash_step (r, u.pp);
	}

@@ -154,16 +154,22 @@ ucl_hash_caseless_func (const ucl_object_t *o)
	switch (leftover) {
	case 7:
		u.c.c7 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 6:
		u.c.c6 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 5:
		u.c.c5 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 4:
		u.c.c4 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 3:
		u.c.c3 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 2:
		u.c.c2 = lc_map[(unsigned char)s[i++]];
+
		/* FALLTHRU */
	case 1:
		u.c.c1 = lc_map[(unsigned char)s[i]];
		r = mum_hash_step (r, u.pp);
@@ -177,7 +183,45 @@ static inline int
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
{
	if (k1->keylen == k2->keylen) {
-
		return memcmp (k1->key, k2->key, k1->keylen) == 0;
+
		unsigned fp, i;
+
		const char *s = k1->key, *d = k2->key;
+
		unsigned char c1, c2, c3, c4;
+
		union {
+
			unsigned char c[4];
+
			uint32_t n;
+
		} cmp1, cmp2;
+
		size_t leftover = k1->keylen % 4;
+

+
		fp = k1->keylen - leftover;
+

+
		for (i = 0; i != fp; i += 4) {
+
			c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
+
			cmp1.c[0] = lc_map[c1];
+
			cmp1.c[1] = lc_map[c2];
+
			cmp1.c[2] = lc_map[c3];
+
			cmp1.c[3] = lc_map[c4];
+

+
			c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
+
			cmp2.c[0] = lc_map[c1];
+
			cmp2.c[1] = lc_map[c2];
+
			cmp2.c[2] = lc_map[c3];
+
			cmp2.c[3] = lc_map[c4];
+

+
			if (cmp1.n != cmp2.n) {
+
				return 0;
+
			}
+
		}
+

+
		while (leftover > 0) {
+
			if (lc_map[(unsigned char)s[i]] != lc_map[(unsigned char)d[i]]) {
+
				return 0;
+
			}
+

+
			leftover--;
+
			i++;
+
		}
+

+
		return 1;
	}

	return 0;
@@ -418,6 +462,7 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
{
	khiter_t k;
	struct ucl_hash_elt *elt;
+
	size_t i;

	if (hashlin == NULL) {
		return;
@@ -430,8 +475,15 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
		k = kh_get (ucl_hash_caseless_node, h, obj);
		if (k != kh_end (h)) {
			elt = &kh_value (h, k);
+
			i = elt->ar_idx;
			kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
			kh_del (ucl_hash_caseless_node, h, k);
+

+
			/* Update subsequent elts */
+
			for (; i < hashlin->ar.n; i ++) {
+
				elt = &kh_value (h, i);
+
				elt->ar_idx --;
+
			}
		}
	}
	else {
@@ -440,8 +492,37 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
		k = kh_get (ucl_hash_node, h, obj);
		if (k != kh_end (h)) {
			elt = &kh_value (h, k);
+
			i = elt->ar_idx;
			kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
			kh_del (ucl_hash_node, h, k);
+

+
			/* Update subsequent elts */
+
			for (; i < hashlin->ar.n; i ++) {
+
				elt = &kh_value (h, i);
+
				elt->ar_idx --;
+
			}
		}
	}
}
+

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

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

+
		if (hashlin->caseless) {
+
			khash_t(ucl_hash_caseless_node) *h = (khash_t(
+
					ucl_hash_caseless_node) *)
+
					hashlin->hash;
+
			kh_resize (ucl_hash_caseless_node, h, sz * 2);
+
		} else {
+
			khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
					hashlin->hash;
+
			kh_resize (ucl_hash_node, h, sz * 2);
+
		}
+
	}
+
}

\ No newline at end of file
modified external/libucl/src/ucl_hash.h
@@ -90,4 +90,10 @@ const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
 */
bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);

+
/**
+
 * Reserves space in hash
+
 * @param hashlin
+
 */
+
void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz);
+

#endif
modified external/libucl/src/ucl_internal.h
@@ -63,7 +63,9 @@
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_PARAM_H
-
#include <sys/param.h>
+
# ifndef _WIN32
+
# include <sys/param.h>
+
# endif
#endif

#ifdef HAVE_LIMITS_H
@@ -76,7 +78,9 @@
#include <errno.h>
#endif
#ifdef HAVE_UNISTD_H
-
#include <unistd.h>
+
# ifndef _WIN32
+
# include <unistd.h>
+
# endif
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
@@ -91,6 +95,31 @@
#include <strings.h>
#endif

+
#if defined(_MSC_VER)
+
/* Windows hacks */
+
#include <BaseTsd.h>
+
typedef SSIZE_T ssize_t;
+
#define strdup _strdup
+
#define snprintf _snprintf
+
#define vsnprintf _vsnprintf
+
#define strcasecmp _stricmp
+
#define strncasecmp _strnicmp
+
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+
#if _MSC_VER >= 1900
+
#include <../ucrt/stdlib.h>
+
#else
+
#include <../include/stdlib.h>
+
#endif
+
#ifndef PATH_MAX
+
#define PATH_MAX _MAX_PATH
+
#endif
+

+
/* Dirname, basename implementations */
+

+

+
#endif
+

#include "utlist.h"
#include "utstring.h"
#include "uthash.h"
@@ -119,6 +148,7 @@ enum ucl_parser_state {
	UCL_STATE_OBJECT,
	UCL_STATE_ARRAY,
	UCL_STATE_KEY,
+
	UCL_STATE_KEY_OBRACE,
	UCL_STATE_VALUE,
	UCL_STATE_AFTER_VALUE,
	UCL_STATE_ARRAY_VALUE,
@@ -147,7 +177,7 @@ enum ucl_character_type {

struct ucl_macro {
	char *name;
-
	union {
+
	union _ucl_macro {
		ucl_macro_handler handler;
		ucl_context_macro_handler context_handler;
	} h;
@@ -156,22 +186,37 @@ struct ucl_macro {
	UT_hash_handle hh;
};

+
enum ucl_stack_flags {
+
	UCL_STACK_HAS_OBRACE = (1u << 0),
+
	UCL_STACK_MAX = (1u << 1),
+
};
+

struct ucl_stack {
	ucl_object_t *obj;
	struct ucl_stack *next;
-
	uint64_t level;
+
	union {
+
		struct {
+
			uint16_t level;
+
			uint16_t flags;
+
			uint32_t line;
+
		} params;
+
		uint64_t len;
+
	} e;
+
	struct ucl_chunk *chunk;
};

struct ucl_chunk {
	const unsigned char *begin;
	const unsigned char *end;
	const unsigned char *pos;
+
	char *fname;
	size_t remain;
	unsigned int line;
	unsigned int column;
	unsigned priority;
	enum ucl_duplicate_strategy strategy;
	enum ucl_parse_type parse_type;
+
	struct ucl_parser_special_handler *special_handler;
	struct ucl_chunk *next;
};

@@ -210,6 +255,7 @@ struct ucl_parser {
	struct ucl_stack *stack;
	struct ucl_chunk *chunks;
	struct ucl_pubkey *keys;
+
    struct ucl_parser_special_handler *special_handlers;
	struct ucl_variable *variables;
	ucl_variable_handler var_handler;
	void *var_data;
@@ -230,6 +276,13 @@ struct ucl_object_userdata {
 */
size_t ucl_unescape_json_string (char *str, size_t len);

+

+
/**
+
 * Unescape single quoted string inplace
+
 * @param str
+
 */
+
size_t ucl_unescape_squoted_string (char *str, size_t len);
+

/**
 * Handle include macro
 * @param data include data
@@ -434,6 +487,16 @@ ucl_emit_get_standard_context (enum ucl_emitter emit_type);
void ucl_elt_string_write_json (const char *str, size_t size,
		struct ucl_emitter_context *ctx);

+

+
/**
+
 * Serialize string as single quoted string
+
 * @param str string to emit
+
 * @param buf target buffer
+
 */
+
void
+
ucl_elt_string_write_squoted (const char *str, size_t size,
+
		struct ucl_emitter_context *ctx);
+

/**
 * Write multiline string using `EOD` as string terminator
 * @param str
@@ -573,4 +636,10 @@ bool ucl_parse_msgpack (struct ucl_parser *parser);

bool ucl_parse_csexp (struct ucl_parser *parser);

+
/**
+
 * Free ucl chunk
+
 * @param chunk
+
 */
+
void ucl_chunk_free (struct ucl_chunk *chunk);
+

#endif /* UCL_INTERNAL_H_ */
modified external/libucl/src/ucl_msgpack.c
@@ -434,7 +434,6 @@ static ssize_t ucl_msgpack_parse_ignore (struct ucl_parser *parser,
#define MSGPACK_FLAG_EXT (1 << 3)
#define MSGPACK_FLAG_ASSOC (1 << 4)
#define MSGPACK_FLAG_KEY (1 << 5)
-
#define MSGPACK_CONTAINER_BIT (1ULL << 62)

/*
 * Search tree packed in array
@@ -768,7 +767,6 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
	assert (obj_parser != NULL);

	if (obj_parser->flags & MSGPACK_FLAG_CONTAINER) {
-
		assert ((len & MSGPACK_CONTAINER_BIT) == 0);
		/*
		 * Insert new container to the stack
		 */
@@ -779,6 +777,8 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
				ucl_create_err (&parser->err, "no memory");
				return NULL;
			}
+

+
			parser->stack->chunk = parser->chunks;
		}
		else {
			stack = calloc (1, sizeof (struct ucl_stack));
@@ -788,11 +788,12 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
				return NULL;
			}

+
			stack->chunk = parser->chunks;
			stack->next = parser->stack;
			parser->stack = stack;
		}

-
		parser->stack->level = len | MSGPACK_CONTAINER_BIT;
+
		parser->stack->e.len = len;

#ifdef MSGPACK_DEBUG_PARSER
		stack = parser->stack;
@@ -823,16 +824,11 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
static bool
ucl_msgpack_is_container_finished (struct ucl_stack *container)
{
-
	uint64_t level;
-

	assert (container != NULL);

-
	if (container->level & MSGPACK_CONTAINER_BIT) {
-
		level = container->level & ~MSGPACK_CONTAINER_BIT;

-
		if (level == 0) {
-
			return true;
-
		}
+
	if (container->e.len == 0) {
+
		return true;
	}

	return false;
@@ -843,12 +839,11 @@ ucl_msgpack_insert_object (struct ucl_parser *parser,
		const unsigned char *key,
		size_t keylen, ucl_object_t *obj)
{
-
	uint64_t level;
	struct ucl_stack *container;

	container = parser->stack;
	assert (container != NULL);
-
	assert (container->level > 0);
+
	assert (container->e.len > 0);
	assert (obj != NULL);
	assert (container->obj != NULL);

@@ -875,10 +870,7 @@ ucl_msgpack_insert_object (struct ucl_parser *parser,
		return false;
	}

-
	if (container->level & MSGPACK_CONTAINER_BIT) {
-
		level = container->level & ~MSGPACK_CONTAINER_BIT;
-
		container->level = (level - 1) | MSGPACK_CONTAINER_BIT;
-
	}
+
	container->e.len--;

	return true;
}
@@ -887,7 +879,7 @@ static struct ucl_stack *
ucl_msgpack_get_next_container (struct ucl_parser *parser)
{
	struct ucl_stack *cur = NULL;
-
	uint64_t level;
+
	uint64_t len;

	cur = parser->stack;

@@ -895,17 +887,16 @@ ucl_msgpack_get_next_container (struct ucl_parser *parser)
		return NULL;
	}

-
	if (cur->level & MSGPACK_CONTAINER_BIT) {
-
		level = cur->level & ~MSGPACK_CONTAINER_BIT;
+
	len = cur->e.len;

-
		if (level == 0) {
-
			/* We need to switch to the previous container */
-
			parser->stack = cur->next;
-
			parser->cur_obj = cur->obj;
-
			free (cur);
+
	if (len == 0) {
+
		/* We need to switch to the previous container */
+
		parser->stack = cur->next;
+
		parser->cur_obj = cur->obj;
+
		free (cur);

#ifdef MSGPACK_DEBUG_PARSER
-
			cur = parser->stack;
+
		cur = parser->stack;
			while (cur) {
				fprintf(stderr, "-");
				cur = cur->next;
@@ -913,8 +904,7 @@ ucl_msgpack_get_next_container (struct ucl_parser *parser)
			fprintf(stderr, "-%s -> %d\n", parser->cur_obj->type == UCL_OBJECT ? "object" : "array", (int)parser->cur_obj->len);
#endif

-
			return ucl_msgpack_get_next_container (parser);
-
		}
+
		return ucl_msgpack_get_next_container (parser);
	}

	/*
@@ -1311,8 +1301,7 @@ ucl_msgpack_consume (struct ucl_parser *parser)

	/* Rewind to the top level container */
	ucl_msgpack_get_next_container (parser);
-
	assert (parser->stack == NULL ||
-
			(parser->stack->level & MSGPACK_CONTAINER_BIT) == 0);
+
	assert (parser->stack == NULL);

	return true;
}
modified external/libucl/src/ucl_parser.c
@@ -21,6 +21,7 @@
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

+
#include <math.h>
#include "ucl.h"
#include "ucl_internal.h"
#include "ucl_chartable.h"
@@ -44,16 +45,17 @@ struct ucl_parser_saved_state {
 * @param len
 * @return new position in chunk
 */
-
#define ucl_chunk_skipc(chunk, p)    do{					\
-
    if (*(p) == '\n') {										\
-
        (chunk)->line ++;									\
-
        (chunk)->column = 0;								\
-
    }														\
-
    else (chunk)->column ++;								\
-
    (p++);													\
-
    (chunk)->pos ++;										\
-
    (chunk)->remain --;										\
-
    } while (0)
+
#define ucl_chunk_skipc(chunk, p)    \
+
do {                                 \
+
	if (*(p) == '\n') {          \
+
		(chunk)->line ++;    \
+
		(chunk)->column = 0; \
+
	}                            \
+
	else (chunk)->column ++;     \
+
	(p++);                       \
+
	(chunk)->pos ++;             \
+
	(chunk)->remain --;          \
+
} while (0)

static inline void
ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
@@ -87,6 +89,7 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
	}

	parser->err_code = code;
+
	parser->state = UCL_STATE_ERROR;
}

static void
@@ -342,7 +345,6 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
		/* Call generic handler */
		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
				parser->var_data)) {
-
			*out_len += dstlen;
			*found = true;
			if (need_free) {
				free (dst);
@@ -459,18 +461,11 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
	}
	if (!found) {
		if (strict && parser->var_handler != NULL) {
-
			size_t var_len = 0;
-
			while (var_len < remain && p[var_len] != '}')
-
				var_len ++;
-

-
			if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free,
+
			if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
							parser->var_data)) {
				memcpy (d, dst, dstlen);
-
				ret += var_len;
-
				d += dstlen;
-
				if (need_free) {
-
					free (dst);
-
				}
+
				ret += dstlen;
+
				d += remain;
				found = true;
			}
		}
@@ -564,13 +559,15 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
 * @param need_unescape need to unescape source (and copy it)
 * @param need_lowercase need to lowercase value (and copy)
 * @param need_expand need to expand variables (and copy as well)
+
 * @param unescape_squote unescape single quoted string
 * @return output length (excluding \0 symbol)
 */
static inline ssize_t
ucl_copy_or_store_ptr (struct ucl_parser *parser,
		const unsigned char *src, unsigned char **dst,
		const char **dst_const, size_t in_len,
-
		bool need_unescape, bool need_lowercase, bool need_expand)
+
		bool need_unescape, bool need_lowercase, bool need_expand,
+
		bool unescape_squote)
{
	ssize_t ret = -1, tret;
	unsigned char *tmp;
@@ -593,8 +590,14 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
		}

		if (need_unescape) {
-
			ret = ucl_unescape_json_string (*dst, ret);
+
			if (!unescape_squote) {
+
				ret = ucl_unescape_json_string (*dst, ret);
+
			}
+
			else {
+
				ret = ucl_unescape_squoted_string (*dst, ret);
+
			}
		}
+

		if (need_expand) {
			tmp = *dst;
			tret = ret;
@@ -628,17 +631,29 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
 */
static inline ucl_object_t *
ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
-
		bool is_array, int level)
+
		bool is_array, uint32_t level, bool has_obrace)
{
	struct ucl_stack *st;
+
	bool need_free = false;

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

+
				return NULL;
+
			}
+

			obj->type = UCL_OBJECT;
		}
+

		if (obj->value.ov == NULL) {
			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
		}
@@ -647,8 +662,18 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
	else {
		if (obj == NULL) {
			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
+
			need_free = true;
		}
		else {
+
			if (obj->type == UCL_OBJECT) {
+
				/* Bad combination for merge: array and object */
+
				ucl_set_err (parser, UCL_EMERGE,
+
						"cannot merge an object with an array",
+
						&parser->err);
+

+
				return NULL;
+
			}
+

			obj->type = UCL_ARRAY;
		}
		parser->state = UCL_STATE_VALUE;
@@ -659,12 +684,38 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
	if (st == NULL) {
		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
				&parser->err);
-
		ucl_object_unref (obj);
+
		if (need_free) {
+
			ucl_object_unref (obj);
+
		}
+

		return NULL;
	}

	st->obj = obj;
-
	st->level = level;
+

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

+
		return NULL;
+
	}
+

+

+
	st->e.params.level = level;
+
	st->e.params.line = parser->chunks->line;
+
	st->chunk = parser->chunks;
+

+
	if (has_obrace) {
+
		st->e.params.flags = UCL_STACK_HAS_OBRACE;
+
	}
+
	else {
+
		st->e.params.flags = 0;
+
	}
+

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

@@ -969,7 +1020,10 @@ ucl_lex_number (struct ucl_parser *parser,
 */
static bool
ucl_lex_json_string (struct ucl_parser *parser,
-
		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
+
		struct ucl_chunk *chunk,
+
		bool *need_unescape,
+
		bool *ucl_escape,
+
		bool *var_expand)
{
	const unsigned char *p = chunk->pos;
	unsigned char c;
@@ -1009,7 +1063,8 @@ ucl_lex_json_string (struct ucl_parser *parser,
						ucl_chunk_skipc (chunk, p);
					}
					if (p >= chunk->end) {
-
						ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
+
						ucl_set_err (parser, UCL_ESYNTAX,
+
								"unfinished escape character",
								&parser->err);
						return false;
					}
@@ -1035,7 +1090,54 @@ ucl_lex_json_string (struct ucl_parser *parser,
		ucl_chunk_skipc (chunk, p);
	}

-
	ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
+
	ucl_set_err (parser, UCL_ESYNTAX,
+
			"no quote at the end of json string",
+
			&parser->err);
+
	return false;
+
}
+

+
/**
+
 * Process single quoted string
+
 * @param parser
+
 * @param chunk
+
 * @param need_unescape
+
 * @return
+
 */
+
static bool
+
ucl_lex_squoted_string (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, bool *need_unescape)
+
{
+
	const unsigned char *p = chunk->pos;
+
	unsigned char c;
+

+
	while (p < chunk->end) {
+
		c = *p;
+
		if (c == '\\') {
+
			ucl_chunk_skipc (chunk, p);
+

+
			if (p >= chunk->end) {
+
				ucl_set_err (parser, UCL_ESYNTAX,
+
						"unfinished escape character",
+
						&parser->err);
+
				return false;
+
			}
+
			else {
+
				ucl_chunk_skipc (chunk, p);
+
			}
+

+
			*need_unescape = true;
+
			continue;
+
		}
+
		else if (c == '\'') {
+
			ucl_chunk_skipc (chunk, p);
+
			return true;
+
		}
+

+
		ucl_chunk_skipc (chunk, p);
+
	}
+

+
	ucl_set_err (parser, UCL_ESYNTAX,
+
			"no quote at the end of single quoted string",
			&parser->err);
	return false;
}
@@ -1075,12 +1177,20 @@ bool
ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
{
	ucl_hash_t *container;
-
	ucl_object_t *tobj;
+
	ucl_object_t *tobj = NULL, *cur;
	char errmsg[256];

	container = parser->stack->obj->value.ov;

-
	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
+
	DL_FOREACH (parser->stack->obj, cur) {
+
		tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (cur->value.ov, nobj));
+

+
		if (tobj != NULL) {
+
			break;
+
		}
+
	}
+

+

	if (tobj == NULL) {
		container = ucl_hash_insert_object (container, nobj,
				parser->flags & UCL_PARSER_KEY_LOWERCASE);
@@ -1102,8 +1212,6 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
			 * - if a new object has bigger priority, then we overwrite an old one
			 * - if a new object has lower priority, then we ignore it
			 */
-

-

			/* Special case for inherited objects */
			if (tobj->flags & UCL_OBJECT_INHERITED) {
				prinew = priold + 1;
@@ -1370,7 +1478,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
	/* Create a new object */
	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
-
			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
+
			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE,
+
			false, false);
	if (keylen == -1) {
		ucl_object_unref (nobj);
		return false;
@@ -1566,7 +1675,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
	const unsigned char *p, *c;
	ucl_object_t *obj = NULL;
	unsigned int stripped_spaces;
-
	int str_len;
+
	ssize_t str_len;
	bool need_unescape = false, ucl_escape = false, var_expand = false;

	p = chunk->pos;
@@ -1604,20 +1713,57 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
					&obj->trash_stack[UCL_TRASH_VALUE],
					&obj->value.sv, str_len, need_unescape, false,
-
					var_expand)) == -1) {
+
					var_expand, false)) == -1) {
				return false;
			}
+

+
			obj->len = str_len;
+
			parser->state = UCL_STATE_AFTER_VALUE;
+

+
			return true;
+
			break;
+
		case '\'':
+
			ucl_chunk_skipc (chunk, p);
+

+
			if (!ucl_lex_squoted_string (parser, chunk, &need_unescape)) {
+
				return false;
+
			}
+

+
			obj = ucl_parser_get_container (parser);
+
			if (!obj) {
+
				return false;
+
			}
+

+
			str_len = chunk->pos - c - 2;
+
			obj->type = UCL_STRING;
+
			obj->flags |= UCL_OBJECT_SQUOTED;
+

+
			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
+
					&obj->trash_stack[UCL_TRASH_VALUE],
+
					&obj->value.sv, str_len, need_unescape, false,
+
					var_expand, true)) == -1) {
+
				return false;
+
			}
+

			obj->len = str_len;

			parser->state = UCL_STATE_AFTER_VALUE;
-
			p = chunk->pos;

			return true;
			break;
		case '{':
			obj = ucl_parser_get_container (parser);
+
			if (obj == NULL) {
+
				return false;
+
			}
			/* We have a new object */
-
			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
+
			if (parser->stack) {
+
				obj = ucl_parser_add_container (obj, parser, false,
+
						parser->stack->e.params.level, true);
+
			}
+
			else {
+
				return false;
+
			}
			if (obj == NULL) {
				return false;
			}
@@ -1628,8 +1774,18 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
			break;
		case '[':
			obj = ucl_parser_get_container (parser);
+
			if (obj == NULL) {
+
				return false;
+
			}
			/* We have a new array */
-
			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
+
			if (parser->stack) {
+
				obj = ucl_parser_add_container (obj, parser, true,
+
						parser->stack->e.params.level, true);
+
			}
+
			else {
+
				return false;
+
			}
+

			if (obj == NULL) {
				return false;
			}
@@ -1677,7 +1833,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
						if ((str_len = ucl_copy_or_store_ptr (parser, c,
								&obj->trash_stack[UCL_TRASH_VALUE],
								&obj->value.sv, str_len - 1, false,
-
								false, var_expand)) == -1) {
+
								false, var_expand, false)) == -1) {
							return false;
						}
						obj->len = str_len;
@@ -1689,6 +1845,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
				}
			}
			/* Fallback to ordinary strings */
+
			/* FALLTHRU */
		default:
parse_string:
			if (obj == NULL) {
@@ -1729,18 +1886,28 @@ parse_string:
				obj->len = 0;
				obj->type = UCL_NULL;
			}
+
			else if (str_len == 3 && memcmp (c, "nan", 3) == 0) {
+
				obj->len = 0;
+
				obj->type = UCL_FLOAT;
+
				obj->value.dv = NAN;
+
			}
+
			else if (str_len == 3 && memcmp (c, "inf", 3) == 0) {
+
				obj->len = 0;
+
				obj->type = UCL_FLOAT;
+
				obj->value.dv = INFINITY;
+
			}
			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
				obj->type = UCL_STRING;
				if ((str_len = ucl_copy_or_store_ptr (parser, c,
						&obj->trash_stack[UCL_TRASH_VALUE],
						&obj->value.sv, str_len, need_unescape,
-
						false, var_expand)) == -1) {
+
						false, var_expand, false)) == -1) {
					return false;
				}
				obj->len = str_len;
			}
+

			parser->state = UCL_STATE_AFTER_VALUE;
-
			p = chunk->pos;

			return true;
			break;
@@ -1792,6 +1959,17 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)

					/* Pop all nested objects from a stack */
					st = parser->stack;
+

+
					if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) {
+
						parser->err_code = UCL_EUNPAIRED;
+
						ucl_create_err (&parser->err,
+
								"%s:%d object closed with } is not opened with { at line %d",
+
								chunk->fname ? chunk->fname : "memory",
+
								parser->chunks->line, st->e.params.line);
+

+
						return false;
+
					}
+

					parser->stack = st->next;
					UCL_FREE (sizeof (struct ucl_stack), st);

@@ -1802,10 +1980,14 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
					while (parser->stack != NULL) {
						st = parser->stack;

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

+

						parser->stack = st->next;
						parser->cur_obj = st->obj;
						UCL_FREE (sizeof (struct ucl_stack), st);
@@ -2180,6 +2362,8 @@ ucl_state_machine (struct ucl_parser *parser)
				return false;
			}
			else {
+
				bool seen_obrace = false;
+

				/* Skip any spaces */
				while (p < chunk->end && ucl_test_character (*p,
						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
@@ -2191,20 +2375,28 @@ ucl_state_machine (struct ucl_parser *parser)
				if (*p == '[') {
					parser->state = UCL_STATE_VALUE;
					ucl_chunk_skipc (chunk, p);
+
					seen_obrace = true;
				}
				else {
-
					parser->state = UCL_STATE_KEY;
+

					if (*p == '{') {
						ucl_chunk_skipc (chunk, p);
+
						parser->state = UCL_STATE_KEY_OBRACE;
+
						seen_obrace = true;
+
					}
+
					else {
+
						parser->state = UCL_STATE_KEY;
					}
				}

				if (parser->top_obj == NULL) {
					if (parser->state == UCL_STATE_VALUE) {
-
						obj = ucl_parser_add_container (NULL, parser, true, 0);
+
						obj = ucl_parser_add_container (NULL, parser, true, 0,
+
								seen_obrace);
					}
					else {
-
						obj = ucl_parser_add_container (NULL, parser, false, 0);
+
						obj = ucl_parser_add_container (NULL, parser, false, 0,
+
								seen_obrace);
					}

					if (obj == NULL) {
@@ -2218,6 +2410,7 @@ ucl_state_machine (struct ucl_parser *parser)
			}
			break;
		case UCL_STATE_KEY:
+
		case UCL_STATE_KEY_OBRACE:
			/* Skip any spaces */
			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
				ucl_chunk_skipc (chunk, p);
@@ -2240,6 +2433,7 @@ ucl_state_machine (struct ucl_parser *parser)
				parser->state = UCL_STATE_ERROR;
				return false;
			}
+

			if (end_of_object) {
				p = chunk->pos;
				parser->state = UCL_STATE_AFTER_VALUE;
@@ -2248,8 +2442,11 @@ ucl_state_machine (struct ucl_parser *parser)
			else if (parser->state != UCL_STATE_MACRO_NAME) {
				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
					/* Parse more keys and nest objects accordingly */
-
					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
-
							parser->stack->level + 1);
+
					obj = ucl_parser_add_container (parser->cur_obj,
+
							parser,
+
							false,
+
							parser->stack->e.params.level + 1,
+
							parser->state == UCL_STATE_KEY_OBRACE);
					if (obj == NULL) {
						return false;
					}
@@ -2301,7 +2498,8 @@ ucl_state_machine (struct ucl_parser *parser)
				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",
+
							"error at %s:%d at column %d: invalid macro",
+
							chunk->fname ? chunk->fname : "memory",
							chunk->line,
							chunk->column);
					parser->state = UCL_STATE_ERROR;
@@ -2324,8 +2522,9 @@ ucl_state_machine (struct ucl_parser *parser)
						HASH_FIND (hh, parser->macroes, c, macro_len, macro);
						if (macro == NULL) {
							ucl_create_err (&parser->err,
-
									"error on line %d at column %d: "
+
									"error at %s:%d at column %d: "
									"unknown macro: '%.*s', character: '%c'",
+
									chunk->fname ? chunk->fname : "memory",
									chunk->line,
									chunk->column,
									(int) (p - c),
@@ -2341,7 +2540,8 @@ ucl_state_machine (struct ucl_parser *parser)
					else {
						/* We have invalid macro name */
						ucl_create_err (&parser->err,
-
								"error on line %d at column %d: invalid macro name",
+
								"error at %s:%d at column %d: invalid macro name",
+
								chunk->fname ? chunk->fname : "memory",
								chunk->line,
								chunk->column);
						parser->state = UCL_STATE_ERROR;
@@ -2440,6 +2640,35 @@ ucl_state_machine (struct ucl_parser *parser)
		}
	}

+
	if (parser->stack != NULL && parser->state != UCL_STATE_ERROR) {
+
		struct ucl_stack *st;
+
		bool has_error = false;
+

+
		LL_FOREACH (parser->stack, st) {
+
			if (st->chunk != parser->chunks) {
+
				break; /* Not our chunk, give up */
+
			}
+
			if (st->e.params.flags & UCL_STACK_HAS_OBRACE) {
+
				if (parser->err == NULL) {
+
					utstring_new (parser->err);
+
				}
+

+
				utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ",
+
						chunk->fname ? chunk->fname : "memory",
+
						parser->chunks->line,
+
						st->e.params.line);
+

+
				has_error = true;
+
			}
+
		}
+

+
		if (has_error) {
+
			parser->err_code = UCL_EUNPAIRED;
+

+
			return false;
+
		}
+
	}
+

	return true;
}

@@ -2489,6 +2718,16 @@ ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
	return true;
}

+
int
+
ucl_parser_get_default_priority (struct ucl_parser *parser)
+
{
+
	if (parser == NULL) {
+
		return -1;
+
	}
+

+
	return parser->default_priority;
+
}
+

void
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
		ucl_macro_handler handler, void* ud)
@@ -2602,6 +2841,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
		enum ucl_parse_type parse_type)
{
	struct ucl_chunk *chunk;
+
	struct ucl_parser_special_handler *special_handler;

	if (parser == NULL) {
		return false;
@@ -2619,6 +2859,28 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
			return false;
		}

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

+
		LL_FOREACH (parser->special_handlers, special_handler) {
+
			if (len >= special_handler->magic_len &&
+
					memcmp (data, special_handler->magic, special_handler->magic_len) == 0) {
+
				unsigned char *ndata = NULL;
+
				size_t nlen = 0;
+

+
				if (!special_handler->handler (parser, data, len, &ndata, &nlen,
+
						special_handler->user_data)) {
+
					ucl_create_err (&parser->err, "call for external handler failed");
+
					return false;
+
				}
+

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

+
				break;
+
			}
+
		}
+

		if (parse_type == UCL_PARSE_AUTO && len > 0) {
			/* We need to detect parse type by the first symbol */
			if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
@@ -2641,6 +2903,11 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
		chunk->priority = priority;
		chunk->strategy = strat;
		chunk->parse_type = parse_type;
+

+
		if (parser->cur_file) {
+
			chunk->fname = strdup (parser->cur_file);
+
		}
+

		LL_PREPEND (parser->chunks, chunk);
		parser->recursion ++;

@@ -2707,6 +2974,41 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
}

bool
+
ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data,
+
		size_t len)
+
{
+
	if (parser == NULL || parser->top_obj == NULL) {
+
		return false;
+
	}
+

+
	bool res;
+
	struct ucl_chunk *chunk;
+

+
	int state = parser->state;
+
	parser->state = UCL_STATE_INIT;
+

+
	/* Prevent inserted chunks from unintentionally closing the current object */
+
	if (parser->stack != NULL && parser->stack->next != NULL) {
+
		parser->stack->e.params.level = parser->stack->next->e.params.level;
+
	}
+

+
	res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority,
+
					parser->chunks->strategy, parser->chunks->parse_type);
+

+
	/* Remove chunk from the stack */
+
	chunk = parser->chunks;
+
	if (chunk != NULL) {
+
		parser->chunks = chunk->next;
+
		ucl_chunk_free (chunk);
+
		parser->recursion --;
+
	}
+

+
	parser->state = state;
+

+
	return res;
+
}
+

+
bool
ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
		size_t len, unsigned priority)
{
@@ -2755,3 +3057,55 @@ ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)

	return true;
}
+

+
unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser)
+
{
+
	if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
+
		parser->chunks->pos == parser->chunks->end) {
+
		return 0;
+
	}
+

+
	return( *parser->chunks->pos );
+
}
+

+
bool ucl_parser_chunk_skip (struct ucl_parser *parser)
+
{
+
	if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
+
		parser->chunks->pos == parser->chunks->end) {
+
		return false;
+
	}
+

+
	const unsigned char *p = parser->chunks->pos;
+
	ucl_chunk_skipc( parser->chunks, p );
+
	if( parser->chunks->pos != NULL ) return true;
+
	return false;
+
}
+

+
ucl_object_t*
+
ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth)
+
{
+
	ucl_object_t *obj;
+

+
	if (parser == NULL || parser->stack == NULL) {
+
		return NULL;
+
	}
+

+
	struct ucl_stack *stack = parser->stack;
+
	if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
+
	{
+
		return NULL;
+
	}
+

+
	for( unsigned int i = 0; i < depth; ++i )
+
	{
+
		stack = stack->next;
+
		if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
+
		{
+
			return NULL;
+
		}
+
	}
+

+
	obj = ucl_object_ref (stack->obj);
+
	return obj;
+
}
+

modified external/libucl/src/ucl_schema.c
@@ -49,7 +49,16 @@ static bool ucl_schema_validate (const ucl_object_t *schema,
/*
 * Create validation error
 */
-
static void
+

+
#ifdef __GNUC__
+
static inline void
+
ucl_schema_create_error (struct ucl_schema_error *err,
+
		enum ucl_schema_error_code code, const ucl_object_t *obj,
+
		const char *fmt, ...)
+
__attribute__ (( format( printf, 4, 5) ));
+
#endif
+

+
static inline void
ucl_schema_create_error (struct ucl_schema_error *err,
		enum ucl_schema_error_code code, const ucl_object_t *obj,
		const char *fmt, ...)
@@ -311,7 +320,7 @@ ucl_schema_validate_number (const ucl_object_t *schema,
			if (fabs (remainder (val, constraint)) > alpha) {
				ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
						"number %.4f is not multiple of %.4f, remainder is %.7f",
-
						val, constraint);
+
						val, constraint, remainder (val, constraint));
				ret = false;
				break;
			}
@@ -371,7 +380,7 @@ ucl_schema_validate_string (const ucl_object_t *schema,
			constraint = ucl_object_toint (elt);
			if (obj->len > constraint) {
				ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
-
						"string is too big: %.3f, maximum is: %.3f",
+
						"string is too big: %u, maximum is: %" PRId64,
						obj->len, constraint);
				ret = false;
				break;
@@ -382,7 +391,7 @@ ucl_schema_validate_string (const ucl_object_t *schema,
			constraint = ucl_object_toint (elt);
			if (obj->len < constraint) {
				ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
-
						"string is too short: %.3f, minimum is: %.3f",
+
						"string is too short: %u, minimum is: %" PRId64,
						obj->len, constraint);
				ret = false;
				break;
modified external/libucl/src/ucl_util.c
@@ -40,7 +40,9 @@
#endif

#ifdef HAVE_LIBGEN_H
-
#include <libgen.h> /* For dirname */
+
#ifndef _WIN32
+
#  include <libgen.h> /* For dirname */
+
#endif
#endif

typedef kvec_t(ucl_object_t *) ucl_array_t;
@@ -65,8 +67,10 @@ typedef kvec_t(ucl_object_t *) ucl_array_t;
#include <fetch.h>
#endif

-
#ifdef _WIN32
+
#if defined(_MSC_VER)
#include <windows.h>
+
#include <io.h>
+
#include <direct.h>

#ifndef PROT_READ
#define PROT_READ       1
@@ -87,6 +91,10 @@ typedef kvec_t(ucl_object_t *) ucl_array_t;
#define MAP_FAILED      ((void *) -1)
#endif

+
#define getcwd _getcwd
+
#define open _open
+
#define close _close
+

static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
{
	void *map = NULL;
@@ -133,16 +141,46 @@ static int ucl_munmap(void *map,size_t length)
	return(0);
}

-
static char* ucl_realpath(const char *path, char *resolved_path) {
-
    char *p;
-
    char tmp[MAX_PATH + 1];
-
    strncpy(tmp, path, sizeof(tmp)-1);
-
    p = tmp;
-
    while(*p) {
-
        if (*p == '/') *p = '\\';
-
        p++;
-
    }
-
    return _fullpath(resolved_path, tmp, MAX_PATH);
+
static char* ucl_realpath(const char *path, char *resolved_path)
+
{
+
	char *p;
+
	char tmp[MAX_PATH + 1];
+
	strncpy(tmp, path, sizeof(tmp)-1);
+
	p = tmp;
+
	while(*p) {
+
		if (*p == '/') *p = '\\';
+
		p++;
+
	}
+
	return _fullpath(resolved_path, tmp, MAX_PATH);
+
}
+

+

+
char *dirname(char *path)
+
{
+
	static char path_buffer[_MAX_PATH];
+
	char drive[_MAX_DRIVE];
+
	char dir[_MAX_DIR];
+
	char fname[_MAX_FNAME];
+
	char ext[_MAX_EXT];
+

+
	_splitpath (path, drive, dir, fname, ext);
+
	_makepath(path_buffer, drive, dir, NULL, NULL);
+

+
	return path_buffer;
+
}
+

+
char *basename(char *path)
+
{
+
	static char path_buffer[_MAX_PATH];
+
	char drive[_MAX_DRIVE];
+
	char dir[_MAX_DIR];
+
	char fname[_MAX_FNAME];
+
	char ext[_MAX_EXT];
+

+
	_splitpath(path, drive, dir, fname, ext);
+
	_makepath(path_buffer, NULL, NULL, fname, ext);
+

+
	return path_buffer;
}
#else
#define ucl_mmap mmap
@@ -393,6 +431,69 @@ ucl_unescape_json_string (char *str, size_t len)
	return (t - str);
}

+
size_t
+
ucl_unescape_squoted_string (char *str, size_t len)
+
{
+
	char *t = str, *h = str;
+

+
	if (len <= 1) {
+
		return len;
+
	}
+

+
	/* t is target (tortoise), h is source (hare) */
+

+
	while (len) {
+
		if (*h == '\\') {
+
			h ++;
+

+
			if (len == 1) {
+
				/*
+
				 * If \ is last, then do not try to go further
+
				 * Issue: #74
+
				 */
+
				len --;
+
				*t++ = '\\';
+
				continue;
+
			}
+

+
			switch (*h) {
+
			case '\'':
+
				*t++ = '\'';
+
				break;
+
			case '\n':
+
				/* Ignore \<newline> style stuff */
+
				break;
+
			case '\r':
+
				/* Ignore \r and the following \n if needed */
+
				if (len > 1 && h[1] == '\n') {
+
					h ++;
+
					len --;
+
				}
+
				break;
+
			default:
+
				/* Ignore \ */
+
				*t++ = '\\';
+
				*t++ = *h;
+
				break;
+
			}
+

+
			h ++;
+
			len --;
+
		}
+
		else {
+
			*t++ = *h++;
+
		}
+

+
		if (len > 0) {
+
			len --;
+
		}
+
	}
+

+
	*t = '\0';
+

+
	return (t - str);
+
}
+

char *
ucl_copy_key_trash (const ucl_object_t *obj)
{
@@ -415,6 +516,30 @@ ucl_copy_key_trash (const ucl_object_t *obj)
	return obj->trash_stack[UCL_TRASH_KEY];
}

+
void
+
ucl_chunk_free (struct ucl_chunk *chunk)
+
{
+
	if (chunk) {
+
		if (chunk->special_handler) {
+
			if (chunk->special_handler->free_function) {
+
				chunk->special_handler->free_function (
+
						(unsigned char *) chunk->begin,
+
						chunk->end - chunk->begin,
+
						chunk->special_handler->user_data);
+
			} else {
+
				UCL_FREE (chunk->end - chunk->begin,
+
						(unsigned char *) chunk->begin);
+
			}
+
		}
+

+
		if (chunk->fname) {
+
			free (chunk->fname);
+
		}
+

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

char *
ucl_copy_value_trash (const ucl_object_t *obj)
{
@@ -500,7 +625,7 @@ ucl_parser_free (struct ucl_parser *parser)
		UCL_FREE (sizeof (struct ucl_macro), macro);
	}
	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
-
		UCL_FREE (sizeof (struct ucl_chunk), chunk);
+
		ucl_chunk_free (chunk);
	}
	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
		UCL_FREE (sizeof (struct ucl_pubkey), key);
@@ -617,6 +742,12 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
	return true;
}

+
void ucl_parser_add_special_handler (struct ucl_parser *parser,
+
		struct ucl_parser_special_handler *handler)
+
{
+
	LL_APPEND (parser->special_handlers, handler);
+
}
+

#ifdef CURL_FOUND
struct ucl_curl_cbdata {
	unsigned char *buf;
@@ -752,13 +883,20 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
	int fd;
	struct stat st;

-
	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
-
		if (must_exist) {
+
	if (stat (filename, &st) == -1) {
+
		if (must_exist || errno == EPERM) {
			ucl_create_err (err, "cannot stat file %s: %s",
					filename, strerror (errno));
		}
		return false;
	}
+
	if (!S_ISREG (st.st_mode)) {
+
		if (must_exist) {
+
			ucl_create_err (err, "file %s is not a regular file", filename);
+
		}
+

+
		return false;
+
	}
	if (st.st_size == 0) {
		/* Do not map empty files */
		*buf = NULL;
@@ -909,7 +1047,7 @@ ucl_include_url (const unsigned char *data, size_t len,
		chunk = parser->chunks;
		if (chunk != NULL) {
			parser->chunks = chunk->next;
-
			UCL_FREE (sizeof (struct ucl_chunk), chunk);
+
			ucl_chunk_free (chunk);
		}
	}

@@ -952,9 +1090,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,
		if (params->soft_fail) {
			return false;
		}
-
		if (!params->must_exist) {
+
		if (!params->must_exist && errno != EPERM) {
			return true;
		}
+

		ucl_create_err (&parser->err, "cannot open file %s: %s",
									filebuf,
									strerror (errno));
@@ -977,7 +1116,12 @@ ucl_include_file_single (const unsigned char *data, size_t len,
			return false;
		}

-
		return (!params->must_exist || false);
+
		if (params->must_exist || parser->err != NULL) {
+
			/* The case of fatal errors */
+
			return false;
+
		}
+

+
		return true;
	}

	if (params->check_signature) {
@@ -1040,53 +1184,89 @@ ucl_include_file_single (const unsigned char *data, size_t len,
		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
				params->prefix, strlen (params->prefix)));

-
		if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) {
-
			/* Create an array with key: prefix */
-
			old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
-
			old_obj->key = params->prefix;
-
			old_obj->keylen = strlen (params->prefix);
-
			ucl_copy_key_trash(old_obj);
-
			old_obj->prev = old_obj;
-
			old_obj->next = NULL;
+
		if (strcasecmp (params->target, "array") == 0) {
+
			if (old_obj == NULL) {
+
				/* Create an array with key: prefix */
+
				old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
+
				old_obj->key = params->prefix;
+
				old_obj->keylen = strlen (params->prefix);
+
				ucl_copy_key_trash (old_obj);
+
				old_obj->prev = old_obj;
+
				old_obj->next = NULL;

-
			container = ucl_hash_insert_object (container, old_obj,
-
					parser->flags & UCL_PARSER_KEY_LOWERCASE);
-
			parser->stack->obj->len ++;
+
				container = ucl_hash_insert_object (container, old_obj,
+
						parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
				parser->stack->obj->len++;

-
			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
-
			nest_obj->prev = nest_obj;
-
			nest_obj->next = NULL;
+
				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
				nest_obj->prev = nest_obj;
+
				nest_obj->next = NULL;

-
			ucl_array_append (old_obj, nest_obj);
-
		}
-
		else if (old_obj == NULL) {
-
			/* Create an object with key: prefix */
-
			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
				ucl_array_append (old_obj, nest_obj);
+
			}
+
			else {
+
				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 (buf) {
+
							ucl_munmap (buf, buflen);
+
						}

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

+
					ucl_array_append (old_obj, nest_obj);
				}
+
				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 (buf) {
+
							ucl_munmap (buf, buflen);
+
						}

-
				return false;
-
			}
+
						return false;
+
					}
+
					new_obj->key = old_obj->key;
+
					new_obj->keylen = old_obj->keylen;
+
					new_obj->flags |= UCL_OBJECT_MULTIVALUE;
+
					new_obj->prev = new_obj;
+
					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 (buf) {
+
							ucl_munmap (buf, buflen);
+
						}

-
			nest_obj->key = params->prefix;
-
			nest_obj->keylen = strlen (params->prefix);
-
			ucl_copy_key_trash(nest_obj);
-
			nest_obj->prev = nest_obj;
-
			nest_obj->next = NULL;
+
						return false;
+
					}
+
					nest_obj->prev = nest_obj;
+
					nest_obj->next = NULL;

-
			container = ucl_hash_insert_object (container, nest_obj,
-
					parser->flags & UCL_PARSER_KEY_LOWERCASE);
-
			parser->stack->obj->len ++;
+
					ucl_array_append (new_obj, old_obj);
+
					ucl_array_append (new_obj, nest_obj);
+
					ucl_hash_replace (container, old_obj, new_obj);
+
				}
+
			}
		}
-
		else if (strcasecmp (params->target, "array") == 0 ||
-
				ucl_object_type(old_obj) == UCL_ARRAY) {
-
			if (ucl_object_type(old_obj) == UCL_ARRAY) {
-
				/* Append to the existing array */
+
		else {
+
			/* Case of object */
+
			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 (buf) {
@@ -1095,64 +1275,39 @@ ucl_include_file_single (const unsigned char *data, size_t len,

					return false;
				}
+

+
				nest_obj->key = params->prefix;
+
				nest_obj->keylen = strlen (params->prefix);
+
				ucl_copy_key_trash(nest_obj);
				nest_obj->prev = nest_obj;
				nest_obj->next = NULL;

-
				ucl_array_append (old_obj, nest_obj);
+
				container = ucl_hash_insert_object (container, nest_obj,
+
						parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
				parser->stack->obj->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 (buf) {
-
						ucl_munmap (buf, buflen);
-
					}
-

-
					return false;
+
				if (ucl_object_type (old_obj) == UCL_OBJECT) {
+
					/* Append to existing Object*/
+
					nest_obj = old_obj;
				}
-
				new_obj->key = old_obj->key;
-
				new_obj->keylen = old_obj->keylen;
-
				new_obj->flags |= UCL_OBJECT_MULTIVALUE;
-
				new_obj->prev = new_obj;
-
				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");
+
				else {
+
					/* The key is not an object */
+
					ucl_create_err (&parser->err,
+
							"Conflicting type for key: %s, asked %s, has %s",
+
							params->prefix, params->target,
+
							ucl_object_type_to_string (ucl_object_type (old_obj)));
					if (buf) {
						ucl_munmap (buf, buflen);
					}

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

-
				ucl_array_append (new_obj, old_obj);
-
				ucl_array_append (new_obj, nest_obj);
-
				ucl_hash_replace (container, old_obj, new_obj);
			}
		}
-
		else {
-
			if (ucl_object_type (old_obj) == UCL_OBJECT) {
-
				/* Append to existing Object*/
-
				nest_obj = old_obj;
-
			}
-
			else {
-
				/* The key is not an object */
-
				ucl_create_err (&parser->err,
-
						"Conflicting type for key: %s",
-
						params->prefix);
-
				if (buf) {
-
					ucl_munmap (buf, buflen);
-
				}

-
				return false;
-
			}
-
		}

-
		 /* Put all of the content of the include inside that object */
+
		/* Put all of the content of the include inside that object */
		parser->stack->obj->value.ov = container;

		st = UCL_ALLOC (sizeof (struct ucl_stack));
@@ -1167,7 +1322,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,
			return false;
		}
		st->obj = nest_obj;
-
		st->level = parser->stack->level;
+
		st->e.params.level = parser->stack->e.params.level;
+
		st->e.params.flags = parser->stack->e.params.flags;
+
		st->e.params.line = parser->stack->e.params.line;
+
		st->chunk = parser->chunks;
		LL_PREPEND (parser->stack, st);
		parser->cur_obj = nest_obj;
	}
@@ -1175,57 +1333,49 @@ ucl_include_file_single (const unsigned char *data, size_t len,
	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
			params->strat, params->parse_type);

-
	if (!res) {
-
		if (!params->must_exist) {
-
			/* Free error */
-
			utstring_free (parser->err);
-
			parser->err = NULL;
-
			res = true;
+
	if (res) {
+
		/* Stop nesting the include, take 1 level off the stack */
+
		if (params->prefix != NULL && nest_obj != NULL) {
+
			parser->stack = st->next;
+
			UCL_FREE (sizeof (struct ucl_stack), st);
		}
-
	}
-

-
	/* Stop nesting the include, take 1 level off the stack */
-
	if (params->prefix != NULL && nest_obj != NULL) {
-
		parser->stack = st->next;
-
		UCL_FREE (sizeof (struct ucl_stack), st);
-
	}

-
	/* Remove chunk from the stack */
-
	chunk = parser->chunks;
-
	if (chunk != NULL) {
-
		parser->chunks = chunk->next;
-
		UCL_FREE (sizeof (struct ucl_chunk), chunk);
-
		parser->recursion --;
-
	}
-

-
	/* Restore old file vars */
-
	if (parser->cur_file) {
-
		free (parser->cur_file);
-
	}
-

-
	parser->cur_file = old_curfile;
-
	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
-
		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
-
			DL_DELETE (parser->variables, cur_var);
-
			free (cur_var->var);
-
			free (cur_var->value);
-
			UCL_FREE (sizeof (struct ucl_variable), cur_var);
+
		/* Remove chunk from the stack */
+
		chunk = parser->chunks;
+
		if (chunk != NULL) {
+
			parser->chunks = chunk->next;
+
			ucl_chunk_free (chunk);
+
			parser->recursion--;
+
		}
+

+
		/* Restore old file vars */
+
		if (parser->cur_file) {
+
			free (parser->cur_file);
+
		}
+

+
		parser->cur_file = old_curfile;
+
		DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
+
			if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
+
				DL_DELETE (parser->variables, cur_var);
+
				free (cur_var->var);
+
				free (cur_var->value);
+
				UCL_FREE (sizeof (struct ucl_variable), cur_var);
+
			} else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
+
				DL_DELETE (parser->variables, cur_var);
+
				free (cur_var->var);
+
				free (cur_var->value);
+
				UCL_FREE (sizeof (struct ucl_variable), cur_var);
+
			}
		}
-
		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
-
			DL_DELETE (parser->variables, cur_var);
-
			free (cur_var->var);
-
			free (cur_var->value);
-
			UCL_FREE (sizeof (struct ucl_variable), cur_var);
+
		if (old_filename) {
+
			DL_APPEND (parser->variables, old_filename);
+
		}
+
		if (old_curdir) {
+
			DL_APPEND (parser->variables, old_curdir);
		}
-
	}
-
	if (old_filename) {
-
		DL_APPEND (parser->variables, old_filename);
-
	}
-
	if (old_curdir) {
-
		DL_APPEND (parser->variables, old_curdir);
-
	}

-
	parser->state = prev_state;
+
		parser->state = prev_state;
+
	}

	if (buflen > 0) {
		ucl_munmap (buf, buflen);
@@ -2057,14 +2207,23 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags
		obj->type = UCL_STRING;
		if (flags & UCL_STRING_ESCAPE) {
			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
-
				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
-
					escaped_len ++;
+
				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+
					switch (*p) {
+
					case '\v':
+
						escaped_len += 5;
+
						break;
+
					case ' ':
+
						break;
+
					default:
+
						escaped_len ++;
+
						break;
+
					}
				}
			}
			dst = malloc (escaped_len + 1);
			if (dst != NULL) {
				for (p = start, d = dst; p < end; p ++, d ++) {
-
					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
+
					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
						switch (*p) {
						case '\n':
							*d++ = '\\';
@@ -2086,10 +2245,21 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags
							*d++ = '\\';
							*d = 'f';
							break;
+
						case '\v':
+
							*d++ = '\\';
+
							*d++ = 'u';
+
							*d++ = '0';
+
							*d++ = '0';
+
							*d++ = '0';
+
							*d   = 'B';
+
							break;
						case '\\':
							*d++ = '\\';
							*d = '\\';
							break;
+
						case ' ':
+
							*d = ' ';
+
							break;
						case '"':
							*d++ = '\\';
							*d = '"';
@@ -2229,17 +2399,17 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
				while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
					tmp = ucl_object_ref (cur);
					ucl_object_insert_key_common (found, tmp, cur->key,
-
							cur->keylen, copy_key, false, false);
+
							cur->keylen, copy_key, true, false);
				}
				ucl_object_unref (elt);
			}
			else {
				/* Just make a list of scalars */
-
				DL_APPEND (found, elt);
+
				DL_CONCAT (found, elt);
			}
		}
		else {
-
			DL_APPEND (found, elt);
+
			DL_CONCAT (found, elt);
		}
	}

@@ -2326,30 +2496,98 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
	ucl_object_iter_t iter = NULL;

-
	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
+
	if (top == NULL || elt == NULL) {
		return false;
	}

-
	/* Mix two hashes */
-
	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
-
		if (copy) {
-
			cp = ucl_object_copy (cur);
+
	if (top->type == UCL_ARRAY) {
+
		if (elt->type == UCL_ARRAY) {
+
			/* Merge two arrays */
+
			return ucl_array_merge (top, elt, copy);
		}
		else {
-
			cp = ucl_object_ref (cur);
+
			if (copy) {
+
				ucl_array_append (top, ucl_object_copy (elt));
+

+
				return true;
+
			}
+
			else {
+
				ucl_array_append (top, ucl_object_ref (elt));
+

+
				return true;
+
			}
		}
-
		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
-
		if (found == NULL) {
-
			/* The key does not exist */
-
			top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
-
			top->len ++;
+
	}
+
	else if (top->type == UCL_OBJECT) {
+
		if (elt->type == UCL_OBJECT) {
+
			/* Mix two hashes */
+
			while ((cur = (ucl_object_t *) ucl_hash_iterate (elt->value.ov,
+
					&iter))) {
+

+
				if (copy) {
+
					cp = ucl_object_copy (cur);
+
				} else {
+
					cp = ucl_object_ref (cur);
+
				}
+

+
				found = __DECONST(ucl_object_t *,
+
						ucl_hash_search (top->value.ov, cp->key, cp->keylen));
+

+
				if (found == NULL) {
+
					/* The key does not exist */
+
					top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
+
							false);
+
					top->len++;
+
				}
+
				else {
+
					/* The key already exists, merge it recursively */
+
					if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
+
						if (!ucl_object_merge (found, cp, copy)) {
+
							return false;
+
						}
+
					}
+
					else {
+
						ucl_hash_replace (top->value.ov, found, cp);
+
						ucl_object_unref (found);
+
					}
+
				}
+
			}
		}
		else {
-
			/* The key already exists, replace it */
-
			ucl_hash_replace (top->value.ov, found, cp);
-
			ucl_object_unref (found);
+
			if (copy) {
+
				cp = ucl_object_copy (elt);
+
			}
+
			else {
+
				cp = ucl_object_ref (elt);
+
			}
+

+
			found = __DECONST(ucl_object_t *,
+
					ucl_hash_search (top->value.ov, cp->key, cp->keylen));
+

+
			if (found == NULL) {
+
				/* The key does not exist */
+
				top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
+
						false);
+
				top->len++;
+
			}
+
			else {
+
				/* The key already exists, merge it recursively */
+
				if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
+
					if (!ucl_object_merge (found, cp, copy)) {
+
						return false;
+
					}
+
				}
+
				else {
+
					ucl_hash_replace (top->value.ov, found, cp);
+
					ucl_object_unref (found);
+
				}
+
			}
		}
	}
+
	else {
+
		/* Cannot merge trivial objects */
+
		return false;
+
	}

	return true;
}
@@ -2468,9 +2706,17 @@ ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
	return NULL;
}

+
enum ucl_safe_iter_flags {
+
	UCL_ITERATE_FLAG_UNDEFINED = 0,
+
	UCL_ITERATE_FLAG_INSIDE_ARRAY,
+
	UCL_ITERATE_FLAG_INSIDE_OBJECT,
+
	UCL_ITERATE_FLAG_IMPLICIT,
+
};
+

const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
struct ucl_object_safe_iter {
	char magic[4]; /* safety check */
+
	uint32_t flags;
	const ucl_object_t *impl_it; /* implicit object iteration */
	ucl_object_iter_t expl_it; /* explicit iteration */
};
@@ -2489,6 +2735,7 @@ ucl_object_iterate_new (const ucl_object_t *obj)
	it = UCL_ALLOC (sizeof (*it));
	if (it != NULL) {
		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
+
		it->flags = UCL_ITERATE_FLAG_UNDEFINED;
		it->expl_it = NULL;
		it->impl_it = obj;
	}
@@ -2505,11 +2752,14 @@ ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
	UCL_SAFE_ITER_CHECK (rit);

	if (rit->expl_it != NULL) {
-
		UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
+
		if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
+
			UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
+
		}
	}

	rit->impl_it = obj;
	rit->expl_it = NULL;
+
	rit->flags = UCL_ITERATE_FLAG_UNDEFINED;

	return it;
}
@@ -2533,7 +2783,20 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
		return NULL;
	}

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

+
		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
+
			/* Need to switch to another implicit object in chain */
+
			rit->impl_it = rit->impl_it->next;
+
			rit->expl_it = NULL;
+

+
			return ucl_object_iterate_safe (it, type);
+
		}
+
	}
+
	else if (rit->impl_it->type == UCL_ARRAY) {
+
		rit->flags = UCL_ITERATE_FLAG_INSIDE_ARRAY;
		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);

		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
@@ -2546,6 +2809,7 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
	}
	else {
		/* Just iterate over the implicit array */
+
		rit->flags = UCL_ITERATE_FLAG_IMPLICIT;
		ret = rit->impl_it;
		rit->impl_it = rit->impl_it->next;

@@ -2568,7 +2832,9 @@ ucl_object_iterate_free (ucl_object_iter_t it)
	UCL_SAFE_ITER_CHECK (rit);

	if (rit->expl_it != NULL) {
-
		UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
+
		if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
+
			UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
+
		}
	}

	UCL_FREE (sizeof (*rit), it);
@@ -2680,6 +2946,21 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
	return new;
}

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

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

ucl_object_t*
ucl_object_new_userdata (ucl_userdata_dtor dtor,
		ucl_userdata_emitter emitter,
@@ -2935,6 +3216,22 @@ ucl_array_pop_first (ucl_object_t *top)
	return ret;
}

+
unsigned int
+
ucl_array_size (const ucl_object_t *top)
+
{
+
	if (top == NULL || top->type != UCL_ARRAY) {
+
		return 0;
+
	}
+

+
	UCL_ARRAY_GET (vec, top);
+

+
	if (vec != NULL) {
+
		return kv_size(*vec);
+
	}
+

+
	return 0;
+
}
+

const ucl_object_t *
ucl_array_find_index (const ucl_object_t *top, unsigned int index)
{
@@ -3008,7 +3305,7 @@ ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
	}
	switch (obj->type) {
	case UCL_INT:
-
		*target = obj->value.iv; /* Probaly could cause overflow */
+
		*target = obj->value.iv; /* Probably could cause overflow */
		break;
	case UCL_FLOAT:
	case UCL_TIME:
@@ -3042,7 +3339,7 @@ ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
		break;
	case UCL_FLOAT:
	case UCL_TIME:
-
		*target = obj->value.dv; /* Loosing of decimal points */
+
		*target = obj->value.dv; /* Losing of decimal points */
		break;
	default:
		return false;
modified external/libucl/tests/basic.test
@@ -16,7 +16,7 @@ for _tin in ${TEST_DIR}/basic/*.in ; do
	diff -s $_out $_t.res -u 2>/dev/null
		if [ $? -ne 0 ] ; then
			rm $_out
-
			echo "Test: $_t output missmatch"
+
			echo "Test: $_t output mismatch"
			exit 1
		fi
	fi
modified external/libucl/tests/basic/13.in
@@ -6,4 +6,4 @@ key = value_orig;
.include(priority=1) "${CURDIR}/include_dir/pri1.conf"
.include(priority=2) "${CURDIR}/include_dir/pri2.conf"

-
.include(try=true) "${CURDIR}/include_dir/invalid.conf"
+
# No longer valid! .include(try=true) "${CURDIR}/include_dir/invalid.conf"
deleted external/libucl/tests/basic/20.in
@@ -1,2 +0,0 @@
-
# issue 112
-
[[0

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

\ No newline at end of file
deleted external/libucl/tests/basic/21.res
@@ -1,10 +0,0 @@
-
[
-
    9,
-
    {
-
        0 [
-
            [
-
                0,
-
            ]
-
        ]
-
    }
-
]
modified external/libucl/tests/basic/9.in
@@ -16,8 +16,8 @@ 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="prefix3"; 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
@@ -18,9 +18,6 @@ array [
]
array1 [
    10,
-
    {
-
        key1 = "value";
-
    }
]
prefix {
    key1 = "value";
@@ -31,4 +28,9 @@ prefix2 [
        key1 = "value";
    }
]
+
prefix3 [
+
    {
+
        key1 = "value";
+
    }
+
]

modified external/libucl/tests/generate.test
@@ -6,7 +6,7 @@ $PROG ${TEST_OUT_DIR}/generate.out
diff -s ${TEST_OUT_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
if [ $? -ne 0 ] ; then
	rm ${TEST_OUT_DIR}/generate.out
-
	echo "Test: generate.res output missmatch"
+
	echo "Test: generate.res output mismatch"
	exit 1
fi
rm ${TEST_OUT_DIR}/generate.out
modified external/libucl/tests/run_tests.sh
@@ -19,7 +19,7 @@ for _tin in ${TEST_DIR}/*.in ; do
	diff -s $_t.out $_t.res -u 2>/dev/null
		if [ $? -ne 0 ] ; then
			rm $_t.out
-
			echo "Test: $_t output missmatch"
+
			echo "Test: $_t output mismatch"
			exit 1
		fi
	fi
@@ -31,7 +31,7 @@ if [ $# -gt 2 ] ; then
	diff -s ${TEST_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
	if [ $? -ne 0 ] ; then
		rm ${TEST_DIR}/generate.out
-
		echo "Test: generate.res output missmatch"
+
		echo "Test: generate.res output mismatch"
    	exit 1
	fi
	rm ${TEST_DIR}/generate.out
modified external/libucl/tests/schema/patternProperties.json
@@ -24,6 +24,11 @@
                "valid": false
            },
            {
+
                "description": "a single invalid match is invalid",
+
                "data": {"fooooo": 2, "foo": "bar"},
+
                "valid": false
+
            },
+
            {
                "description": "multiple invalid matches is invalid",
                "data": {"foo": "bar", "foooooo" : "baz"},
                "valid": false
modified external/libucl/tests/schema/refRemote.json
@@ -48,7 +48,7 @@
                "valid": false
            }
        ]
-
    },
+
    }
/*
    {
        "description": "change resolution scope",
modified external/libucl/tests/streamline.test
@@ -6,7 +6,7 @@ $PROG ${TEST_OUT_DIR}/streamline.out
diff -s ${TEST_OUT_DIR}/streamline.out ${TEST_DIR}/streamline.res -u 2>/dev/null
if [ $? -ne 0 ] ; then
	rm ${TEST_OUT_DIR}/streamline.out
-
	echo "Test: streamline.res output missmatch"
+
	echo "Test: streamline.res output mismatch"
	exit 1
fi
rm ${TEST_OUT_DIR}/streamline.out

\ No newline at end of file
modified external/libucl/tests/test_generate.c
@@ -106,7 +106,7 @@ main (int argc, char **argv)
	cur = ucl_object_fromstring ("Ебв"); /* UTF8 */
	ucl_array_prepend (ar1, cur);
/*
-
 * This is ususally broken or fragile as utf collate is far from perfect
+
 * This is usually 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
modified external/libucl/utils/objdump.c
@@ -146,14 +146,14 @@ main(int argc, char **argv)
	ucl_parser_add_chunk (parser, inbuf, r);
	fclose (in);
	if (ucl_parser_get_error(parser)) {
-
		printf ("Error occured: %s\n", ucl_parser_get_error(parser));
+
		printf ("Error occurred: %s\n", ucl_parser_get_error(parser));
		ret = 1;
		goto end;
	}

	obj = ucl_parser_get_object (parser);
	if (ucl_parser_get_error (parser)) {
-
		printf ("Error occured: %s\n", ucl_parser_get_error(parser));
+
		printf ("Error occurred: %s\n", ucl_parser_get_error(parser));
		ret = 1;
		goto end;
	}