Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to latest version
Baptiste Daroussin committed 10 years ago
commit b5fa0a30962800f7ca9c4586635c4e5c4899f626
parent 2a20ee0
18 files changed +2694 -339
modified external/Makefile.am
@@ -194,6 +194,7 @@ libucl_la_SOURCES= libucl/src/ucl_emitter.c \
			libucl/src/ucl_schema.c \
			libucl/src/ucl_util.c \
			libucl/src/ucl_msgpack.c \
+
			libucl/src/ucl_sexp.c \
			libucl/src/xxhash.c
libucl_la_CFLAGS=	$(ucl_common_cflags) -shared
libucl_static_la_SOURCES=	$(libucl_la_SOURCES)
modified external/libucl/README.md
@@ -21,7 +21,7 @@
- [Performance](#performance)
- [Conclusion](#conclusion)

-
## Introduction
+
## Introduction 

This document describes the main features and principles of the configuration
language called `UCL` - universal configuration language.
@@ -271,6 +271,11 @@ the key already exists, it must be the correct type
* `target` (default: object) - Specify if the `prefix` `key` should be an
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)
+
	- `error` - create error on duplicate keys and stop parsing
+
	- `rewrite` - always rewrite an old value with new one (ignoring priorities)

Priorities are used by UCL parser to manage the policy of objects rewriting during including other files
as following:
deleted external/libucl/cmake/CMakeLists.txt
@@ -1,127 +0,0 @@
-
PROJECT(libucl C)
-

-
SET(LIBUCL_VERSION_MAJOR 0)
-
SET(LIBUCL_VERSION_MINOR 5)
-
SET(LIBUCL_VERSION_PATCH 0)
-

-
SET(LIBUCL_VERSION         "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
-

-
INCLUDE(CheckCCompilerFlag)
-
INCLUDE(FindOpenSSL)
-
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
-

-
OPTION(ENABLE_URL_INCLUDE  "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF)
-
OPTION(ENABLE_URL_SIGN  "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF)
-
OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF)
-

-
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-
	LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt)
-
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-

-
IF(ENABLE_URL_INCLUDE MATCHES "ON")
-
    FIND_LIBRARY(LIBFETCH_LIBRARY NAMES fetch PATHS	PATH_SUFFIXES lib64 lib
-
                      PATHS
-
                          ~/Library/Frameworks
-
                          /Library/Frameworks
-
                          /usr/local
-
                          /usr
-
                          /sw
-
                          /opt/local
-
                          /opt/csw
-
                          /opt
-
                     DOC "Path where the libfetch library can be found")
-
    IF(LIBFETCH_LIBRARY)
-
    	FIND_FILE(HAVE_FETCH_H NAMES fetch.h PATHS /usr/include
-
    											   /opt/include
-
    											   /usr/local/include
-
    				DOC "Path to libfetch header")
-
    ELSE(LIBFETCH_LIBRARY)
-
    	# Try to find libcurl
-
    	ProcessPackage(CURL libcurl)
-
    	IF(NOT CURL_FOUND)
-
    		MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration")
-
    	ENDIF(NOT CURL_FOUND)
-
    ENDIF(LIBFETCH_LIBRARY)
-
ENDIF(ENABLE_URL_INCLUDE MATCHES "ON")
-

-
SET(CMAKE_C_WARN_FLAGS "")
-
CHECK_C_COMPILER_FLAG(-Wall SUPPORT_WALL)
-
CHECK_C_COMPILER_FLAG(-W SUPPORT_W)
-
CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WPARAM)
-
CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN)
-
CHECK_C_COMPILER_FLAG(-Wstrict-prototypes SUPPORT_WSTRICT_PROTOTYPES)
-
IF(NOT "${CMAKE_C_COMPILER_ID}" MATCHES SunPro)
-
	CHECK_C_COMPILER_FLAG("-std=c99" SUPPORT_STD_FLAG)
-
ENDIF(NOT "${CMAKE_C_COMPILER_ID}" MATCHES SunPro)
-
IF(SUPPORT_W)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W")
-
ENDIF(SUPPORT_W)
-
IF(SUPPORT_WALL)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wall")
-
ENDIF(SUPPORT_WALL)
-
IF(SUPPORT_WPARAM)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter")
-
ENDIF(SUPPORT_WPARAM)
-
IF(SUPPORT_WPOINTER_SIGN)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign")
-
ENDIF(SUPPORT_WPOINTER_SIGN)
-
IF(SUPPORT_WSTRICT_PROTOTYPES)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wstrict-prototypes")
-
ENDIF(SUPPORT_WSTRICT_PROTOTYPES)
-
IF(SUPPORT_STD_FLAG)
-
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -std=c99")
-
ENDIF(SUPPORT_STD_FLAG)
-

-
IF(ENABLE_URL_SIGN MATCHES "ON")
-
	IF(OPENSSL_FOUND)
-
		SET(HAVE_OPENSSL 1)
-
		INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}")
-
	ENDIF(OPENSSL_FOUND)
-
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
-

-
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../src")
-
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../include")
-
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../uthash")
-
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../klib")
-

-
SET(UCLSRC            ../src/ucl_util.c
-
                      ../src/ucl_parser.c
-
                      ../src/ucl_emitter.c
-
                      ../src/ucl_emitter_streamline.c
-
                      ../src/ucl_emitter_utils.c
-
                      ../src/ucl_hash.c
-
                      ../src/ucl_schema.c
-
                      ../src/xxhash.c)
-

-

-
SET (LIB_TYPE STATIC)
-
IF (BUILD_SHARED_LIBS)
-
  SET (LIB_TYPE SHARED)
-
ENDIF (BUILD_SHARED_LIBS)
-
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
-
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
-

-
IF(WITH_LUA)
-
	SET(UCL_LUA_SRC ../lua/lua_ucl.c)
-
	ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
-
	IF(ENABLE_LUAJIT MATCHES "ON")
-
		TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
-
	ELSE(ENABLE_LUAJIT MATCHES "ON")
-
		TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
-
	ENDIF(ENABLE_LUAJIT MATCHES "ON")
-
	TARGET_LINK_LIBRARIES(lua-ucl ucl)
-
	SET_TARGET_PROPERTIES(lua-ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
-
ENDIF(WITH_LUA)
-

-
IF(HAVE_FETCH_H)
-
    TARGET_LINK_LIBRARIES(ucl fetch)
-
ELSE(HAVE_FETCH_H)
-
    IF(CURL_FOUND)
-
        TARGET_LINK_LIBRARIES(ucl ${CURL_LIBRARIES})
-
    ENDIF(CURL_FOUND)
-
ENDIF(HAVE_FETCH_H)
-
IF(ENABLE_URL_SIGN MATCHES "ON")
-
	IF(OPENSSL_FOUND)
-
		TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES})
-
	ENDIF(OPENSSL_FOUND)
-
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
modified external/libucl/doc/Makefile.am
@@ -4,6 +4,6 @@ dist_man_MANS = libucl.3

gen-man: @PANDOC@
	tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \
-
	cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \ 
+
	cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \
	-e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \
-
	@PANDOC@ -s -f markdown -t man -o libucl.3 

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

+
#pragma once
+
#include <string>
+
#include <memory>
+
#include <iostream>
+
#include <strstream>
+

+
#include "ucl.h"
+

+
// C++11 API inspired by json11: https://github.com/dropbox/json11/
+

+
namespace ucl {
+

+
struct ucl_map_construct_t { };
+
constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
+
struct ucl_array_construct_t { };
+
constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
+

+
class Ucl final {
+
private:
+

+
	struct ucl_deleter {
+
		void operator() (ucl_object_t *obj) {
+
			ucl_object_unref (obj);
+
		}
+
	};
+

+
	static int
+
	append_char (unsigned char c, size_t nchars, void *ud)
+
	{
+
		std::string *out = reinterpret_cast<std::string *>(ud);
+

+
		out->append (nchars, (char)c);
+

+
		return nchars;
+
	}
+
	static int
+
	append_len (unsigned const char *str, size_t len, void *ud)
+
	{
+
		std::string *out = reinterpret_cast<std::string *>(ud);
+

+
		out->append ((const char *)str, len);
+

+
		return len;
+
	}
+
	static int
+
	append_int (int64_t elt, void *ud)
+
	{
+
		std::string *out = reinterpret_cast<std::string *>(ud);
+
		auto nstr = std::to_string (elt);
+

+
		out->append (nstr);
+

+
		return nstr.size ();
+
	}
+
	static int
+
	append_double (double elt, void *ud)
+
	{
+
		std::string *out = reinterpret_cast<std::string *>(ud);
+
		auto nstr = std::to_string (elt);
+

+
		out->append (nstr);
+

+
		return nstr.size ();
+
	}
+

+
	static struct ucl_emitter_functions default_emit_funcs()
+
	{
+
		struct ucl_emitter_functions func = {
+
			Ucl::append_char,
+
			Ucl::append_len,
+
			Ucl::append_int,
+
			Ucl::append_double,
+
			nullptr,
+
			nullptr
+
		};
+

+
		return func;
+
	};
+

+
	std::unique_ptr<ucl_object_t, ucl_deleter> obj;
+

+
public:
+
	class const_iterator {
+
	private:
+
		struct ucl_iter_deleter {
+
			void operator() (ucl_object_iter_t it) {
+
				ucl_object_iterate_free (it);
+
			}
+
		};
+
		std::shared_ptr<void> it;
+
		std::unique_ptr<Ucl> cur;
+
	public:
+
		typedef std::forward_iterator_tag iterator_category;
+

+
		const_iterator(const Ucl &obj) {
+
			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)));
+
		}
+

+
		const_iterator() {}
+
		const_iterator(const const_iterator &other) {
+
			it = other.it;
+
		}
+
		~const_iterator() {}
+

+
		const_iterator& operator=(const const_iterator &other) {
+
			it = other.it;
+
			return *this;
+
		}
+

+
		bool operator==(const const_iterator &other) const
+
		{
+
			if (cur && other.cur) {
+
				return cur->obj.get() == other.cur->obj.get();
+
			}
+

+
			return !cur && !other.cur;
+
		}
+

+
		bool operator!=(const const_iterator &other) const
+
		{
+
			return !(*this == other);
+
		}
+

+
		const_iterator& operator++()
+
		{
+
			if (it) {
+
				cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
+
			}
+

+
			if (!*cur) {
+
				it.reset ();
+
				cur.reset ();
+
			}
+

+
			return *this;
+
		}
+

+
		const Ucl& operator*() const
+
		{
+
			return *cur;
+
		}
+
		const Ucl* operator->() const
+
		{
+
			return cur.get();
+
		}
+
	};
+

+
	// We grab ownership if get non-const ucl_object_t
+
	Ucl(ucl_object_t *other) {
+
		obj.reset (other);
+
	}
+

+
	// Shared ownership
+
	Ucl(const ucl_object_t *other) {
+
		obj.reset (ucl_object_ref (other));
+
	}
+

+
	Ucl(const Ucl &other) {
+
		obj.reset (ucl_object_ref (other.obj.get()));
+
	}
+

+
	Ucl(Ucl &&other) {
+
		obj.swap (other.obj);
+
	}
+

+
	Ucl() noexcept {
+
		obj.reset (ucl_object_typed_new (UCL_NULL));
+
	}
+
	Ucl(std::nullptr_t) noexcept {
+
		obj.reset (ucl_object_typed_new (UCL_NULL));
+
	}
+
	Ucl(double value) {
+
		obj.reset (ucl_object_typed_new (UCL_FLOAT));
+
		obj->value.dv = value;
+
	}
+
	Ucl(int64_t value) {
+
		obj.reset (ucl_object_typed_new (UCL_INT));
+
		obj->value.iv = value;
+
	}
+
	Ucl(bool value) {
+
		obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
+
		obj->value.iv = static_cast<int64_t>(value);
+
	}
+
	Ucl(const std::string &value) {
+
		obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
+
				UCL_STRING_RAW));
+
	}
+
	Ucl(const char * value) {
+
		obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
+
	}
+

+
	// Implicit constructor: anything with a to_json() function.
+
	template <class T, class = decltype(&T::to_ucl)>
+
	Ucl(const T & t) : Ucl(t.to_ucl()) {}
+

+
	// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
+
	template <class M, typename std::enable_if<
+
		std::is_constructible<std::string, typename M::key_type>::value
+
		&& std::is_constructible<Ucl, typename M::mapped_type>::value,
+
		int>::type = 0>
+
	Ucl(const M & m) {
+
		obj.reset (ucl_object_typed_new (UCL_OBJECT));
+
		auto cobj = obj.get ();
+

+
		for (const auto &e : m) {
+
			ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
+
					e.first.data (), e.first.size (), true);
+
		}
+
	}
+

+
	// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
+
	template <class V, typename std::enable_if<
+
		std::is_constructible<Ucl, typename V::value_type>::value,
+
		int>::type = 0>
+
	Ucl(const V & v) {
+
		obj.reset (ucl_object_typed_new (UCL_ARRAY));
+
		auto cobj = obj.get ();
+

+
		for (const auto &e : v) {
+
			ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
+
		}
+
	}
+

+
	ucl_type_t type () const {
+
		if (obj) {
+
			return ucl_object_type (obj.get ());
+
		}
+
		return UCL_NULL;
+
	}
+

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

+
		if (obj->key) {
+
			res.assign (obj->key, obj->keylen);
+
		}
+

+
		return res;
+
	}
+

+
	double number_value () const
+
	{
+
		if (obj) {
+
			return ucl_object_todouble (obj.get());
+
		}
+

+
		return 0.0;
+
	}
+

+
	int64_t int_value () const
+
	{
+
		if (obj) {
+
			return ucl_object_toint (obj.get());
+
		}
+

+
		return 0;
+
	}
+

+
	bool bool_value () const
+
	{
+
		if (obj) {
+
			return ucl_object_toboolean (obj.get());
+
		}
+

+
		return false;
+
	}
+

+
	const std::string string_value () const
+
	{
+
		std::string res;
+

+
		if (obj) {
+
			res.assign (ucl_object_tostring (obj.get()));
+
		}
+

+
		return res;
+
	}
+

+
	const Ucl operator[] (size_t i) const
+
	{
+
		if (type () == UCL_ARRAY) {
+
			return Ucl (ucl_array_find_index (obj.get(), i));
+
		}
+

+
		return Ucl (nullptr);
+
	}
+

+
	const Ucl operator[](const std::string &key) const
+
	{
+
		if (type () == UCL_OBJECT) {
+
			return Ucl (ucl_object_find_keyl (obj.get(),
+
					key.data (), key.size ()));
+
		}
+

+
		return Ucl (nullptr);
+
	}
+
	// Serialize.
+
	void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
+
	{
+
		struct ucl_emitter_functions cbdata;
+

+
		cbdata = Ucl::default_emit_funcs();
+
		cbdata.ud = reinterpret_cast<void *>(&out);
+

+
		ucl_object_emit_full (obj.get(), type, &cbdata);
+
	}
+

+
	std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
+
	{
+
		std::string out;
+

+
		dump (out, type);
+

+
		return out;
+
	}
+

+
	static Ucl parse (const std::string & in, std::string & err)
+
	{
+
		auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
+

+
		if (!ucl_parser_add_chunk (parser, (const unsigned char *)in.data (),
+
				in.size ())) {
+
			err.assign (ucl_parser_get_error (parser));
+
			ucl_parser_free (parser);
+

+
			return nullptr;
+
		}
+

+
		auto obj = ucl_parser_get_object (parser);
+
		ucl_parser_free (parser);
+

+
		// Obj will handle ownership
+
		return Ucl (obj);
+
	}
+

+
	static Ucl parse (const char * in, std::string & err)
+
	{
+
		if (in) {
+
			return parse (std::string(in), err);
+
		} else {
+
			err = "null input";
+
			return nullptr;
+
		}
+
	}
+

+
	static Ucl parse (std::istream &ifs, std::string &err)
+
	{
+
		return Ucl::parse (std::string(std::istreambuf_iterator<char>(ifs),
+
				std::istreambuf_iterator<char>()), err);
+
	}
+

+
	bool operator== (const Ucl &rhs) const
+
	{
+
		return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
+
	}
+
	bool operator< (const Ucl &rhs) const
+
	{
+
		return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
+
	}
+
	bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
+
	bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
+
	bool operator> (const Ucl &rhs) const { return (rhs < *this); }
+
	bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
+

+
	operator bool () const
+
	{
+
		if (!obj || type() == UCL_NULL) {
+
			return false;
+
		}
+

+
		if (type () == UCL_BOOLEAN) {
+
			return bool_value ();
+
		}
+

+
		return true;
+
	}
+

+
	const_iterator begin() const
+
	{
+
		return const_iterator(*this);
+
	}
+
	const_iterator cbegin() const
+
	{
+
		return const_iterator(*this);
+
	}
+
	const_iterator end() const
+
	{
+
		return const_iterator();
+
	}
+
	const_iterator cend() const
+
	{
+
		return const_iterator();
+
	}
+
};
+

+
};
modified external/libucl/include/ucl.h
@@ -1,4 +1,4 @@
-
/* Copyright (c) 2013, Vsevolod Stakhov
+
/* Copyright (c) 2013-2015, Vsevolod Stakhov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -182,10 +182,30 @@ typedef enum ucl_object_flags {
	UCL_OBJECT_EPHEMERAL = (1 << 3), /**< Temporary object that does not need to be freed really */
	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_INHERITED = (1 << 6), /**< Object has been inherited from another */
+
	UCL_OBJECT_BINARY = (1 << 7) /**< Object contains raw binary data */
} ucl_object_flags_t;

/**
+
 * Duplicate policy types
+
 */
+
enum ucl_duplicate_strategy {
+
	UCL_DUPLICATE_APPEND = 0, /**< Default policy to merge based on priorities */
+
	UCL_DUPLICATE_MERGE,     /**< Merge new object with old one */
+
	UCL_DUPLICATE_REWRITE,   /**< Rewrite old keys */
+
	UCL_DUPLICATE_ERROR      /**< Stop parsing on duplicate found */
+
};
+

+
/**
+
 * Input format type
+
 */
+
enum ucl_parse_type {
+
	UCL_PARSE_UCL = 0, /**< Default ucl format */
+
	UCL_PARSE_MSGPACK, /**< Message pack input format */
+
	UCL_PARSE_CSEXP /**< Canonical S-expressions */
+
};
+

+
/**
 * UCL object structure. Please mention that the most of fields should not be touched by
 * UCL users. In future, this structure may be converted to private one.
 */
@@ -195,7 +215,7 @@ typedef struct ucl_object_s {
	 */
	union {
		int64_t iv;							/**< Int value of an object */
-
		const char *sv;					/**< String value of an object */
+
		const char *sv;						/**< String value of an object */
		double dv;							/**< Double value of an object */
		void *av;							/**< Array					*/
		void *ov;							/**< Object					*/
@@ -720,7 +740,7 @@ UCL_EXTERN int ucl_object_compare (const ucl_object_t *o1,
 * @param cmp
 */
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
-
		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2));
+
		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2));

/**
 * Get the priority for specific UCL object
@@ -917,6 +937,21 @@ UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
		const unsigned char *data, size_t len, unsigned priority);

/**
+
 * 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
+
 * @param len the length of a chunk
+
 * @param priority the desired priority of a chunk (only 4 least significant bits
+
 * are considered for this parameter)
+
 * @param strat duplicates merging strategy
+
 * @param parse_type input format
+
 * @return true if chunk has been added and false in case of error
+
 */
+
UCL_EXTERN bool ucl_parser_add_chunk_full (struct ucl_parser *parser,
+
		const unsigned char *data, size_t len, unsigned priority,
+
		enum ucl_duplicate_strategy strat, enum ucl_parse_type parse_type);
+

+
/**
 * Load ucl object from a string
 * @param parser parser structure
 * @param data the pointer to the string
modified external/libucl/lua/lua_ucl.c
@@ -69,6 +69,7 @@ func = "huh";
#define PARSER_META "ucl.parser.meta"
#define EMITTER_META "ucl.emitter.meta"
#define NULL_META "null.emitter.meta"
+
#define OBJECT_META "ucl.object.meta"

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);
@@ -461,6 +462,24 @@ ucl_object_lua_import (lua_State *L, int idx)
}

static int
+
lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
+
{
+
	unsigned char *result;
+

+
	result = ucl_object_emit (obj, type);
+

+
	if (result != NULL) {
+
		lua_pushstring (L, (const char *)result);
+
		free (result);
+
	}
+
	else {
+
		lua_pushnil (L);
+
	}
+

+
	return 1;
+
}
+

+
static int
lua_ucl_parser_init (lua_State *L)
{
	struct ucl_parser *parser, **pparser;
@@ -489,6 +508,12 @@ lua_ucl_parser_get (lua_State *L, int index)
	return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
}

+
static ucl_object_t *
+
lua_ucl_object_get (lua_State *L, int index)
+
{
+
	return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
+
}
+

/***
 * @method parser:parse_file(name)
 * Parse UCL object from file.
@@ -594,6 +619,108 @@ lua_ucl_parser_get_object (lua_State *L)
	return ret;
}

+
/***
+
 * @method parser:get_object_wrapped()
+
 * Get top object from parser and export it to userdata object without
+
 * unwrapping to lua.
+
 * @return {ucl.object or nil} ucl object wrapped variable
+
 */
+
static int
+
lua_ucl_parser_get_object_wrapped (lua_State *L)
+
{
+
	struct ucl_parser *parser;
+
	ucl_object_t *obj, **pobj;
+
	int ret = 1;
+

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

+
	if (obj != NULL) {
+
		pobj = lua_newuserdata (L, sizeof (*pobj));
+
		*pobj = obj;
+
		luaL_getmetatable (L, OBJECT_META);
+
		lua_setmetatable (L, -2);
+
	}
+
	else {
+
		lua_pushnil (L);
+
	}
+

+
	return ret;
+
}
+

+
/***
+
 * @method parser:validate(schema)
+
 * Validates the top object in the parser against schema. Schema might be
+
 * another object or a string that represents file to load schema from.
+
 *
+
 * @param {string/table} schema input schema
+
 * @return {result,err} two values: boolean result and the corresponding error
+
 *
+
 */
+
static int
+
lua_ucl_parser_validate (lua_State *L)
+
{
+
	struct ucl_parser *parser, *schema_parser;
+
	ucl_object_t *schema;
+
	const char *schema_file;
+
	struct ucl_schema_error err;
+

+
	parser = lua_ucl_parser_get (L, 1);
+

+
	if (parser && parser->top_obj) {
+
		if (lua_type (L, 2) == LUA_TTABLE) {
+
			schema = ucl_object_lua_import (L, 2);
+

+
			if (schema == NULL) {
+
				lua_pushboolean (L, false);
+
				lua_pushstring (L, "cannot load schema from lua table");
+

+
				return 2;
+
			}
+
		}
+
		else if (lua_type (L, 2) == LUA_TSTRING) {
+
			schema_parser = ucl_parser_new (0);
+
			schema_file = luaL_checkstring (L, 2);
+

+
			if (!ucl_parser_add_file (schema_parser, schema_file)) {
+
				lua_pushboolean (L, false);
+
				lua_pushfstring (L, "cannot parse schema file \"%s\": "
+
						"%s", schema_file, ucl_parser_get_error (parser));
+
				ucl_parser_free (schema_parser);
+

+
				return 2;
+
			}
+

+
			schema = ucl_parser_get_object (schema_parser);
+
			ucl_parser_free (schema_parser);
+
		}
+
		else {
+
			lua_pushboolean (L, false);
+
			lua_pushstring (L, "invalid schema argument");
+

+
			return 2;
+
		}
+

+
		if (!ucl_object_validate (schema, parser->top_obj, &err)) {
+
			lua_pushboolean (L, false);
+
			lua_pushfstring (L, "validation error: "
+
					"%s", err.msg);
+
		}
+
		else {
+
			lua_pushboolean (L, true);
+
			lua_pushnil (L);
+
		}
+

+
		ucl_object_unref (schema);
+
	}
+
	else {
+
		lua_pushboolean (L, false);
+
		lua_pushstring (L, "invalid parser or empty top object");
+
	}
+

+
	return 2;
+
}
+

static int
lua_ucl_parser_gc (lua_State *L)
{
@@ -605,6 +732,161 @@ lua_ucl_parser_gc (lua_State *L)
	return 0;
}

+
/***
+
 * @method object:unwrap()
+
 * Unwraps opaque ucl object to the native lua object (performing copying)
+
 * @return {variant} any lua object
+
 */
+
static int
+
lua_ucl_object_unwrap (lua_State *L)
+
{
+
	ucl_object_t *obj;
+

+
	obj = lua_ucl_object_get (L, 1);
+

+
	if (obj) {
+
		ucl_object_push_lua (L, obj, true);
+
	}
+
	else {
+
		lua_pushnil (L);
+
	}
+

+
	return 1;
+
}
+

+
/***
+
 * @method object:tostring(type)
+
 * Unwraps opaque ucl object to string (json by default). Optionally you can
+
 * specify output format:
+
 *
+
 * - `json` - fine printed json
+
 * - `json-compact` - compacted json
+
 * - `config` - fine printed configuration
+
 * - `ucl` - same as `config`
+
 * - `yaml` - embedded yaml
+
 * @param {string} type optional
+
 * @return {string} string representation of the opaque ucl object
+
 */
+
static int
+
lua_ucl_object_tostring (lua_State *L)
+
{
+
	ucl_object_t *obj;
+
	enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
+

+
	obj = lua_ucl_object_get (L, 1);
+

+
	if (obj) {
+
		if (lua_gettop (L) > 1) {
+
			if (lua_type (L, 2) == LUA_TSTRING) {
+
				const char *strtype = lua_tostring (L, 2);
+

+
				if (strcasecmp (strtype, "json") == 0) {
+
					format = UCL_EMIT_JSON;
+
				}
+
				else if (strcasecmp (strtype, "json-compact") == 0) {
+
					format = UCL_EMIT_JSON_COMPACT;
+
				}
+
				else if (strcasecmp (strtype, "yaml") == 0) {
+
					format = UCL_EMIT_YAML;
+
				}
+
				else if (strcasecmp (strtype, "config") == 0 ||
+
						strcasecmp (strtype, "ucl") == 0) {
+
					format = UCL_EMIT_CONFIG;
+
				}
+
			}
+
		}
+

+
		return lua_ucl_to_string (L, obj, format);
+
	}
+
	else {
+
		lua_pushnil (L);
+
	}
+

+
	return 1;
+
}
+

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

+
	obj = lua_ucl_object_get (L, 1);
+
	schema = lua_ucl_object_get (L, 2);
+

+
	if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
+
		if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TSTRING) {
+
			path = lua_tostring (L, 3);
+
			if (path[0] == '#') {
+
				path ++;
+
			}
+
		}
+

+
		if (path) {
+
			schema_elt = ucl_lookup_path_char (schema, path, '/');
+
		}
+
		else {
+
			/* Use the top object */
+
			schema_elt = schema;
+
		}
+

+
		if (schema_elt) {
+
			res = ucl_object_validate (schema_elt, obj, &err);
+

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

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

+
	return 2;
+
}
+

+
static int
+
lua_ucl_object_gc (lua_State *L)
+
{
+
	ucl_object_t *obj;
+

+
	obj = lua_ucl_object_get (L, 1);
+

+
	ucl_object_unref (obj);
+

+
	return 0;
+
}
+

static void
lua_ucl_parser_mt (lua_State *L)
{
@@ -625,25 +907,45 @@ lua_ucl_parser_mt (lua_State *L)
	lua_pushcfunction (L, lua_ucl_parser_get_object);
	lua_setfield (L, -2, "get_object");

+
	lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
+
	lua_setfield (L, -2, "get_object_wrapped");
+

+
	lua_pushcfunction (L, lua_ucl_parser_validate);
+
	lua_setfield (L, -2, "validate");
+

	lua_pop (L, 1);
}

-
static int
-
lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
+
static void
+
lua_ucl_object_mt (lua_State *L)
{
-
	unsigned char *result;
+
	luaL_newmetatable (L, OBJECT_META);

-
	result = ucl_object_emit (obj, type);
+
	lua_pushvalue(L, -1);
+
	lua_setfield(L, -2, "__index");

-
	if (result != NULL) {
-
		lua_pushstring (L, (const char *)result);
-
		free (result);
-
	}
-
	else {
-
		lua_pushnil (L);
-
	}
+
	lua_pushcfunction (L, lua_ucl_object_gc);
+
	lua_setfield (L, -2, "__gc");

-
	return 1;
+
	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_pushcfunction (L, lua_ucl_object_unwrap);
+
	lua_setfield (L, -2, "unwrap");
+

+
	lua_pushcfunction (L, lua_ucl_object_unwrap);
+
	lua_setfield (L, -2, "tolua");
+

+
	lua_pushcfunction (L, lua_ucl_object_validate);
+
	lua_setfield (L, -2, "validate");
+

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

+
	lua_pop (L, 1);
}

static int
@@ -789,6 +1091,7 @@ luaopen_ucl (lua_State *L)
{
	lua_ucl_parser_mt (L);
	lua_ucl_null_mt (L);
+
	lua_ucl_object_mt (L);

	/* Create the refs weak table: */
	lua_createtable (L, 0, 2);
modified external/libucl/src/Makefile.am
@@ -12,6 +12,7 @@ libucl_la_SOURCES= ucl_emitter.c \
					ucl_schema.c \
					ucl_util.c \
					ucl_msgpack.c \
+
					ucl_sexp.c \
					xxhash.c
libucl_la_CFLAGS=	$(libucl_common_cflags) \
					@CURL_CFLAGS@
modified external/libucl/src/ucl_chartable.h
@@ -26,7 +26,7 @@

#include "ucl_internal.h"

-
static const unsigned int ucl_chartable[255] = {
+
static const unsigned int ucl_chartable[256] = {
UCL_CHARACTER_VALUE_END, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
@@ -255,6 +255,7 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR,
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR
};

modified external/libucl/src/ucl_emitter.c
@@ -498,7 +498,14 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,

	case UCL_STRING:
		ucl_emitter_print_key_msgpack (print_key, ctx, obj);
-
		ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
+

+
		if (obj->flags & UCL_OBJECT_BINARY) {
+
			ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
+
					obj->len);
+
		}
+
		else {
+
			ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
+
		}
		break;

	case UCL_NULL:
@@ -509,27 +516,31 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
	case UCL_OBJECT:
		ucl_emitter_print_key_msgpack (print_key, ctx, obj);
		ucl_emit_msgpack_start_obj (ctx, obj, print_key);
-
		it = ucl_object_iterate_new (obj);
+
		it = NULL;

-
		while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
+
		while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
			LL_FOREACH (cur, celt) {
				ucl_emit_msgpack_elt (ctx, celt, false, true);
+
				/* XXX:
+
				 * in msgpack the length of objects is encoded within a single elt
+
				 * so in case of multi-value keys we are using merely the first
+
				 * element ignoring others
+
				 */
+
				break;
			}
		}

-
		ucl_object_iterate_free (it);
		break;

	case UCL_ARRAY:
		ucl_emitter_print_key_msgpack (print_key, ctx, obj);
		ucl_emit_msgpack_start_array (ctx, obj, print_key);
-
		it = ucl_object_iterate_new (obj);
+
		it = NULL;

-
		while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
+
		while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
			ucl_emit_msgpack_elt (ctx, cur, false, false);
		}

-
		ucl_object_iterate_free (it);
		break;

	case UCL_USERDATA:
modified external/libucl/src/ucl_internal.h
@@ -157,7 +157,7 @@ struct ucl_macro {
struct ucl_stack {
	ucl_object_t *obj;
	struct ucl_stack *next;
-
	int level;
+
	uint64_t level;
};

struct ucl_chunk {
@@ -168,6 +168,8 @@ struct ucl_chunk {
	unsigned int line;
	unsigned int column;
	unsigned priority;
+
	enum ucl_duplicate_strategy strategy;
+
	enum ucl_parse_type parse_type;
	struct ucl_chunk *next;
};

@@ -303,9 +305,10 @@ ucl_create_err (UT_string **err, const char *fmt, ...)
__attribute__ (( format( printf, 2, 3) ));
#endif

+
#undef UCL_FATAL_ERRORS
+

static inline void
ucl_create_err (UT_string **err, const char *fmt, ...)
-

{
	if (*err == NULL) {
		utstring_new (*err);
@@ -314,6 +317,10 @@ ucl_create_err (UT_string **err, const char *fmt, ...)
		utstring_printf_va (*err, fmt, ap);
		va_end (ap);
	}
+

+
#ifdef UCL_FATAL_ERRORS
+
	assert (0);
+
#endif
}

/**
@@ -478,6 +485,15 @@ void ucl_emitter_print_string_msgpack (struct ucl_emitter_context *ctx,
		const char *s, size_t len);

/**
+
 * Print binary string to the msgpack output
+
 * @param ctx
+
 * @param s
+
 * @param len
+
 */
+
void ucl_emitter_print_binary_string_msgpack (struct ucl_emitter_context *ctx,
+
		const char *s, size_t len);
+

+
/**
 * Print array preamble for msgpack
 * @param ctx
 * @param len
@@ -498,7 +514,7 @@ void ucl_emitter_print_object_msgpack (struct ucl_emitter_context *ctx,
 */
void ucl_emitter_print_null_msgpack (struct ucl_emitter_context *ctx);
/**
-
 * Print object's key if needed to the msgpakc output
+
 * Print object's key if needed to the msgpack output
 * @param print_key
 * @param ctx
 * @param obj
@@ -507,4 +523,20 @@ void ucl_emitter_print_key_msgpack (bool print_key,
		struct ucl_emitter_context *ctx,
		const ucl_object_t *obj);

+
/**
+
 * Add new element to an object using the current merge strategy and priority
+
 * @param parser
+
 * @param nobj
+
 * @return
+
 */
+
bool ucl_parser_process_object_element (struct ucl_parser *parser,
+
		ucl_object_t *nobj);
+

+
/**
+
 * Parse msgpack chunk
+
 * @param parser
+
 * @return
+
 */
+
bool ucl_parse_msgpack (struct ucl_parser *parser);
+

#endif /* UCL_INTERNAL_H_ */
modified external/libucl/src/ucl_msgpack.c
@@ -85,10 +85,16 @@
#define TO_BE16 SWAP_LE_BE16
#define TO_BE32 SWAP_LE_BE32
#define TO_BE64 SWAP_LE_BE64
+
#define FROM_BE16 SWAP_LE_BE16
+
#define FROM_BE32 SWAP_LE_BE32
+
#define FROM_BE64 SWAP_LE_BE64
#else
#define TO_BE16(val) (uint16_t)(val)
#define TO_BE32(val) (uint32_t)(val)
#define TO_BE64(val) (uint64_t)(val)
+
#define FROM_BE16(val) (uint16_t)(val)
+
#define FROM_BE32(val) (uint32_t)(val)
+
#define FROM_BE64(val) (uint64_t)(val)
#endif

void
@@ -139,9 +145,9 @@ ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, int64_t val)
		/* Bithack abs */
		uval = ((val ^ (val >> 63)) - (val >> 63));

-
		if (val >= -(1 << 5)) {
+
		if (val > -(1 << 5)) {
			len = 1;
-
			buf[0] = mask_negative | (uval & 0xff);
+
			buf[0] = (mask_negative | uval) & 0xff;
		}
		else if (uval <= 0xff) {
			len = 2;
@@ -241,6 +247,39 @@ ucl_emitter_print_string_msgpack (struct ucl_emitter_context *ctx,
}

void
+
ucl_emitter_print_binary_string_msgpack (struct ucl_emitter_context *ctx,
+
		const char *s, size_t len)
+
{
+
	const struct ucl_emitter_functions *func = ctx->func;
+
	const unsigned char l8_ch = 0xc4, l16_ch = 0xc5, l32_ch = 0xc6;
+
	unsigned char buf[5];
+
	unsigned blen;
+

+
	if (len <= 0xff) {
+
		blen = 2;
+
		buf[0] = l8_ch;
+
		buf[1] = len & 0xff;
+
	}
+
	else if (len <= 0xffff) {
+
		uint16_t bl = TO_BE16 (len);
+

+
		blen = 3;
+
		buf[0] = l16_ch;
+
		memcpy (&buf[1], &bl, sizeof (bl));
+
	}
+
	else {
+
		uint32_t bl = TO_BE32 (len);
+

+
		blen = 5;
+
		buf[0] = l32_ch;
+
		memcpy (&buf[1], &bl, sizeof (bl));
+
	}
+

+
	func->ucl_emitter_append_len (buf, blen, func->ud);
+
	func->ucl_emitter_append_len (s, len, func->ud);
+
}
+

+
void
ucl_emitter_print_null_msgpack (struct ucl_emitter_context *ctx)
{
	const struct ucl_emitter_functions *func = ctx->func;
@@ -317,3 +356,1245 @@ ucl_emitter_print_object_msgpack (struct ucl_emitter_context *ctx, size_t len)

	func->ucl_emitter_append_len (buf, blen, func->ud);
}
+

+

+
enum ucl_msgpack_format {
+
	msgpack_positive_fixint = 0,
+
	msgpack_fixmap,
+
	msgpack_fixarray,
+
	msgpack_fixstr,
+
	msgpack_nil,
+
	msgpack_false,
+
	msgpack_true,
+
	msgpack_bin8,
+
	msgpack_bin16,
+
	msgpack_bin32,
+
	msgpack_ext8,
+
	msgpack_ext16,
+
	msgpack_ext32,
+
	msgpack_float32,
+
	msgpack_float64,
+
	msgpack_uint8,
+
	msgpack_uint16,
+
	msgpack_uint32,
+
	msgpack_uint64,
+
	msgpack_int8,
+
	msgpack_int16,
+
	msgpack_int32,
+
	msgpack_int64,
+
	msgpack_fixext1,
+
	msgpack_fixext2,
+
	msgpack_fixext4,
+
	msgpack_fixext8,
+
	msgpack_fixext16,
+
	msgpack_str8,
+
	msgpack_str16,
+
	msgpack_str32,
+
	msgpack_array16,
+
	msgpack_array32,
+
	msgpack_map16,
+
	msgpack_map32,
+
	msgpack_negative_fixint,
+
	msgpack_invalid
+
};
+

+
typedef ssize_t (*ucl_msgpack_parse_function)(struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+

+
static ssize_t ucl_msgpack_parse_map (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_array (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_string (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_int (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_float (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_bool (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_null (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+
static ssize_t ucl_msgpack_parse_ignore (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain);
+

+
#define MSGPACK_FLAG_FIXED (1 << 0)
+
#define MSGPACK_FLAG_CONTAINER (1 << 1)
+
#define MSGPACK_FLAG_TYPEVALUE (1 << 2)
+
#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
+
 */
+
struct ucl_msgpack_parser {
+
	uint8_t prefix;						/* Prefix byte					*/
+
	uint8_t prefixlen;					/* Length of prefix in bits		*/
+
	uint8_t fmt;						/* The desired format 			*/
+
	uint8_t len;						/* Length of the object
+
										  (either length bytes
+
										  or length of value in case
+
										  of fixed objects 				*/
+
	uint8_t flags;						/* Flags of the specified type	*/
+
	ucl_msgpack_parse_function func;	/* Parser function				*/
+
} parsers[] = {
+
	{
+
			0xa0,
+
			3,
+
			msgpack_fixstr,
+
			0,
+
			MSGPACK_FLAG_FIXED|MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0x0,
+
			1,
+
			msgpack_positive_fixint,
+
			0,
+
			MSGPACK_FLAG_FIXED|MSGPACK_FLAG_TYPEVALUE,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xe0,
+
			3,
+
			msgpack_negative_fixint,
+
			0,
+
			MSGPACK_FLAG_FIXED|MSGPACK_FLAG_TYPEVALUE,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0x80,
+
			4,
+
			msgpack_fixmap,
+
			0,
+
			MSGPACK_FLAG_FIXED|MSGPACK_FLAG_CONTAINER|MSGPACK_FLAG_ASSOC,
+
			ucl_msgpack_parse_map
+
	},
+
	{
+
			0x90,
+
			4,
+
			msgpack_fixarray,
+
			0,
+
			MSGPACK_FLAG_FIXED|MSGPACK_FLAG_CONTAINER,
+
			ucl_msgpack_parse_array
+
	},
+
	{
+
			0xd9,
+
			8,
+
			msgpack_str8,
+
			1,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xc4,
+
			8,
+
			msgpack_bin8,
+
			1,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xcf,
+
			8,
+
			msgpack_uint64,
+
			8,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xd3,
+
			8,
+
			msgpack_int64,
+
			8,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xce,
+
			8,
+
			msgpack_uint32,
+
			4,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xd2,
+
			8,
+
			msgpack_int32,
+
			4,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xcb,
+
			8,
+
			msgpack_float64,
+
			8,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_float
+
	},
+
	{
+
			0xca,
+
			8,
+
			msgpack_float32,
+
			4,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_float
+
	},
+
	{
+
			0xc2,
+
			8,
+
			msgpack_false,
+
			1,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_TYPEVALUE,
+
			ucl_msgpack_parse_bool
+
	},
+
	{
+
			0xc3,
+
			8,
+
			msgpack_true,
+
			1,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_TYPEVALUE,
+
			ucl_msgpack_parse_bool
+
	},
+
	{
+
			0xcc,
+
			8,
+
			msgpack_uint8,
+
			1,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xcd,
+
			8,
+
			msgpack_uint16,
+
			2,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xd0,
+
			8,
+
			msgpack_int8,
+
			1,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xd1,
+
			8,
+
			msgpack_int16,
+
			2,
+
			MSGPACK_FLAG_FIXED,
+
			ucl_msgpack_parse_int
+
	},
+
	{
+
			0xc0,
+
			8,
+
			msgpack_nil,
+
			0,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_TYPEVALUE,
+
			ucl_msgpack_parse_null
+
	},
+
	{
+
			0xda,
+
			8,
+
			msgpack_str16,
+
			2,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xdb,
+
			8,
+
			msgpack_str32,
+
			4,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xc5,
+
			8,
+
			msgpack_bin16,
+
			2,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xc6,
+
			8,
+
			msgpack_bin32,
+
			4,
+
			MSGPACK_FLAG_KEY,
+
			ucl_msgpack_parse_string
+
	},
+
	{
+
			0xdc,
+
			8,
+
			msgpack_array16,
+
			2,
+
			MSGPACK_FLAG_CONTAINER,
+
			ucl_msgpack_parse_array
+
	},
+
	{
+
			0xdd,
+
			8,
+
			msgpack_array32,
+
			4,
+
			MSGPACK_FLAG_CONTAINER,
+
			ucl_msgpack_parse_array
+
	},
+
	{
+
			0xde,
+
			8,
+
			msgpack_map16,
+
			2,
+
			MSGPACK_FLAG_CONTAINER|MSGPACK_FLAG_ASSOC,
+
			ucl_msgpack_parse_map
+
	},
+
	{
+
			0xdf,
+
			8,
+
			msgpack_map32,
+
			4,
+
			MSGPACK_FLAG_CONTAINER|MSGPACK_FLAG_ASSOC,
+
			ucl_msgpack_parse_map
+
	},
+
	{
+
			0xc7,
+
			8,
+
			msgpack_ext8,
+
			1,
+
			MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xc8,
+
			8,
+
			msgpack_ext16,
+
			2,
+
			MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xc9,
+
			8,
+
			msgpack_ext32,
+
			4,
+
			MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xd4,
+
			8,
+
			msgpack_fixext1,
+
			1,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xd5,
+
			8,
+
			msgpack_fixext2,
+
			2,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xd6,
+
			8,
+
			msgpack_fixext4,
+
			4,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xd7,
+
			8,
+
			msgpack_fixext8,
+
			8,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	},
+
	{
+
			0xd8,
+
			8,
+
			msgpack_fixext16,
+
			16,
+
			MSGPACK_FLAG_FIXED | MSGPACK_FLAG_EXT,
+
			ucl_msgpack_parse_ignore
+
	}
+
};
+

+
#undef MSGPACK_DEBUG_PARSER
+

+
static inline struct ucl_msgpack_parser *
+
ucl_msgpack_get_parser_from_type (unsigned char t)
+
{
+
	unsigned int i, shift, mask;
+

+
	for (i = 0; i < sizeof (parsers) / sizeof (parsers[0]); i ++) {
+
		shift = CHAR_BIT - parsers[i].prefixlen;
+
		mask = parsers[i].prefix >> shift;
+

+
		if (mask == (t >> shift)) {
+
			return &parsers[i];
+
		}
+
	}
+

+
	return NULL;
+
}
+

+
static inline struct ucl_stack *
+
ucl_msgpack_get_container (struct ucl_parser *parser,
+
		struct ucl_msgpack_parser *obj_parser, uint64_t len)
+
{
+
	struct ucl_stack *stack;
+

+
	assert (obj_parser != NULL);
+

+
	if (obj_parser->flags & MSGPACK_FLAG_CONTAINER) {
+
		assert ((len & MSGPACK_CONTAINER_BIT) == 0);
+
		/*
+
		 * Insert new container to the stack
+
		 */
+
		if (parser->stack == NULL) {
+
			parser->stack = calloc (1, sizeof (struct ucl_stack));
+

+
			if (parser->stack == NULL) {
+
				ucl_create_err (&parser->err, "no memory");
+
				return NULL;
+
			}
+
		}
+
		else {
+
			stack = calloc (1, sizeof (struct ucl_stack));
+

+
			if (stack == NULL) {
+
				ucl_create_err (&parser->err, "no memory");
+
				return NULL;
+
			}
+

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

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

+
#ifdef MSGPACK_DEBUG_PARSER
+
		stack = parser->stack;
+
		while (stack) {
+
			fprintf(stderr, "+");
+
			stack = stack->next;
+
		}
+

+
		fprintf(stderr, "%s -> %d\n", obj_parser->flags & MSGPACK_FLAG_ASSOC ? "object" : "array", (int)len);
+
#endif
+
	}
+
	else {
+
		/*
+
		 * Get the current stack top
+
		 */
+
		if (parser->stack) {
+
			return parser->stack;
+
		}
+
		else {
+
			ucl_create_err (&parser->err, "bad top level object for msgpack");
+
			return NULL;
+
		}
+
	}
+

+
	return parser->stack;
+
}
+

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

+
	return false;
+
}
+

+
static bool
+
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 (obj != NULL);
+
	assert (container->obj != NULL);
+

+
	if (container->obj->type == UCL_ARRAY) {
+
		ucl_array_append (container->obj, obj);
+
	}
+
	else if (container->obj->type == UCL_OBJECT) {
+
		if (key == NULL || keylen == 0) {
+
			ucl_create_err (&parser->err, "cannot insert object with no key");
+
			return false;
+
		}
+

+
		obj->key = key;
+
		obj->keylen = keylen;
+

+
		if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
+
			ucl_copy_key_trash (obj);
+
		}
+

+
		ucl_parser_process_object_element (parser, obj);
+
	}
+
	else {
+
		ucl_create_err (&parser->err, "bad container type");
+
		return false;
+
	}
+

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

+
	return true;
+
}
+

+
static struct ucl_stack *
+
ucl_msgpack_get_next_container (struct ucl_parser *parser)
+
{
+
	struct ucl_stack *cur = NULL;
+
	uint64_t level;
+

+
	cur = parser->stack;
+

+
	if (cur == NULL) {
+
		return NULL;
+
	}
+

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

+
		if (level == 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;
+
			while (cur) {
+
				fprintf(stderr, "-");
+
				cur = cur->next;
+
			}
+
			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);
+
		}
+
	}
+

+
	/*
+
	 * For UCL containers we don't know length, so we just insert the whole
+
	 * message pack blob into the top level container
+
	 */
+

+
	assert (cur->obj != NULL);
+

+
	return cur;
+
}
+

+
#define CONSUME_RET do {									\
+
	if (ret != -1) {										\
+
		p += ret;											\
+
		remain -= ret;										\
+
		obj_parser = NULL;									\
+
		assert (remain >= 0);								\
+
	}														\
+
	else {													\
+
		ucl_create_err (&parser->err,						\
+
			"cannot parse type %d of len %u",				\
+
			(int)obj_parser->fmt,							\
+
			(unsigned)len);									\
+
		return false;										\
+
	}														\
+
} while(0)
+

+
#define GET_NEXT_STATE do {									\
+
	container = ucl_msgpack_get_next_container (parser);	\
+
	if (container == NULL) {								\
+
		ucl_create_err (&parser->err,						\
+
					"empty container");						\
+
		return false;										\
+
	}														\
+
	next_state = container->obj->type == UCL_OBJECT ? 		\
+
					read_assoc_key : read_array_value;		\
+
} while(0)
+

+
static bool
+
ucl_msgpack_consume (struct ucl_parser *parser)
+
{
+
	const unsigned char *p, *end, *key = NULL;
+
	struct ucl_stack *container;
+
	enum e_msgpack_parser_state {
+
		read_type,
+
		start_assoc,
+
		start_array,
+
		read_assoc_key,
+
		read_assoc_value,
+
		finish_assoc_value,
+
		read_array_value,
+
		finish_array_value,
+
		error_state
+
	} state = read_type, next_state = error_state;
+
	struct ucl_msgpack_parser *obj_parser;
+
	uint64_t len;
+
	ssize_t ret, remain, keylen = 0;
+
#ifdef MSGPACK_DEBUG_PARSER
+
	uint64_t i;
+
	enum e_msgpack_parser_state hist[256];
+
#endif
+

+
	p = parser->chunks->begin;
+
	remain = parser->chunks->remain;
+
	end = p + remain;
+

+

+
	while (p < end) {
+
#ifdef MSGPACK_DEBUG_PARSER
+
		hist[i++ % 256] = state;
+
#endif
+
		switch (state) {
+
		case read_type:
+
			obj_parser = ucl_msgpack_get_parser_from_type (*p);
+

+
			if (obj_parser == NULL) {
+
				ucl_create_err (&parser->err, "unknown msgpack format: %x",
+
						(unsigned int)*p);
+

+
				return false;
+
			}
+
			/* Now check length sanity */
+
			if (obj_parser->flags & MSGPACK_FLAG_FIXED) {
+
				if (obj_parser->len == 0) {
+
					/* We have an embedded size */
+
					len = *p & ~obj_parser->prefix;
+
				}
+
				else {
+
					if (remain < obj_parser->len) {
+
						ucl_create_err (&parser->err, "not enough data remain to "
+
								"read object's length: %u remain, %u needed",
+
								(unsigned)remain, obj_parser->len);
+

+
						return false;
+
					}
+

+
					len = obj_parser->len;
+
				}
+

+
				if (!(obj_parser->flags & MSGPACK_FLAG_TYPEVALUE)) {
+
					/* We must pass value as the second byte */
+
					if (remain > 0) {
+
						p ++;
+
						remain --;
+
					}
+
				}
+
				else {
+
					/* Len is irrelevant now */
+
					len = 0;
+
				}
+
			}
+
			else {
+
				/* Length is not embedded */
+
				if (remain < obj_parser->len) {
+
					ucl_create_err (&parser->err, "not enough data remain to "
+
							"read object's length: %u remain, %u needed",
+
							(unsigned)remain, obj_parser->len);
+

+
					return false;
+
				}
+

+
				p ++;
+
				remain --;
+

+
				switch (obj_parser->len) {
+
				case 1:
+
					len = *p;
+
					break;
+
				case 2:
+
					len = FROM_BE16 (*(uint16_t *)p);
+
					break;
+
				case 4:
+
					len = FROM_BE32 (*(uint32_t *)p);
+
					break;
+
				case 8:
+
					len = FROM_BE64 (*(uint64_t *)p);
+
					break;
+
				default:
+
					assert (0);
+
					break;
+
				}
+

+
				p += obj_parser->len;
+
				remain -= obj_parser->len;
+
			}
+

+
			if (obj_parser->flags & MSGPACK_FLAG_ASSOC) {
+
				/* We have just read the new associative map */
+
				state = start_assoc;
+
			}
+
			else if (obj_parser->flags & MSGPACK_FLAG_CONTAINER){
+
				state = start_array;
+
			}
+
			else {
+
				state = next_state;
+
			}
+

+
			break;
+
		case start_assoc:
+
			parser->cur_obj = ucl_object_new_full (UCL_OBJECT,
+
					parser->chunks->priority);
+
			/* Insert to the previous level container */
+
			if (parser->stack && !ucl_msgpack_insert_object (parser,
+
					key, keylen, parser->cur_obj)) {
+
				return false;
+
			}
+
			/* Get new container */
+
			container = ucl_msgpack_get_container (parser, obj_parser, len);
+

+
			if (container == NULL) {
+
				return false;
+
			}
+

+
			ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
					p, remain);
+
			CONSUME_RET;
+
			key = NULL;
+
			keylen = 0;
+

+
			if (len > 0) {
+
				state = read_type;
+
				next_state = read_assoc_key;
+
			}
+
			else {
+
				/* Empty object */
+
				state = finish_assoc_value;
+
			}
+
			break;
+

+
		case start_array:
+
			parser->cur_obj = ucl_object_new_full (UCL_ARRAY,
+
					parser->chunks->priority);
+
			/* Insert to the previous level container */
+
			if (parser->stack && !ucl_msgpack_insert_object (parser,
+
					key, keylen, parser->cur_obj)) {
+
				return false;
+
			}
+
			/* Get new container */
+
			container = ucl_msgpack_get_container (parser, obj_parser, len);
+

+
			if (container == NULL) {
+
				return false;
+
			}
+

+
			ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
								p, remain);
+
			CONSUME_RET;
+

+
			if (len > 0) {
+
				state = read_type;
+
				next_state = read_array_value;
+
			}
+
			else {
+
				/* Empty array */
+
				state = finish_array_value;
+
			}
+
			break;
+

+
		case read_array_value:
+
			/*
+
			 * p is now at the value start, len now contains length read and
+
			 * obj_parser contains the corresponding specific parser
+
			 */
+
			container = parser->stack;
+

+
			if (container == NULL) {
+
				return false;
+
			}
+

+
			ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
					p, remain);
+
			CONSUME_RET;
+

+

+
			/* Insert value to the container and check if we have finished array */
+
			if (!ucl_msgpack_insert_object (parser, NULL, 0,
+
					parser->cur_obj)) {
+
				return false;
+
			}
+

+
			if (ucl_msgpack_is_container_finished (container)) {
+
				state = finish_array_value;
+
			}
+
			else {
+
				/* Read more elements */
+
				state = read_type;
+
				next_state = read_array_value;
+
			}
+

+
			break;
+

+
		case read_assoc_key:
+
			/*
+
			 * Keys must have string type for ucl msgpack
+
			 */
+
			if (!(obj_parser->flags & MSGPACK_FLAG_KEY)) {
+
				ucl_create_err (&parser->err, "bad type for key: %u, expected "
+
						"string", (unsigned)obj_parser->fmt);
+

+
				return false;
+
			}
+

+
			key = p;
+
			keylen = len;
+

+
			if (keylen > remain || keylen == 0) {
+
				ucl_create_err (&parser->err, "too long or empty key");
+
				return false;
+
			}
+

+
			p += len;
+
			remain -= len;
+

+
			state = read_type;
+
			next_state = read_assoc_value;
+
			break;
+

+
		case read_assoc_value:
+
			/*
+
			 * p is now at the value start, len now contains length read and
+
			 * obj_parser contains the corresponding specific parser
+
			 */
+
			container = parser->stack;
+

+
			if (container == NULL) {
+
				return false;
+
			}
+

+
			ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
					p, remain);
+
			CONSUME_RET;
+

+
			assert (key != NULL && keylen > 0);
+

+
			if (!ucl_msgpack_insert_object (parser, key, keylen,
+
					parser->cur_obj)) {
+
				return false;
+
			}
+

+
			key = NULL;
+
			keylen = 0;
+

+
			if (ucl_msgpack_is_container_finished (container)) {
+
				state = finish_assoc_value;
+
			}
+
			else {
+
				/* Read more elements */
+
				state = read_type;
+
				next_state = read_assoc_key;
+
			}
+
			break;
+

+
		case finish_array_value:
+
		case finish_assoc_value:
+
			GET_NEXT_STATE;
+
			state = read_type;
+
			break;
+

+
		case error_state:
+
			ucl_create_err (&parser->err, "invalid state machine state");
+

+
			return false;
+
		}
+
	}
+

+
	/* Check the finishing state */
+
	switch (state) {
+
	case start_array:
+
	case start_assoc:
+
		/* Empty container at the end */
+
		if (len != 0) {
+
			ucl_create_err (&parser->err, "invalid non-empty container at the end");
+

+
			return false;
+
		}
+

+
		parser->cur_obj = ucl_object_new_full (
+
				state == start_array ? UCL_ARRAY : UCL_OBJECT,
+
				parser->chunks->priority);
+
		/* Insert to the previous level container */
+
		if (!ucl_msgpack_insert_object (parser,
+
				key, keylen, parser->cur_obj)) {
+
			return false;
+
		}
+
		/* Get new container */
+
		container = ucl_msgpack_get_container (parser, obj_parser, len);
+

+
		if (container == NULL) {
+
			return false;
+
		}
+

+
		ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
				p, remain);
+
		break;
+

+
	case read_array_value:
+
	case read_assoc_value:
+
		if (len != 0) {
+
			ucl_create_err (&parser->err, "unfinished value at the end");
+

+
			return false;
+
		}
+

+
		container = parser->stack;
+

+
		if (container == NULL) {
+
			return false;
+
		}
+

+
		ret = obj_parser->func (parser, container, len, obj_parser->fmt,
+
				p, remain);
+
		CONSUME_RET;
+

+

+
		/* Insert value to the container and check if we have finished array */
+
		if (!ucl_msgpack_insert_object (parser, NULL, 0,
+
				parser->cur_obj)) {
+
			return false;
+
		}
+
		break;
+
	case finish_array_value:
+
	case finish_assoc_value:
+
	case read_type:
+
		/* Valid finishing state */
+
		break;
+
	default:
+
		/* Invalid finishing state */
+
		ucl_create_err (&parser->err, "invalid state machine finishing state: %d",
+
				state);
+

+
		return false;
+
	}
+

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

+
	return true;
+
}
+

+
bool
+
ucl_parse_msgpack (struct ucl_parser *parser)
+
{
+
	ucl_object_t *container = NULL;
+
	const unsigned char *p;
+
	bool ret;
+

+
	assert (parser != NULL);
+
	assert (parser->chunks != NULL);
+
	assert (parser->chunks->begin != NULL);
+
	assert (parser->chunks->remain != 0);
+

+
	p = parser->chunks->begin;
+

+
	if (parser->stack) {
+
		container = parser->stack->obj;
+
	}
+

+
	/*
+
	 * When we start parsing message pack chunk, we must ensure that we
+
	 * have either a valid container or the top object inside message pack is
+
	 * of container type
+
	 */
+
	if (container == NULL) {
+
		if ((*p & 0x80) != 0x80 && !(*p >= 0xdc && *p <= 0xdf)) {
+
			ucl_create_err (&parser->err, "bad top level object for msgpack");
+
			return false;
+
		}
+
	}
+

+
	ret = ucl_msgpack_consume (parser);
+

+
	if (ret && parser->top_obj == NULL) {
+
		parser->top_obj = parser->cur_obj;
+
	}
+

+
	return ret;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_map (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	container->obj = parser->cur_obj;
+

+
	return 0;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_array (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	container->obj = parser->cur_obj;
+

+
	return 0;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_string (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	ucl_object_t *obj;
+

+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	obj = ucl_object_new_full (UCL_STRING, parser->chunks->priority);
+
	obj->value.sv = pos;
+
	obj->len = len;
+

+
	if (fmt >= msgpack_bin8 && fmt <= msgpack_bin32) {
+
		obj->flags |= UCL_OBJECT_BINARY;
+
	}
+

+
	if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
+
		if (obj->flags & UCL_OBJECT_BINARY) {
+
			obj->trash_stack[UCL_TRASH_VALUE] = malloc (len);
+

+
			if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
+
				memcpy (obj->trash_stack[UCL_TRASH_VALUE], pos, len);
+
			}
+
		}
+
		else {
+
			ucl_copy_value_trash (obj);
+
		}
+
	}
+

+
	parser->cur_obj = obj;
+

+
	return len;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_int (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	ucl_object_t *obj;
+

+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	obj = ucl_object_new_full (UCL_INT, parser->chunks->priority);
+

+
	switch (fmt) {
+
	case msgpack_positive_fixint:
+
		obj->value.iv = (*pos & 0x7f);
+
		len = 1;
+
		break;
+
	case msgpack_negative_fixint:
+
		obj->value.iv = - (*pos & 0x1f);
+
		len = 1;
+
		break;
+
	case msgpack_uint8:
+
		obj->value.iv = (unsigned char)*pos;
+
		len = 1;
+
		break;
+
	case msgpack_int8:
+
		obj->value.iv = (signed char)*pos;
+
		len = 1;
+
		break;
+
	case msgpack_int16:
+
		obj->value.iv = FROM_BE16 (*(int16_t *)pos);
+
		len = 2;
+
		break;
+
	case msgpack_uint16:
+
		obj->value.iv = FROM_BE16 (*(uint16_t *)pos);
+
		len = 2;
+
		break;
+
	case msgpack_int32:
+
		obj->value.iv = FROM_BE32 (*(int32_t *)pos);
+
		len = 4;
+
		break;
+
	case msgpack_uint32:
+
		obj->value.iv = FROM_BE32 (*(uint32_t *)pos);
+
		len = 4;
+
		break;
+
	case msgpack_int64:
+
		obj->value.iv = FROM_BE64 (*(int64_t *)pos);
+
		len = 8;
+
		break;
+
	case msgpack_uint64:
+
		obj->value.iv = FROM_BE64 (*(uint64_t *)pos);
+
		len = 8;
+
		break;
+
	default:
+
		assert (0);
+
		break;
+
	}
+

+
	parser->cur_obj = obj;
+

+
	return len;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_float (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	ucl_object_t *obj;
+
	union {
+
		uint32_t i;
+
		float f;
+
	} d;
+

+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	obj = ucl_object_new_full (UCL_FLOAT, parser->chunks->priority);
+

+
	switch (fmt) {
+
	case msgpack_float32:
+
		d.i = FROM_BE32 (*(uint32_t *)pos);
+
		/* XXX: can be slow */
+
		obj->value.dv = d.f;
+
		len = 4;
+
		break;
+
	case msgpack_float64:
+
		obj->value.iv = FROM_BE64 (*(uint64_t *)pos);
+
		len = 8;
+
		break;
+
	default:
+
		assert (0);
+
		break;
+
	}
+

+
	parser->cur_obj = obj;
+

+
	return len;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_bool (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	ucl_object_t *obj;
+

+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	obj = ucl_object_new_full (UCL_BOOLEAN, parser->chunks->priority);
+

+
	switch (fmt) {
+
	case msgpack_true:
+
		obj->value.iv = true;
+
		break;
+
	case msgpack_false:
+
		obj->value.iv = false;
+
		break;
+
	default:
+
		assert (0);
+
		break;
+
	}
+

+
	parser->cur_obj = obj;
+

+
	return 1;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_null (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	ucl_object_t *obj;
+

+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
+
	parser->cur_obj = obj;
+

+
	return 1;
+
}
+

+
static ssize_t
+
ucl_msgpack_parse_ignore (struct ucl_parser *parser,
+
		struct ucl_stack *container, size_t len, enum ucl_msgpack_format fmt,
+
		const unsigned char *pos, size_t remain)
+
{
+
	if (len > remain) {
+
		return -1;
+
	}
+

+
	switch (fmt) {
+
	case msgpack_fixext1:
+
		len = 2;
+
		break;
+
	case msgpack_fixext2:
+
		len = 3;
+
		break;
+
	case msgpack_fixext4:
+
		len = 5;
+
		break;
+
	case msgpack_fixext8:
+
		len = 9;
+
		break;
+
	case msgpack_fixext16:
+
		len = 17;
+
		break;
+
	case msgpack_ext8:
+
	case msgpack_ext16:
+
	case msgpack_ext32:
+
		len = len + 1;
+
		break;
+
	default:
+
		ucl_create_err (&parser->err, "bad type: %x", (unsigned)fmt);
+
		return -1;
+
	}
+

+
	return len;
+
}
modified external/libucl/src/ucl_parser.c
@@ -562,7 +562,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
 * @return
 */
static inline ucl_object_t *
-
ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level)
+
ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
+
		bool is_array, int level)
{
	struct ucl_stack *st;

@@ -573,7 +574,9 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
		else {
			obj->type = UCL_OBJECT;
		}
-
		obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
		if (obj->value.ov == NULL) {
+
			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
		}
		parser->state = UCL_STATE_KEY;
	}
	else {
@@ -1001,6 +1004,98 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
	}
}

+
bool
+
ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
+
{
+
	ucl_hash_t *container;
+
	ucl_object_t *tobj;
+

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

+
	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
+
	if (tobj == NULL) {
+
		container = ucl_hash_insert_object (container, nobj,
+
				parser->flags & UCL_PARSER_KEY_LOWERCASE);
+
		nobj->prev = nobj;
+
		nobj->next = NULL;
+
		parser->stack->obj->len ++;
+
	}
+
	else {
+
		unsigned priold = ucl_object_get_priority (tobj),
+
				prinew = ucl_object_get_priority (nobj);
+
		switch (parser->chunks->strategy) {
+

+
		case UCL_DUPLICATE_APPEND:
+
			/*
+
			 * The logic here is the following:
+
			 *
+
			 * - if we have two objects with the same priority, then we form an
+
			 * implicit or explicit array
+
			 * - 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;
+
			}
+

+
			if (priold == prinew) {
+
				ucl_parser_append_elt (parser, container, tobj, nobj);
+
			}
+
			else if (priold > prinew) {
+
				/*
+
				 * We add this new object to a list of trash objects just to ensure
+
				 * that it won't come to any real object
+
				 * XXX: rather inefficient approach
+
				 */
+
				DL_APPEND (parser->trash_objs, nobj);
+
			}
+
			else {
+
				ucl_hash_replace (container, tobj, nobj);
+
				ucl_object_unref (tobj);
+
			}
+

+
			break;
+

+
		case UCL_DUPLICATE_REWRITE:
+
			/* We just rewrite old values regardless of priority */
+
			ucl_hash_replace (container, tobj, nobj);
+
			ucl_object_unref (tobj);
+

+
			break;
+

+
		case UCL_DUPLICATE_ERROR:
+
			ucl_create_err (&parser->err, "error while parsing %s: "
+
					"line: %d, column: %d: duplicate element for key '%s' "
+
					"has been found",
+
					parser->cur_file ? parser->cur_file : "<unknown>",
+
					parser->chunks->line, parser->chunks->column, nobj->key);
+
			return false;
+

+
		case UCL_DUPLICATE_MERGE:
+
			/*
+
			 * Here we do have some old object so we just push it on top of objects stack
+
			 */
+
			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
+
				ucl_object_unref (nobj);
+
				nobj = tobj;
+
			}
+
			else {
+
				/* For other types we create implicit array as usual */
+
				ucl_parser_append_elt (parser, container, tobj, nobj);
+
			}
+
			break;
+
		}
+
	}
+

+
	parser->stack->obj->value.ov = container;
+
	parser->cur_obj = nobj;
+

+
	return true;
+
}
+

/**
 * Parse a key in an object
 * @param parser
@@ -1018,8 +1113,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
	bool got_quote = false, got_eq = false, got_semicolon = false,
			need_unescape = false, ucl_escape = false, var_expand = false,
			got_content = false, got_sep = false;
-
	ucl_object_t *nobj, *tobj;
-
	ucl_hash_t *container;
+
	ucl_object_t *nobj;
	ssize_t keylen;

	p = chunk->pos;
@@ -1204,57 +1298,17 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
		return false;
	}

-
	container = parser->stack->obj->value.ov;
	nobj->key = key;
	nobj->keylen = keylen;
-
	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
-
	if (tobj == NULL) {
-
		container = ucl_hash_insert_object (container, nobj,
-
				parser->flags & UCL_PARSER_KEY_LOWERCASE);
-
		nobj->prev = nobj;
-
		nobj->next = NULL;
-
		parser->stack->obj->len ++;
-
	}
-
	else {
-
		/*
-
		 * The logic here is the following:
-
		 *
-
		 * - if we have two objects with the same priority, then we form an
-
		 * implicit or explicit array
-
		 * - if a new object has bigger priority, then we overwrite an old one
-
		 * - if a new object has lower priority, then we ignore it
-
		 */
-
		unsigned priold = ucl_object_get_priority (tobj),
-
				prinew = ucl_object_get_priority (nobj);
-

-
		/* Special case for inherited objects */
-
		if (tobj->flags & UCL_OBJECT_INHERITED) {
-
			prinew = priold + 1;
-
		}

-
		if (priold == prinew) {
-
			ucl_parser_append_elt (parser, container, tobj, nobj);
-
		}
-
		else if (priold > prinew) {
-
			/*
-
			 * We add this new object to a list of trash objects just to ensure
-
			 * that it won't come to any real object
-
			 * XXX: rather inefficient approach
-
			 */
-
			DL_APPEND (parser->trash_objs, nobj);
-
		}
-
		else {
-
			ucl_hash_replace (container, tobj, nobj);
-
			ucl_object_unref (tobj);
-
		}
+
	if (!ucl_parser_process_object_element (parser, nobj)) {
+
		return false;
	}

	if (ucl_escape) {
		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
	}

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

	return true;
}
@@ -1387,8 +1441,8 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
	return len;
}

-
static ucl_object_t*
-
ucl_get_value_object (struct ucl_parser *parser)
+
static inline ucl_object_t*
+
ucl_parser_get_container (struct ucl_parser *parser)
{
	ucl_object_t *t, *obj = NULL;

@@ -1400,7 +1454,12 @@ ucl_get_value_object (struct ucl_parser *parser)
		/* Object must be allocated */
		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
		t = parser->stack->obj;
-
		ucl_array_append (t, obj);
+

+
		if (!ucl_array_append (t, obj)) {
+
			ucl_object_unref (obj);
+
			return NULL;
+
		}
+

		parser->cur_obj = obj;
	}
	else {
@@ -1451,7 +1510,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
				return false;
			}

-
			obj = ucl_get_value_object (parser);
+
			obj = ucl_parser_get_container (parser);
			str_len = chunk->pos - c - 2;
			obj->type = UCL_STRING;
			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
@@ -1468,9 +1527,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
			return true;
			break;
		case '{':
-
			obj = ucl_get_value_object (parser);
+
			obj = ucl_parser_get_container (parser);
			/* We have a new object */
-
			obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
+
			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
			if (obj == NULL) {
				return false;
			}
@@ -1480,9 +1539,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
			return true;
			break;
		case '[':
-
			obj = ucl_get_value_object (parser);
+
			obj = ucl_parser_get_container (parser);
			/* We have a new array */
-
			obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
+
			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
			if (obj == NULL) {
				return false;
			}
@@ -1502,7 +1561,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
			}
			break;
		case '<':
-
			obj = ucl_get_value_object (parser);
+
			obj = ucl_parser_get_container (parser);
			/* We have something like multiline value, which must be <<[A-Z]+\n */
			if (chunk->end - p > 3) {
				if (memcmp (p, "<<", 2) == 0) {
@@ -1545,7 +1604,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
		default:
parse_string:
			if (obj == NULL) {
-
				obj = ucl_get_value_object (parser);
+
				obj = ucl_parser_get_container (parser);
			}

			/* Parse atom */
@@ -1905,17 +1964,6 @@ ucl_state_machine (struct ucl_parser *parser)
	bool next_key = false, end_of_object = false, ret;

	if (parser->top_obj == NULL) {
-
		if (*chunk->pos == '[') {
-
			obj = ucl_add_parser_stack (NULL, parser, true, 0);
-
		}
-
		else {
-
			obj = ucl_add_parser_stack (NULL, parser, false, 0);
-
		}
-
		if (obj == NULL) {
-
			return false;
-
		}
-
		parser->top_obj = obj;
-
		parser->cur_obj = obj;
		parser->state = UCL_STATE_INIT;
	}

@@ -1939,7 +1987,9 @@ ucl_state_machine (struct ucl_parser *parser)
						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
					ucl_chunk_skipc (chunk, p);
				}
+

				p = chunk->pos;
+

				if (*p == '[') {
					parser->state = UCL_STATE_VALUE;
					ucl_chunk_skipc (chunk, p);
@@ -1950,6 +2000,23 @@ ucl_state_machine (struct ucl_parser *parser)
						ucl_chunk_skipc (chunk, p);
					}
				}
+

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

+
					if (obj == NULL) {
+
						return false;
+
					}
+

+
					parser->top_obj = obj;
+
					parser->cur_obj = obj;
+
				}
+

			}
			break;
		case UCL_STATE_KEY:
@@ -1983,7 +2050,7 @@ 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_add_parser_stack (parser->cur_obj, parser, false,
+
					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
							parser->stack->level + 1);
					if (obj == NULL) {
						return false;
@@ -2035,20 +2102,36 @@ ucl_state_machine (struct ucl_parser *parser)
					*p != '(') {
				ucl_chunk_skipc (chunk, p);
			}
-
			else if (p - c > 0) {
-
				/* We got macro name */
-
				macro_len = (size_t)(p - c);
-
				HASH_FIND (hh, parser->macroes, c, macro_len, macro);
-
				if (macro == NULL) {
-
					ucl_create_err (&parser->err, "error on line %d at column %d: "
-
							"unknown macro: '%.*s', character: '%c'",
-
								chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
+
			else {
+
				if (p - c > 0) {
+
					/* We got macro name */
+
					macro_len = (size_t) (p - c);
+
					HASH_FIND (hh, parser->macroes, c, macro_len, macro);
+
					if (macro == NULL) {
+
						ucl_create_err (&parser->err,
+
								"error on line %d at column %d: "
+
										"unknown macro: '%.*s', character: '%c'",
+
								chunk->line,
+
								chunk->column,
+
								(int) (p - c),
+
								c,
+
								*chunk->pos);
+
						parser->state = UCL_STATE_ERROR;
+
						return false;
+
					}
+
					/* Now we need to skip all spaces */
+
					SKIP_SPACES_COMMENTS(parser, chunk, p);
+
					parser->state = UCL_STATE_MACRO;
+
				}
+
				else {
+
					/* We have invalid macro name */
+
					ucl_create_err (&parser->err,
+
							"error on line %d at column %d: invalid macro name",
+
							chunk->line,
+
							chunk->column);
					parser->state = UCL_STATE_ERROR;
					return false;
				}
-
				/* Now we need to skip all spaces */
-
				SKIP_SPACES_COMMENTS(parser, chunk, p);
-
				parser->state = UCL_STATE_MACRO;
			}
			break;
		case UCL_STATE_MACRO:
@@ -2270,8 +2353,9 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser,
}

bool
-
ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data,
-
		size_t len, unsigned priority)
+
ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
+
		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
+
		enum ucl_parse_type parse_type)
{
	struct ucl_chunk *chunk;

@@ -2300,14 +2384,24 @@ ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *d
		chunk->line = 1;
		chunk->column = 0;
		chunk->priority = priority;
+
		chunk->strategy = strat;
+
		chunk->parse_type = parse_type;
		LL_PREPEND (parser->chunks, chunk);
		parser->recursion ++;
+

		if (parser->recursion > UCL_MAX_RECURSION) {
			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
					parser->recursion);
			return false;
		}
-
		return ucl_state_machine (parser);
+

+
		switch (parse_type) {
+
		default:
+
		case UCL_PARSE_UCL:
+
			return ucl_state_machine (parser);
+
		case UCL_PARSE_MSGPACK:
+
			return ucl_parse_msgpack (parser);
+
		}
	}

	ucl_create_err (&parser->err, "a parser is in an invalid state");
@@ -2316,6 +2410,19 @@ ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *d
}

bool
+
ucl_parser_add_chunk_priority (struct ucl_parser *parser,
+
		const unsigned char *data, size_t len, unsigned priority)
+
{
+
	/* We dereference parser, so this check is essential */
+
	if (parser == NULL) {
+
		return false;
+
	}
+

+
	return ucl_parser_add_chunk_full (parser, data, len,
+
				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
+
}
+

+
bool
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
		size_t len)
{
@@ -2323,8 +2430,8 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
		return false;
	}

-
	return ucl_parser_add_chunk_priority (parser, data, len,
-
			parser->default_priority);
+
	return ucl_parser_add_chunk_full (parser, data, len,
+
			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
}

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

+
#ifdef HAVE_CONFIG_H
+
#include "config.h"
+
#endif
+

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

+
#define NEXT_STATE do {            \
+
if (p >= end) {                    \
+
    if (state != read_ebrace) {    \
+
      ucl_create_err (&parser->err,\
+
                     "extra data");\
+
      state = parse_err;           \
+
    }                              \
+
}                                  \
+
else {                             \
+
switch (*p) {                      \
+
    case '(':                      \
+
        state = read_obrace;       \
+
        break;                     \
+
    case ')':                      \
+
        state = read_ebrace;       \
+
        break;                     \
+
    default:                       \
+
        len = 0;                   \
+
        mult = 1;                  \
+
        state = read_length;       \
+
        break;                     \
+
    }                              \
+
}                                  \
+
} while(0)
+

+
bool
+
ucl_parse_csexp (struct ucl_parser *parser)
+
{
+
	const unsigned char *p, *end;
+
	ucl_object_t *obj;
+
	struct ucl_stack *st;
+
	uint64_t len = 0, mult = 1;
+
	enum {
+
		start_parse,
+
		read_obrace,
+
		read_length,
+
		read_value,
+
		read_ebrace,
+
		parse_err
+
	} state = start_parse;
+

+
	assert (parser != NULL);
+
	assert (parser->chunks != NULL);
+
	assert (parser->chunks->begin != NULL);
+
	assert (parser->chunks->remain != 0);
+

+
	p = parser->chunks->begin;
+
	end = p + parser->chunks->remain;
+

+
	while (p < end) {
+
		switch (state) {
+
		case start_parse:
+
			/* At this point we expect open brace */
+
			if (*p == '(') {
+
				state = read_obrace;
+
			}
+
			else {
+
				ucl_create_err (&parser->err, "bad starting character for "
+
						"sexp block: %x", (int)*p);
+
				state = parse_err;
+
			}
+
			break;
+

+
		case read_obrace:
+
			st = calloc (1, sizeof (*st));
+

+
			if (st == NULL) {
+
				ucl_create_err (&parser->err, "no memory");
+
				state = parse_err;
+
				continue;
+
			}
+

+
			st->obj = ucl_object_typed_new (UCL_ARRAY);
+

+
			if (st->obj == NULL) {
+
				ucl_create_err (&parser->err, "no memory");
+
				state = parse_err;
+
				continue;
+
			}
+

+
			if (parser->stack == NULL) {
+
				/* We have no stack */
+
				parser->stack = st;
+

+
				if (parser->top_obj == NULL) {
+
					parser->top_obj = st->obj;
+
				}
+
			}
+
			else {
+
				/* Prepend new element to the stack */
+
				LL_PREPEND (parser->stack, st);
+
			}
+

+
			p ++;
+
			NEXT_STATE;
+

+
			break;
+

+
		case read_length:
+
			if (*p == ':') {
+
				if (len == 0) {
+
					ucl_create_err (&parser->err, "zero length element");
+
					state = parse_err;
+
					continue;
+
				}
+

+
				state = read_value;
+
			}
+
			else if (*p >= '0' && *p <= '9') {
+
				len += (*p - '0') * mult;
+
				mult *= 10;
+

+
				if (len > UINT32_MAX) {
+
					ucl_create_err (&parser->err, "too big length of an "
+
									"element");
+
					state = parse_err;
+
					continue;
+
				}
+
			}
+
			else {
+
				ucl_create_err (&parser->err, "bad length character: %x",
+
						(int)*p);
+
				state = parse_err;
+
				continue;
+
			}
+

+
			p ++;
+
			break;
+

+
		case read_value:
+
			if ((uint64_t)(end - p) > len || len == 0) {
+
				ucl_create_err (&parser->err, "invalid length: %llu, %ld "
+
						"remain", (long long unsigned)len, (long)(end - p));
+
				state = parse_err;
+
				continue;
+
			}
+
			obj = ucl_object_typed_new (UCL_STRING);
+

+
			obj->value.sv = (const char*)p;
+
			obj->len = len;
+
			obj->flags |= UCL_OBJECT_BINARY;
+

+
			if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
+
				ucl_copy_value_trash (obj);
+
			}
+

+
			ucl_array_append (parser->stack->obj, obj);
+
			p += len;
+
			NEXT_STATE;
+
			break;
+

+
		case read_ebrace:
+
			if (parser->stack == NULL) {
+
				/* We have an extra end brace */
+
				ucl_create_err (&parser->err, "invalid length: %llu, %ld "
+
						"remain", (long long unsigned)len, (long)(end - p));
+
				state = parse_err;
+
				continue;
+
			}
+
			/* Pop the container */
+
			st = parser->stack;
+
			parser->stack = st->next;
+

+
			if (parser->stack->obj->type == UCL_ARRAY) {
+
				ucl_array_append (parser->stack->obj, st->obj);
+
			}
+
			else {
+
				ucl_create_err (&parser->err, "bad container object, array "
+
						"expected");
+
				state = parse_err;
+
				continue;
+
			}
+

+
			free (st);
+
			p++;
+
			NEXT_STATE;
+
			break;
+

+
		case parse_err:
+
		default:
+
			return false;
+
		}
+
	}
+

+
	if (state != read_ebrace) {
+
		ucl_create_err (&parser->err, "invalid finishing state: %d", state);
+
		return false;
+
	}
+

+
	return true;
+
}

\ No newline at end of file
modified external/libucl/src/ucl_util.c
@@ -410,11 +410,24 @@ ucl_copy_value_trash (const ucl_object_t *obj)
		if (obj->type == UCL_STRING) {

			/* Special case for strings */
-
			deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
-
			if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
-
				memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
-
				deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
-
				deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
+
			if (obj->flags & UCL_OBJECT_BINARY) {
+
				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len);
+
				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
+
					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
+
							obj->value.sv,
+
							obj->len);
+
					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
+
				}
+
			}
+
			else {
+
				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
+
				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
+
					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
+
							obj->value.sv,
+
							obj->len);
+
					deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
+
					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
+
				}
			}
		}
		else {
@@ -424,6 +437,7 @@ ucl_copy_value_trash (const ucl_object_t *obj)
		}
		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
	}
+
	
	return obj->trash_stack[UCL_TRASH_VALUE];
}

@@ -796,6 +810,20 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
}
#endif

+
struct ucl_include_params {
+
	bool check_signature;
+
	bool must_exist;
+
	bool use_glob;
+
	bool use_prefix;
+
	bool soft_fail;
+
	bool allow_glob;
+
	unsigned priority;
+
	enum ucl_duplicate_strategy strat;
+
	enum ucl_parse_type parse_type;
+
	const char *prefix;
+
	const char *target;
+
};
+

/**
 * Include an url to configuration
 * @param data
@@ -806,8 +834,8 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
 */
static bool
ucl_include_url (const unsigned char *data, size_t len,
-
		struct ucl_parser *parser, bool check_signature, bool must_exist,
-
		bool use_prefix, const char *prefix, const char *target, unsigned priority)
+
		struct ucl_parser *parser,
+
		struct ucl_include_params *params)
{

	bool res;
@@ -819,11 +847,11 @@ ucl_include_url (const unsigned char *data, size_t len,

	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);

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

-
	if (check_signature) {
+
	if (params->check_signature) {
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
		unsigned char *sigbuf = NULL;
		size_t siglen = 0;
@@ -850,7 +878,8 @@ ucl_include_url (const unsigned char *data, size_t len,
	prev_state = parser->state;
	parser->state = UCL_STATE_INIT;

-
	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
+
	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
+
			params->strat, params->parse_type);
	if (res == true) {
		/* Remove chunk from the stack */
		chunk = parser->chunks;
@@ -879,9 +908,7 @@ ucl_include_url (const unsigned char *data, size_t len,
 */
static bool
ucl_include_file_single (const unsigned char *data, size_t len,
-
		struct ucl_parser *parser, bool check_signature, bool must_exist,
-
		bool use_prefix, const char *prefix, const char *target,
-
		bool soft_fail, unsigned priority)
+
		struct ucl_parser *parser, struct ucl_include_params *params)
{
	bool res;
	struct ucl_chunk *chunk;
@@ -898,10 +925,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,

	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
	if (ucl_realpath (filebuf, realbuf) == NULL) {
-
		if (soft_fail) {
+
		if (params->soft_fail) {
			return false;
		}
-
		if (!must_exist) {
+
		if (!params->must_exist) {
			return true;
		}
		ucl_create_err (&parser->err, "cannot open file %s: %s",
@@ -912,22 +939,23 @@ ucl_include_file_single (const unsigned char *data, size_t len,

	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
		/* We are likely including the file itself */
-
		if (soft_fail) {
+
		if (params->soft_fail) {
			return false;
		}
+

		ucl_create_err (&parser->err, "trying to include the file %s from itself",
				realbuf);
		return false;
	}

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

-
	if (check_signature) {
+
	if (params->check_signature) {
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
		unsigned char *sigbuf = NULL;
		size_t siglen = 0;
@@ -971,26 +999,27 @@ ucl_include_file_single (const unsigned char *data, size_t len,
	prev_state = parser->state;
	parser->state = UCL_STATE_INIT;

-
	if (use_prefix && prefix == NULL) {
+
	if (params->use_prefix && params->prefix == NULL) {
		/* Auto generate a key name based on the included filename */
-
		prefix = basename (realbuf);
-
		ext = strrchr(prefix, '.');
+
		params->prefix = basename (realbuf);
+
		ext = strrchr (params->prefix, '.');
		if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) {
			/* Strip off .conf or .ucl */
			*ext = '\0';
		}
	}
-
	if (prefix != NULL) {
+
	if (params->prefix != NULL) {
		/* This is a prefixed include */
		container = parser->stack->obj->value.ov;

-
		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix)));
+
		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
+
				params->prefix, strlen (params->prefix)));

-
		if (strcasecmp (target, "array") == 0 && old_obj == NULL) {
+
		if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) {
			/* Create an array with key: prefix */
-
			old_obj = ucl_object_new_full (UCL_ARRAY, priority);
-
			old_obj->key = prefix;
-
			old_obj->keylen = strlen (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;
@@ -999,7 +1028,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
					parser->flags & UCL_PARSER_KEY_LOWERCASE);
			parser->stack->obj->len ++;

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

@@ -1007,9 +1036,9 @@ ucl_include_file_single (const unsigned char *data, size_t len,
		}
		else if (old_obj == NULL) {
			/* Create an object with key: prefix */
-
			nest_obj = ucl_object_new_full (UCL_OBJECT, priority);
-
			nest_obj->key = prefix;
-
			nest_obj->keylen = strlen (prefix);
+
			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
			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;
@@ -1018,10 +1047,11 @@ ucl_include_file_single (const unsigned char *data, size_t len,
					parser->flags & UCL_PARSER_KEY_LOWERCASE);
			parser->stack->obj->len ++;
		}
-
		else if (strcasecmp (target, "array") == 0 || ucl_object_type(old_obj) == UCL_ARRAY) {
+
		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 */
-
				nest_obj = ucl_object_new_full (UCL_OBJECT, priority);
+
				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
				nest_obj->prev = nest_obj;
				nest_obj->next = NULL;

@@ -1036,7 +1066,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
				new_obj->prev = new_obj;
				new_obj->next = NULL;

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

@@ -1054,7 +1084,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
				/* The key is not an object */
				ucl_create_err (&parser->err,
						"Conflicting type for key: %s",
-
						prefix);
+
						params->prefix);
				return false;
			}
		}
@@ -1076,8 +1106,9 @@ ucl_include_file_single (const unsigned char *data, size_t len,
		}
	}

-
	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
-
	if (!res && !must_exist) {
+
	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
+
			params->strat, params->parse_type);
+
	if (!res && !params->must_exist) {
		/* Free error */
		utstring_free (parser->err);
		parser->err = NULL;
@@ -1085,7 +1116,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
	}

	/* Stop nesting the include, take 1 level off the stack */
-
	if (prefix != NULL && nest_obj != NULL) {
+
	if (params->prefix != NULL && nest_obj != NULL) {
		parser->stack = st->next;
		UCL_FREE (sizeof (struct ucl_stack), st);
	}
@@ -1144,9 +1175,7 @@ ucl_include_file_single (const unsigned char *data, size_t len,
 */
static bool
ucl_include_file (const unsigned char *data, size_t len,
-
		struct ucl_parser *parser, bool check_signature, bool must_exist,
-
		bool allow_glob, bool use_prefix, const char *prefix,
-
		const char *target, bool soft_fail, unsigned priority)
+
		struct ucl_parser *parser, struct ucl_include_params *params)
{
	const unsigned char *p = data, *end = data + len;
	bool need_glob = false;
@@ -1155,9 +1184,8 @@ ucl_include_file (const unsigned char *data, size_t len,
	size_t i;

#ifndef _WIN32
-
	if (!allow_glob) {
-
		return ucl_include_file_single (data, len, parser, check_signature,
-
			must_exist, use_prefix, prefix, target, soft_fail, priority);
+
	if (!params->allow_glob) {
+
		return ucl_include_file_single (data, len, parser, params);
	}
	else {
		/* Check for special symbols in a filename */
@@ -1174,13 +1202,12 @@ ucl_include_file (const unsigned char *data, size_t len,
			ucl_strlcpy (glob_pattern, (const char *)data,
				(len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern)));
			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
-
				return (!must_exist || false);
+
				return (!params->must_exist || false);
			}
			for (i = 0; i < globbuf.gl_pathc; i ++) {
				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
-
						strlen (globbuf.gl_pathv[i]), parser, check_signature,
-
						must_exist, use_prefix, prefix, target, soft_fail, priority)) {
-
					if (soft_fail) {
+
						strlen (globbuf.gl_pathv[i]), parser, params)) {
+
					if (params->soft_fail) {
						continue;
					}
					globfree (&globbuf);
@@ -1190,22 +1217,20 @@ ucl_include_file (const unsigned char *data, size_t len,
			}
			globfree (&globbuf);

-
			if (cnt == 0 && must_exist) {
+
			if (cnt == 0 && params->must_exist) {
				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
					glob_pattern);
				return false;
			}
		}
		else {
-
			return ucl_include_file_single (data, len, parser, check_signature,
-
				must_exist, use_prefix, prefix, target, soft_fail, priority);
+
			return ucl_include_file_single (data, len, parser, params);
		}
	}
#else
	/* Win32 compilers do not support globbing. Therefore, for Win32,
	   treat allow_glob/need_glob as a NOOP and just return */
-
	return ucl_include_file_single (data, len, parser, check_signature,
-
		must_exist, use_prefix, prefix, target, soft_fail, priority);
+
	return ucl_include_file_single (data, len, parser, params);
#endif
	
	return true;
@@ -1227,22 +1252,25 @@ ucl_include_common (const unsigned char *data, size_t len,
		bool default_try,
		bool default_sign)
{
-
	bool try_load, allow_glob, allow_url, need_sign, use_prefix, search;
-
	const char *prefix, *target;
-
	unsigned priority;
+
	bool allow_url, search;
+
	const char *duplicate;
	const ucl_object_t *param;
	ucl_object_iter_t it = NULL, ip = NULL;
	char ipath[PATH_MAX];
+
	struct ucl_include_params params;

	/* Default values */
-
	try_load = default_try;
-
	allow_glob = false;
-
	allow_url = true;
-
	need_sign = default_sign;
-
	use_prefix = false;
-
	prefix = NULL;
-
	target = "object";
-
	priority = 0;
+
	params.soft_fail = default_try;
+
	params.allow_glob = false;
+
	params.check_signature = default_sign;
+
	params.use_prefix = false;
+
	params.target = "object";
+
	params.prefix = NULL;
+
	params.priority = 0;
+
	params.parse_type = UCL_PARSE_UCL;
+
	params.strat = UCL_DUPLICATE_APPEND;
+
	params.must_exist = !default_try;
+

	search = false;

	/* Process arguments */
@@ -1250,27 +1278,43 @@ ucl_include_common (const unsigned char *data, size_t len,
		while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
			if (param->type == UCL_BOOLEAN) {
				if (strncmp (param->key, "try", param->keylen) == 0) {
-
					try_load = ucl_object_toboolean (param);
+
					params.must_exist = !ucl_object_toboolean (param);
				}
				else if (strncmp (param->key, "sign", param->keylen) == 0) {
-
					need_sign = ucl_object_toboolean (param);
+
					params.check_signature = ucl_object_toboolean (param);
				}
				else if (strncmp (param->key, "glob", param->keylen) == 0) {
-
					allow_glob = ucl_object_toboolean (param);
+
					params.allow_glob = ucl_object_toboolean (param);
				}
				else if (strncmp (param->key, "url", param->keylen) == 0) {
					allow_url = ucl_object_toboolean (param);
				}
				else if (strncmp (param->key, "prefix", param->keylen) == 0) {
-
					use_prefix = ucl_object_toboolean (param);
+
					params.use_prefix = ucl_object_toboolean (param);
				}
			}
			else if (param->type == UCL_STRING) {
				if (strncmp (param->key, "key", param->keylen) == 0) {
-
					prefix = ucl_object_tostring (param);
+
					params.prefix = ucl_object_tostring (param);
				}
				else if (strncmp (param->key, "target", param->keylen) == 0) {
-
					target = ucl_object_tostring (param);
+
					params.target = ucl_object_tostring (param);
+
				}
+
				else if (strncmp (param->key, "duplicate", param->keylen) == 0) {
+
					duplicate = ucl_object_tostring (param);
+

+
					if (strcmp (duplicate, "append") == 0) {
+
						params.strat = UCL_DUPLICATE_APPEND;
+
					}
+
					else if (strcmp (duplicate, "merge") == 0) {
+
						params.strat = UCL_DUPLICATE_MERGE;
+
					}
+
					else if (strcmp (duplicate, "rewrite") == 0) {
+
						params.strat = UCL_DUPLICATE_REWRITE;
+
					}
+
					else if (strcmp (duplicate, "error") == 0) {
+
						params.strat = UCL_DUPLICATE_ERROR;
+
					}
				}
			}
			else if (param->type == UCL_ARRAY) {
@@ -1280,7 +1324,7 @@ ucl_include_common (const unsigned char *data, size_t len,
			}
			else if (param->type == UCL_INT) {
				if (strncmp (param->key, "priority", param->keylen) == 0) {
-
					priority = ucl_object_toint (param);
+
					params.priority = ucl_object_toint (param);
				}
			}
		}
@@ -1289,20 +1333,17 @@ ucl_include_common (const unsigned char *data, size_t len,
	if (parser->includepaths == NULL) {
		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
			/* Globbing is not used for URL's */
-
			return ucl_include_url (data, len, parser, need_sign,
-
					!try_load, use_prefix, prefix, target, priority);
+
			return ucl_include_url (data, len, parser, &params);
		}
		else if (data != NULL) {
			/* Try to load a file */
-
			return ucl_include_file (data, len, parser, need_sign, !try_load,
-
					allow_glob, use_prefix, prefix, target, false, priority);
+
			return ucl_include_file (data, len, parser, &params);
		}
	}
	else {
		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
			/* Globbing is not used for URL's */
-
			return ucl_include_url (data, len, parser, need_sign,
-
					!try_load, use_prefix, prefix, target, priority);
+
			return ucl_include_url (data, len, parser, &params);
		}

		ip = ucl_object_iterate_new (parser->includepaths);
@@ -1310,9 +1351,9 @@ ucl_include_common (const unsigned char *data, size_t len,
			if (ucl_object_type(param) == UCL_STRING) {
				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
						(int)len, data);
-
				if ((search = ucl_include_file (ipath, strlen (ipath), parser, need_sign,
-
						!try_load, allow_glob, use_prefix, prefix, target, true, priority))) {
-
					if (!allow_glob) {
+
				if ((search = ucl_include_file (ipath, strlen (ipath),
+
						parser, &params))) {
+
					if (!params.allow_glob) {
						break;
					}
				}
@@ -2903,7 +2944,9 @@ ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)

	switch (obj->type) {
	case UCL_STRING:
-
		*target = ucl_copy_value_trash (obj);
+
		if (!(obj->flags & UCL_OBJECT_BINARY)) {
+
			*target = ucl_copy_value_trash (obj);
+
		}
		break;
	default:
		return false;
@@ -2924,7 +2967,12 @@ ucl_object_tostring (const ucl_object_t *obj)
const char *
ucl_object_tostring_forced (const ucl_object_t *obj)
{
-
	return ucl_copy_value_trash (obj);
+
	/* TODO: For binary strings we might encode string here */
+
	if (!(obj->flags & UCL_OBJECT_BINARY)) {
+
		return ucl_copy_value_trash (obj);
+
	}
+

+
	return NULL;
}

bool
@@ -3171,7 +3219,7 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)

void
ucl_object_array_sort (ucl_object_t *ar,
-
		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
+
		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
{
	UCL_ARRAY_GET (vec, ar);

modified external/libucl/tests/Makefile.am
@@ -1,10 +1,12 @@
-
EXTRA_DIST = $(TESTS) basic schema generate.res streamline.res rcl_test.json.xz
+
EXTRA_DIST = $(TESTS) basic schema generate.res \
+
	streamline.res rcl_test.json.xz

TESTS = basic.test \
		generate.test \
		schema.test \
+
		msgpack.test \
		speed.test \
-
		streamline.test
+
		msgpack.test
TESTS_ENVIRONMENT = $(SH) \
			TEST_DIR=$(top_srcdir)/tests \
			TEST_OUT_DIR=$(top_builddir)/tests \
@@ -35,4 +37,9 @@ test_streamline_SOURCES = test_streamline.c
test_streamline_LDADD = $(common_test_ldadd)
test_streamline_CFLAGS = $(common_test_cflags)

-
check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline

\ No newline at end of file
+
test_msgpack_SOURCES = test_msgpack.c
+
test_msgpack_LDADD = $(common_test_ldadd)
+
test_msgpack_CFLAGS = $(common_test_cflags)
+

+
check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline \
+
	test_msgpack

\ No newline at end of file
modified external/libucl/tests/test_schema.c
@@ -40,20 +40,24 @@ read_stdin (char **buf)
	p = *buf;
	remain = size;

-
	while ((ret = read (STDIN_FILENO, p, remain)) > 0) {
+
	while ((ret = read (STDIN_FILENO, p, remain - 1)) > 0) {
		remain -= ret;
		p += ret;
-
		if (remain == 0) {
+

+
		if (remain <= 1) {
			*buf = realloc (*buf, size * 2);
			if (*buf == NULL) {
				return -1;
			}
-
			p = *buf + size;
-
			remain = size;
+

+
			p = *buf + size - 1;
+
			remain = size + 1;
			size *= 2;
		}
	}

+
	*p = '\0';
+

	return ret;
}

modified external/libucl/utils/chargen.c
@@ -54,9 +54,9 @@ main (int argc, char **argv)
		name = argv[1];
	}

-
	printf ("static const unsigned int %s[255] = {\n", name);
+
	printf ("static const unsigned int %s[256] = {\n", name);

-
	for (i = 0; i < 255; i ++) {
+
	for (i = 0; i < 256; i ++) {
		need_or = false;
		r = 0;
		/* UCL_CHARACTER_VALUE_END */
@@ -110,7 +110,7 @@ main (int argc, char **argv)
		if (isprint (i)) {
			r += sprintf (valbuf + r, " /* %c */", i);
		}
-
		if (i != 254) {
+
		if (i != 255) {
			r += sprintf (valbuf + r, ", ");
		}
		col += r;