Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Import libucl
Baptiste Daroussin committed 12 years ago
commit f30c8095c2bfb86a3dfe0e7c23f65ac1cba3dc45
parent db7d150
8 files changed +3271 -1
modified external/Makefile
@@ -1,4 +1,4 @@
-
SUBDIR=	sqlite libyaml expat
+
SUBDIR=	sqlite libyaml expat libucl

.if defined(WITH_BUNDLED_LIBELF)
SUBDIR+= libelf
added external/libucl/Makefile
@@ -0,0 +1,14 @@
+
LIB=	ucl
+
INTERNALLIB=
+

+
SRCS=	src/ucl_emitter.c \
+
	src/ucl_parser.c \
+
	src/ucl_util.c \
+

+
CFLAGS=	-I${.CURDIR}/../uthash \
+
	-I${.CURDIR}/include \
+
	-I${.CURDIR}/src \
+
	-fPIC
+

+
WARNS=	1
+
.include <bsd.lib.mk>
added external/libucl/include/ucl.h
@@ -0,0 +1,413 @@
+
/* Copyright (c) 2013, 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 ''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.
+
 */
+

+
#ifndef RCL_H_
+
#define RCL_H_
+

+
#include <string.h>
+
#include <stddef.h>
+
#include <stdlib.h>
+
#include <stdint.h>
+
#include <stdbool.h>
+
#include <stdarg.h>
+
#include <stdio.h>
+

+
#include "uthash.h"
+
#include "utstring.h"
+

+
/**
+
 * Memory allocation utilities
+
 * UCL_ALLOC(size) - allocate memory for UCL
+
 * UCL_FREE(size, ptr) - free memory of specified size at ptr
+
 * Default: malloc and free
+
 */
+
#ifndef UCL_ALLOC
+
#define UCL_ALLOC(size) malloc(size)
+
#endif
+
#ifndef UCL_FREE
+
#define UCL_FREE(size, ptr) free(ptr)
+
#endif
+

+
/**
+
 * @file rcl.h
+
 * RCL is an rspamd configuration language, which is a form of
+
 * JSON with less strict rules that make it more comfortable for
+
 * using as a configuration language
+
 */
+

+
enum ucl_error {
+
	UCL_EOK = 0,   //!< UCL_EOK
+
	UCL_ESYNTAX,   //!< UCL_ESYNTAX
+
	UCL_EIO,       //!< UCL_EIO
+
	UCL_ESTATE,    //!< UCL_ESTATE
+
	UCL_ENESTED,   //!< UCL_ENESTED
+
	UCL_EMACRO,    //!< UCL_EMACRO
+
	UCL_ERECURSION,//!< UCL_ERECURSION
+
	UCL_EINTERNAL, //!< UCL_EINTERNAL
+
	UCL_ESSL       //!< UCL_ESSL
+
};
+

+
enum ucl_type {
+
	UCL_OBJECT = 0,
+
	UCL_ARRAY,
+
	UCL_INT,
+
	UCL_FLOAT,
+
	UCL_STRING,
+
	UCL_BOOLEAN,
+
	UCL_TIME,
+
	UCL_USERDATA
+
};
+

+
enum ucl_emitter {
+
	UCL_EMIT_JSON = 0,
+
	UCL_EMIT_JSON_COMPACT,
+
	UCL_EMIT_CONFIG
+
};
+

+
enum ucl_flags {
+
	UCL_FLAG_KEY_LOWERCASE = 0x1
+
};
+

+
typedef struct ucl_object_s {
+
	char *key;								/**< the key of an object */
+
	union {
+
		int64_t iv;							/**< int value of an object */
+
		char *sv;							/**< string value of an object */
+
		double dv;							/**< double value of an object */
+
		struct ucl_object_s *ov;		/**< array or hash 			*/
+
		void* ud;						/**< opaque user data		*/
+
	} value;
+
	enum ucl_type type;				/**< real type				*/
+
	int ref;								/**< reference count		*/
+
	struct ucl_object_s *next;		/**< array handle			*/
+
	UT_hash_handle hh;						/**< hash handle			*/
+
} ucl_object_t;
+

+

+
/**
+
 * Creates a new object
+
 * @return new object
+
 */
+
static inline ucl_object_t *
+
ucl_object_new (void)
+
{
+
	ucl_object_t *new;
+
	new = malloc (sizeof (ucl_object_t));
+
	if (new != NULL) {
+
		memset (new, 0, sizeof (ucl_object_t));
+
		new->ref = 1;
+
	}
+
	return new;
+
}
+

+

+
/**
+
 * Converts an object to double value
+
 * @param obj CL object
+
 * @param target target double variable
+
 * @return true if conversion was successful
+
 */
+
static inline bool
+
ucl_obj_todouble_safe (ucl_object_t *obj, double *target)
+
{
+
	if (obj == NULL) {
+
		return false;
+
	}
+
	switch (obj->type) {
+
	case UCL_INT:
+
		*target = obj->value.iv; /* Probaly could cause overflow */
+
		break;
+
	case UCL_FLOAT:
+
	case UCL_TIME:
+
		*target = obj->value.dv;
+
		break;
+
	default:
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Unsafe version of \ref ucl_obj_todouble_safe
+
 * @param obj CL object
+
 * @return double value
+
 */
+
static inline double
+
ucl_obj_todouble (ucl_object_t *obj)
+
{
+
	double result = 0.;
+

+
	ucl_obj_todouble_safe (obj, &result);
+
	return result;
+
}
+

+
/**
+
 * Converts an object to integer value
+
 * @param obj CL object
+
 * @param target target integer variable
+
 * @return true if conversion was successful
+
 */
+
static inline bool
+
ucl_obj_toint_safe (ucl_object_t *obj, int64_t *target)
+
{
+
	if (obj == NULL) {
+
		return false;
+
	}
+
	switch (obj->type) {
+
	case UCL_INT:
+
		*target = obj->value.iv;
+
		break;
+
	case UCL_FLOAT:
+
	case UCL_TIME:
+
		*target = obj->value.dv; /* Loosing of decimal points */
+
		break;
+
	default:
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Unsafe version of \ref ucl_obj_toint_safe
+
 * @param obj CL object
+
 * @return int value
+
 */
+
static inline int64_t
+
ucl_obj_toint (ucl_object_t *obj)
+
{
+
	int64_t result = 0;
+

+
	ucl_obj_toint_safe (obj, &result);
+
	return result;
+
}
+

+
/**
+
 * Converts an object to boolean value
+
 * @param obj CL object
+
 * @param target target boolean variable
+
 * @return true if conversion was successful
+
 */
+
static inline bool
+
ucl_obj_toboolean_safe (ucl_object_t *obj, bool *target)
+
{
+
	if (obj == NULL) {
+
		return false;
+
	}
+
	switch (obj->type) {
+
	case UCL_BOOLEAN:
+
		*target = (obj->value.iv == true);
+
		break;
+
	default:
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Unsafe version of \ref ucl_obj_toboolean_safe
+
 * @param obj CL object
+
 * @return boolean value
+
 */
+
static inline bool
+
ucl_obj_toboolean (ucl_object_t *obj)
+
{
+
	bool result = false;
+

+
	ucl_obj_toboolean_safe (obj, &result);
+
	return result;
+
}
+

+
/**
+
 * Converts an object to string value
+
 * @param obj CL object
+
 * @param target target string variable, no need to free value
+
 * @return true if conversion was successful
+
 */
+
static inline bool
+
ucl_obj_tostring_safe (ucl_object_t *obj, const char **target)
+
{
+
	if (obj == NULL) {
+
		return false;
+
	}
+
	switch (obj->type) {
+
	case UCL_STRING:
+
		*target = obj->value.sv;
+
		break;
+
	default:
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Unsafe version of \ref ucl_obj_tostring_safe
+
 * @param obj CL object
+
 * @return string value
+
 */
+
static inline const char *
+
ucl_obj_tostring (ucl_object_t *obj)
+
{
+
	const char *result = NULL;
+

+
	ucl_obj_tostring_safe (obj, &result);
+
	return result;
+
}
+

+
/**
+
 * Return object identified by a key in the specified object
+
 * @param obj object to get a key from (must be of type UCL_OBJECT)
+
 * @param key key to search
+
 * @return object matched the specified key or NULL if key is not found
+
 */
+
static inline ucl_object_t *
+
ucl_obj_get_key (ucl_object_t *obj, const char *key)
+
{
+
	size_t keylen;
+
	ucl_object_t *ret;
+

+
	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
+
		return NULL;
+
	}
+

+
	keylen = strlen (key);
+
	HASH_FIND(hh, obj->value.ov, key, keylen, ret);
+

+
	return ret;
+
}
+

+
/**
+
 * Macro handler for a parser
+
 * @param data the content of macro
+
 * @param len the length of content
+
 * @param ud opaque user data
+
 * @param err error pointer
+
 * @return true if macro has been parsed
+
 */
+
typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud, UT_string **err);
+

+
/* Opaque parser */
+
struct ucl_parser;
+

+
/**
+
 * Creates new parser object
+
 * @param pool pool to allocate memory from
+
 * @return new parser object
+
 */
+
struct ucl_parser* ucl_parser_new (int flags);
+

+
/**
+
 * Register new handler for a macro
+
 * @param parser parser object
+
 * @param macro macro name (without leading dot)
+
 * @param handler handler (it is called immediately after macro is parsed)
+
 * @param ud opaque user data for a handler
+
 */
+
void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
+
		ucl_macro_handler handler, void* ud);
+

+
/**
+
 * Load new chunk to a parser
+
 * @param parser parser structure
+
 * @param data the pointer to the beginning of a chunk
+
 * @param len the length of a chunk
+
 * @param err if *err is NULL it is set to parser error
+
 * @return true if chunk has been added and false in case of error
+
 */
+
bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
+
		size_t len, UT_string **err);
+

+
/**
+
 * Load and add data from a file
+
 * @param parser parser structure
+
 * @param filename the name of file
+
 * @param err if *err is NULL it is set to parser error
+
 * @return true if chunk has been added and false in case of error
+
 */
+
bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename,
+
		UT_string **err);
+

+
/**
+
 * Get a top object for a parser
+
 * @param parser parser structure
+
 * @param err if *err is NULL it is set to parser error
+
 * @return top parser object or NULL
+
 */
+
ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser, UT_string **err);
+

+
/**
+
 * Free cl parser object
+
 * @param parser parser object
+
 */
+
void ucl_parser_free (struct ucl_parser *parser);
+

+
/**
+
 * Free cl object
+
 * @param obj cl object to free
+
 */
+
void ucl_obj_free (ucl_object_t *obj);
+

+
/**
+
 * Icrease reference count for an object
+
 * @param obj object to ref
+
 */
+
static inline ucl_object_t *
+
ucl_obj_ref (ucl_object_t *obj) {
+
	obj->ref ++;
+
	return obj;
+
}
+

+
/**
+
 * Decrease reference count for an object
+
 * @param obj object to unref
+
 */
+
static inline void
+
ucl_obj_unref (ucl_object_t *obj) {
+
	if (--obj->ref <= 0) {
+
		ucl_obj_free (obj);
+
	}
+
}
+

+
/**
+
 * Emit object to a string
+
 * @param obj object
+
 * @param emit_type if type is UCL_EMIT_JSON then emit json, if type is
+
 * UCL_EMIT_CONFIG then emit config like object
+
 * @return dump of an object (must be freed after using) or NULL in case of error
+
 */
+
unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
+

+
/**
+
 * Add new public key to parser for signatures check
+
 * @param parser parser object
+
 * @param key PEM representation of a key
+
 * @param len length of the key
+
 * @param err if *err is NULL it is set to parser error
+
 * @return true if a key has been successfully added
+
 */
+
bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err);
+

+
#endif /* RCL_H_ */
added external/libucl/src/ucl_chartable.h
@@ -0,0 +1,255 @@
+
/* Copyright (c) 2013, 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 ''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.
+
 */
+

+
#ifndef UCL_CHARTABLE_H_
+
#define UCL_CHARTABLE_H_
+

+
#include "ucl_internal.h"
+

+
static const unsigned char ucl_chartable[255] = {
+
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, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_WHITESPACE, UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_VALUE_END,
+
UCL_CHARACTER_WHITESPACE, UCL_CHARACTER_WHITESPACE,
+
UCL_CHARACTER_WHITESPACE|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,
+
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
+
UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_VALUE_STR /*   */,
+
UCL_CHARACTER_VALUE_STR /* ! */, UCL_CHARACTER_VALUE_STR /* " */,
+
UCL_CHARACTER_VALUE_END /* # */, UCL_CHARACTER_VALUE_STR /* $ */,
+
UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */,
+
UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */,
+
UCL_CHARACTER_VALUE_STR /* ) */, UCL_CHARACTER_VALUE_STR /* * */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* + */,
+
UCL_CHARACTER_VALUE_END /* , */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* - */,
+
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* . */,
+
UCL_CHARACTER_VALUE_STR /* / */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 0 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 1 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 2 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 3 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 4 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 5 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 6 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 7 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 8 */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 9 */,
+
UCL_CHARACTER_VALUE_STR /* : */, UCL_CHARACTER_VALUE_END /* ; */,
+
UCL_CHARACTER_VALUE_STR /* < */, UCL_CHARACTER_VALUE_STR /* = */,
+
UCL_CHARACTER_VALUE_STR /* > */, UCL_CHARACTER_VALUE_STR /* ? */,
+
UCL_CHARACTER_VALUE_STR /* @ */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* A */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* B */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* C */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* D */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* E */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* F */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* G */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* H */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* I */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* J */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* K */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* L */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* M */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* N */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* O */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* P */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Q */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* R */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* S */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* T */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* U */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* V */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* W */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* X */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Y */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Z */,
+
UCL_CHARACTER_VALUE_STR /* [ */, UCL_CHARACTER_VALUE_STR /* \ */,
+
UCL_CHARACTER_VALUE_END /* ] */, UCL_CHARACTER_VALUE_STR /* ^ */,
+
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR /* _ */,
+
UCL_CHARACTER_VALUE_STR /* ` */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* a */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* b */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* c */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* d */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* e */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* f */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* g */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* h */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* i */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* j */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* k */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* l */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* m */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* n */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* o */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* p */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* q */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* r */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* s */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* t */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* u */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* v */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* w */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* x */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* y */,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* z */,
+
UCL_CHARACTER_VALUE_STR /* { */, UCL_CHARACTER_VALUE_STR /* | */,
+
UCL_CHARACTER_VALUE_END /* } */, UCL_CHARACTER_VALUE_STR /* ~ */,
+
UCL_CHARACTER_DENIED,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
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,
+
UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR
+
};
+

+
#endif /* UCL_CHARTABLE_H_ */
added external/libucl/src/ucl_emitter.c
@@ -0,0 +1,444 @@
+
/* Copyright (c) 2013, 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 ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include "ucl.h"
+
#include "ucl_internal.h"
+

+
/**
+
 * @file rcl_emitter.c
+
 * Serialise RCL object to the RCL format
+
 */
+

+

+
static void ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact);
+
static void ucl_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact);
+
static void ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top);
+

+
/**
+
 * Add tabulation to the output buffer
+
 * @param buf target buffer
+
 * @param tabs number of tabs to add
+
 */
+
static inline void
+
ucl_add_tabs (UT_string *buf, unsigned int tabs, bool compact)
+
{
+
	while (!compact && tabs--) {
+
		utstring_append_len (buf, "    ", 4);
+
	}
+
}
+

+
/**
+
 * Serialise string
+
 * @param str string to emit
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_elt_string_write_json (const char *str, UT_string *buf)
+
{
+
	const char *p = str;
+

+
	utstring_append_c (buf, '"');
+
	while (*p != '\0') {
+
		switch (*p) {
+
		case '\n':
+
			utstring_append_len (buf, "\\n", 2);
+
			break;
+
		case '\r':
+
			utstring_append_len (buf, "\\r", 2);
+
			break;
+
		case '\b':
+
			utstring_append_len (buf, "\\b", 2);
+
			break;
+
		case '\t':
+
			utstring_append_len (buf, "\\t", 2);
+
			break;
+
		case '\f':
+
			utstring_append_len (buf, "\\f", 2);
+
			break;
+
		case '\\':
+
			utstring_append_len (buf, "\\\\", 2);
+
			break;
+
		case '"':
+
			utstring_append_len (buf, "\\\"", 2);
+
			break;
+
		default:
+
			utstring_append_c (buf, *p);
+
			break;
+
		}
+
		p ++;
+
	}
+
	utstring_append_c (buf, '"');
+
}
+

+
/**
+
 * Write a single object to the buffer
+
 * @param obj object to write
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
+
{
+
	ucl_object_t *cur, *tmp;
+

+
	if (start_tabs) {
+
		ucl_add_tabs (buf, tabs, compact);
+
	}
+
	if (compact) {
+
		utstring_append_c (buf, '{');
+
	}
+
	else {
+
		utstring_append_len (buf, "{\n", 2);
+
	}
+
	HASH_ITER (hh, obj, cur, tmp) {
+
		ucl_add_tabs (buf, tabs + 1, compact);
+
		ucl_elt_string_write_json (cur->key, buf);
+
		if (compact) {
+
			utstring_append_c (buf, ':');
+
		}
+
		else {
+
			utstring_append_len (buf, ": ", 2);
+
		}
+
		ucl_obj_write_json (cur, buf, tabs + 1, false, compact);
+
		if (cur->hh.next != NULL) {
+
			if (compact) {
+
				utstring_append_c (buf, ',');
+
			}
+
			else {
+
				utstring_append_len (buf, ",\n", 2);
+
			}
+
		}
+
		else if (!compact) {
+
			utstring_append_c (buf, '\n');
+
		}
+
	}
+
	ucl_add_tabs (buf, tabs, compact);
+
	utstring_append_c (buf, '}');
+
}
+

+
/**
+
 * Write a single array to the buffer
+
 * @param obj array to write
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_elt_array_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
+
{
+
	ucl_object_t *cur = obj;
+

+
	if (start_tabs) {
+
		ucl_add_tabs (buf, tabs, compact);
+
	}
+
	if (compact) {
+
		utstring_append_c (buf, '[');
+
	}
+
	else {
+
		utstring_append_len (buf, "[\n", 2);
+
	}
+
	while (cur) {
+
		ucl_elt_write_json (cur, buf, tabs + 1, true, compact);
+
		if (cur->next != NULL) {
+
			if (compact) {
+
				utstring_append_c (buf, ',');
+
			}
+
			else {
+
				utstring_append_len (buf, ",\n", 2);
+
			}
+
		}
+
		else if (!compact) {
+
			utstring_append_c (buf, '\n');
+
		}
+
		cur = cur->next;
+
	}
+
	ucl_add_tabs (buf, tabs, compact);
+
	utstring_append_c (buf, ']');
+
}
+

+
/**
+
 * Emit a single element
+
 * @param obj object
+
 * @param buf buffer
+
 */
+
static void
+
ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
+
{
+
	switch (obj->type) {
+
	case UCL_INT:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		utstring_printf (buf, "%ld", (long int)ucl_obj_toint (obj));
+
		break;
+
	case UCL_FLOAT:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		utstring_printf (buf, "%lf", ucl_obj_todouble (obj));
+
		break;
+
	case UCL_TIME:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		utstring_printf (buf, "%lf", ucl_obj_todouble (obj));
+
		break;
+
	case UCL_BOOLEAN:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		utstring_printf (buf, "%s", ucl_obj_toboolean (obj) ? "true" : "false");
+
		break;
+
	case UCL_STRING:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+
		ucl_elt_string_write_json (ucl_obj_tostring (obj), buf);
+
		break;
+
	case UCL_OBJECT:
+
		ucl_elt_obj_write_json (obj->value.ov, buf, tabs, start_tabs, compact);
+
		break;
+
	case UCL_ARRAY:
+
		ucl_elt_array_write_json (obj->value.ov, buf, tabs, start_tabs, compact);
+
		break;
+
	case UCL_USERDATA:
+
		break;
+
	}
+
}
+

+
/**
+
 * Write a single object to the buffer
+
 * @param obj object
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
+
{
+
	ucl_object_t *cur;
+
	bool is_array = (obj->next != NULL);
+

+
	if (is_array) {
+
		/* This is an array actually */
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, compact);
+
		}
+

+
		if (compact) {
+
			utstring_append_c (buf, '[');
+
		}
+
		else {
+
			utstring_append_len (buf, "[\n", 2);
+
		}
+
		cur = obj;
+
		while (cur != NULL) {
+
			ucl_elt_write_json (cur, buf, tabs + 1, true, compact);
+
			if (cur->next) {
+
				utstring_append_c (buf, ',');
+
			}
+
			if (!compact) {
+
				utstring_append_c (buf, '\n');
+
			}
+
			cur = cur->next;
+
		}
+
		ucl_add_tabs (buf, tabs, compact);
+
		utstring_append_c (buf, ']');
+
	}
+
	else {
+
		ucl_elt_write_json (obj, buf, tabs, start_tabs, compact);
+
	}
+

+
}
+

+
/**
+
 * Emit an object to json
+
 * @param obj object
+
 * @return json output (should be freed after using)
+
 */
+
static unsigned char *
+
ucl_object_emit_json (ucl_object_t *obj, bool compact)
+
{
+
	UT_string *buf;
+
	unsigned char *res;
+

+
	/* Allocate large enough buffer */
+
	utstring_new (buf);
+

+
	ucl_obj_write_json (obj, buf, 0, false, compact);
+

+
	res = utstring_body (buf);
+
	utstring_free (buf);
+

+
	return res;
+
}
+

+
/**
+
 * Write a single object to the buffer
+
 * @param obj object to write
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
+
{
+
	ucl_object_t *cur, *tmp;
+

+
	if (start_tabs) {
+
		ucl_add_tabs (buf, tabs, is_top);
+
	}
+
	if (!is_top) {
+
		utstring_append_len (buf, "{\n", 2);
+
	}
+

+
	while (obj) {
+
		HASH_ITER (hh, obj, cur, tmp) {
+
			ucl_add_tabs (buf, tabs + 1, is_top);
+
			utstring_append_len (buf, cur->key, strlen (cur->key));
+
			if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
+
				utstring_append_len (buf, " = ", 3);
+
			}
+
			else {
+
				utstring_append_c (buf, ' ');
+
			}
+
			ucl_elt_write_rcl (cur, buf, is_top ? tabs : tabs + 1, false, false);
+
			if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) {
+
				utstring_append_len (buf, ";\n", 2);
+
			}
+
			else {
+
				utstring_append_c (buf, '\n');
+
			}
+
		}
+
		obj = obj->next;
+
	}
+
	ucl_add_tabs (buf, tabs, is_top);
+
	if (!is_top) {
+
		utstring_append_c (buf, '}');
+
	}
+
}
+

+
/**
+
 * Write a single array to the buffer
+
 * @param obj array to write
+
 * @param buf target buffer
+
 */
+
static void
+
ucl_elt_array_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
+
{
+
	ucl_object_t *cur = obj;
+

+
	if (start_tabs) {
+
		ucl_add_tabs (buf, tabs, false);
+
	}
+

+
	utstring_append_len (buf, "[\n", 2);
+
	while (cur) {
+
		ucl_elt_write_rcl (cur, buf, tabs + 1, true, false);
+
		utstring_append_len (buf, ",\n", 2);
+
		cur = cur->next;
+
	}
+
	ucl_add_tabs (buf, tabs, false);
+
	utstring_append_c (buf, ']');
+
}
+

+
/**
+
 * Emit a single element
+
 * @param obj object
+
 * @param buf buffer
+
 */
+
static void
+
ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
+
{
+
	switch (obj->type) {
+
	case UCL_INT:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, false);
+
		}
+
		utstring_printf (buf, "%ld", (long int)ucl_obj_toint (obj));
+
		break;
+
	case UCL_FLOAT:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, false);
+
		}
+
		utstring_printf (buf, "%.4lf", ucl_obj_todouble (obj));
+
		break;
+
	case UCL_TIME:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, false);
+
		}
+
		utstring_printf (buf, "%.4lf", ucl_obj_todouble (obj));
+
		break;
+
	case UCL_BOOLEAN:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, false);
+
		}
+
		utstring_printf (buf, "%s", ucl_obj_toboolean (obj) ? "true" : "false");
+
		break;
+
	case UCL_STRING:
+
		if (start_tabs) {
+
			ucl_add_tabs (buf, tabs, false);
+
		}
+
		ucl_elt_string_write_json (ucl_obj_tostring (obj), buf);
+
		break;
+
	case UCL_OBJECT:
+
		ucl_elt_obj_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top);
+
		break;
+
	case UCL_ARRAY:
+
		ucl_elt_array_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top);
+
		break;
+
	case UCL_USERDATA:
+
		break;
+
	}
+
}
+

+
/**
+
 * Emit an object to rcl
+
 * @param obj object
+
 * @return rcl output (should be freed after using)
+
 */
+
static unsigned char *
+
ucl_object_emit_rcl (ucl_object_t *obj)
+
{
+
	UT_string *buf;
+
	unsigned char *res;
+

+
	/* Allocate large enough buffer */
+
	utstring_new (buf);
+

+
	ucl_elt_write_rcl (obj, buf, 0, false, true);
+

+
	res = utstring_body (buf);
+
	utstring_free (buf);
+

+
	return res;
+
}
+

+
unsigned char *
+
ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
+
{
+
	if (emit_type == UCL_EMIT_JSON) {
+
		return ucl_object_emit_json (obj, false);
+
	}
+
	else if (emit_type == UCL_EMIT_JSON_COMPACT) {
+
		return ucl_object_emit_json (obj, true);
+
	}
+
	else {
+
		return ucl_object_emit_rcl (obj);
+
	}
+

+
	return NULL;
+
}
added external/libucl/src/ucl_internal.h
@@ -0,0 +1,171 @@
+
/* Copyright (c) 2013, 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 ''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.
+
 */
+

+
#ifndef UCL_INTERNAL_H_
+
#define UCL_INTERNAL_H_
+

+
#include <sys/types.h>
+
#include <sys/mman.h>
+
#include <sys/stat.h>
+
#include <sys/param.h>
+

+
#include <limits.h>
+
#include <fcntl.h>
+
#include <errno.h>
+
#include <unistd.h>
+
#include <ctype.h>
+

+
#include "utlist.h"
+
#include "ucl.h"
+
#ifdef HAVE_OPENSSL
+
#include <openssl/evp.h>
+
#endif
+

+
/**
+
 * @file rcl_internal.h
+
 * Internal structures and functions of UCL library
+
 */
+

+
#define UCL_MAX_RECURSION 16
+

+
enum ucl_parser_state {
+
	UCL_STATE_INIT = 0,
+
	UCL_STATE_OBJECT,
+
	UCL_STATE_ARRAY,
+
	UCL_STATE_KEY,
+
	UCL_STATE_VALUE,
+
	UCL_STATE_AFTER_VALUE,
+
	UCL_STATE_ARRAY_VALUE,
+
	UCL_STATE_SCOMMENT,
+
	UCL_STATE_MCOMMENT,
+
	UCL_STATE_MACRO_NAME,
+
	UCL_STATE_MACRO,
+
	UCL_STATE_ERROR
+
};
+

+
enum ucl_character_type {
+
	UCL_CHARACTER_DENIED = 0,
+
	UCL_CHARACTER_KEY = 1,
+
	UCL_CHARACTER_KEY_START = 1 << 1,
+
	UCL_CHARACTER_WHITESPACE = 1 << 2,
+
	UCL_CHARACTER_VALUE_END = 1 << 3,
+
	UCL_CHARACTER_VALUE_STR = 1 << 4,
+
	UCL_CHARACTER_VALUE_DIGIT = 1 << 5,
+
	UCL_CHARACTER_VALUE_DIGIT_START = 1 << 6
+
};
+

+
struct ucl_macro {
+
	char *name;
+
	ucl_macro_handler handler;
+
	void* ud;
+
	UT_hash_handle hh;
+
};
+

+
struct ucl_stack {
+
	ucl_object_t *obj;
+
	struct ucl_stack *next;
+
};
+

+
struct ucl_chunk {
+
	const unsigned char *begin;
+
	const unsigned char *end;
+
	const unsigned char *pos;
+
	size_t remain;
+
	unsigned int line;
+
	unsigned int column;
+
	struct ucl_chunk *next;
+
};
+

+
#ifdef HAVE_OPENSSL
+
struct ucl_pubkey {
+
	EVP_PKEY *key;
+
	struct ucl_pubkey *next;
+
};
+
#else
+
struct ucl_pubkey {
+
	struct ucl_pubkey *next;
+
};
+
#endif
+

+
struct ucl_parser {
+
	enum ucl_parser_state state;
+
	enum ucl_parser_state prev_state;
+
	unsigned int recursion;
+
	int flags;
+
	ucl_object_t *top_obj;
+
	ucl_object_t *cur_obj;
+
	struct ucl_macro *macroes;
+
	struct ucl_stack *stack;
+
	struct ucl_chunk *chunks;
+
	struct ucl_pubkey *keys;
+
};
+

+
/**
+
 * Unescape json string inplace
+
 * @param str
+
 */
+
void ucl_unescape_json_string (char *str);
+

+
/**
+
 * Handle include macro
+
 * @param data include data
+
 * @param len length of data
+
 * @param ud user data
+
 * @param err error ptr
+
 * @return
+
 */
+
bool ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err);
+

+
/**
+
 * Handle includes macro
+
 * @param data include data
+
 * @param len length of data
+
 * @param ud user data
+
 * @param err error ptr
+
 * @return
+
 */
+
bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err);
+

+
size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
+
size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);
+

+
#ifdef __GNUC__
+
static inline void
+
ucl_create_err (UT_string **err, const char *fmt, ...)
+
__attribute__ (( format( printf, 2, 3) ));
+
#endif
+

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

+
{
+
	if (*err == NULL) {
+
		utstring_new (*err);
+
		va_list ap;
+
		va_start (ap, fmt);
+
		utstring_printf_va (*err, fmt, ap);
+
		va_end (ap);
+
	}
+
}
+

+
#endif /* UCL_INTERNAL_H_ */
added external/libucl/src/ucl_parser.c
@@ -0,0 +1,1309 @@
+
/* Copyright (c) 2013, 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 ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include "ucl.h"
+
#include "ucl_internal.h"
+
#include "ucl_chartable.h"
+

+
/**
+
 * @file rcl_parser.c
+
 * The implementation of rcl parser
+
 */
+

+
/**
+
 * Move up to len characters
+
 * @param parser
+
 * @param begin
+
 * @param len
+
 * @return new position in chunk
+
 */
+
static inline void
+
ucl_chunk_skipc (struct ucl_chunk *chunk, unsigned char c)
+
{
+
	if (c == '\n') {
+
		chunk->line ++;
+
		chunk->column = 0;
+
	}
+
	else {
+
		chunk->column ++;
+
	}
+

+
	chunk->pos ++;
+
	chunk->remain --;
+
}
+

+
static inline void
+
ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
+
{
+
	ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'",
+
			chunk->line, chunk->column, str, *chunk->pos);
+
}
+

+
static inline bool
+
ucl_test_character (unsigned char c, int type_flags)
+
{
+
	return (ucl_chartable[c] & type_flags) != 0;
+
}
+

+
static bool
+
ucl_skip_comments (struct ucl_parser *parser, UT_string **err)
+
{
+
	struct ucl_chunk *chunk = parser->chunks;
+
	const unsigned char *p;
+
	int comments_nested = 0;
+

+
	p = chunk->pos;
+

+
start:
+
	if (*p == '#') {
+
		if (parser->state != UCL_STATE_SCOMMENT &&
+
				parser->state != UCL_STATE_MCOMMENT) {
+
			while (p < chunk->end) {
+
				if (*p == '\n') {
+
					ucl_chunk_skipc (chunk, *++p);
+
					goto start;
+
				}
+
				ucl_chunk_skipc (chunk, *++p);
+
			}
+
		}
+
	}
+
	else if (*p == '/' && chunk->remain >= 2) {
+
		if (p[1] == '/' && parser->state != UCL_STATE_SCOMMENT &&
+
				parser->state != UCL_STATE_MCOMMENT) {
+
			ucl_chunk_skipc (chunk, *++p);
+
			chunk->pos = p;
+
			while (p < chunk->end) {
+
				if (*p == '\n') {
+
					ucl_chunk_skipc (chunk, *++p);
+
					goto start;
+
				}
+
				ucl_chunk_skipc (chunk, *++p);
+
			}
+
		}
+
		else if (p[1] == '*') {
+
			ucl_chunk_skipc (chunk, *++p);
+
			comments_nested ++;
+
			ucl_chunk_skipc (chunk, *++p);
+

+
			while (p < chunk->end) {
+
				if (*p == '*') {
+
					ucl_chunk_skipc (chunk, *++p);
+
					if (*p == '/') {
+
						comments_nested --;
+
						if (comments_nested == 0) {
+
							ucl_chunk_skipc (chunk, *++p);
+
							goto start;
+
						}
+
					}
+
					ucl_chunk_skipc (chunk, *++p);
+
				}
+
				else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
+
					comments_nested ++;
+
					ucl_chunk_skipc (chunk, *++p);
+
					ucl_chunk_skipc (chunk, *++p);
+
					continue;
+
				}
+
				ucl_chunk_skipc (chunk, *++p);
+
			}
+
			if (comments_nested != 0) {
+
				ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", err);
+
				return false;
+
			}
+
		}
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Return multiplier for a character
+
 * @param c multiplier character
+
 * @param is_bytes if true use 1024 multiplier
+
 * @return multiplier
+
 */
+
static inline unsigned long
+
ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
+
	const struct {
+
		char c;
+
		long mult_normal;
+
		long mult_bytes;
+
	} multipliers[] = {
+
			{'m', 1000 * 1000, 1024 * 1024},
+
			{'k', 1000, 1024},
+
			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
+
	};
+
	int i;
+

+
	for (i = 0; i < 3; i ++) {
+
		if (tolower (c) == multipliers[i].c) {
+
			if (is_bytes) {
+
				return multipliers[i].mult_bytes;
+
			}
+
			return multipliers[i].mult_normal;
+
		}
+
	}
+

+
	return 1;
+
}
+

+

+
/**
+
 * Return multiplier for time scaling
+
 * @param c
+
 * @return
+
 */
+
static inline double
+
ucl_lex_time_multiplier (const unsigned char c) {
+
	const struct {
+
		char c;
+
		double mult;
+
	} multipliers[] = {
+
			{'m', 60},
+
			{'h', 60 * 60},
+
			{'d', 60 * 60 * 24},
+
			{'w', 60 * 60 * 24 * 7},
+
			{'y', 60 * 60 * 24 * 7 * 365}
+
	};
+
	int i;
+

+
	for (i = 0; i < 5; i ++) {
+
		if (tolower (c) == multipliers[i].c) {
+
			return multipliers[i].mult;
+
		}
+
	}
+

+
	return 1;
+
}
+

+
/**
+
 * Return true if a character is a end of an atom
+
 * @param c
+
 * @return
+
 */
+
static inline bool
+
ucl_lex_is_atom_end (const unsigned char c)
+
{
+
	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
+
}
+

+
static inline bool
+
ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
+
{
+
	if (c1 == '/') {
+
		if (c2 == '/' || c2 == '*') {
+
			return true;
+
		}
+
	}
+
	else if (c1 == '#') {
+
		return true;
+
	}
+
	return false;
+
}
+

+
/**
+
 * Parse possible number
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return true if a number has been parsed
+
 */
+
static bool
+
ucl_lex_number (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, ucl_object_t *obj, UT_string **err)
+
{
+
	const unsigned char *p = chunk->pos, *c = chunk->pos;
+
	char *endptr;
+
	bool got_dot = false, got_exp = false, need_double = false, is_date = false;
+
	double dv;
+
	int64_t lv;
+

+
	if (*p == '-') {
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
	}
+
	while (p < chunk->end) {
+
		if (isdigit (*p)) {
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else {
+
			if (p == c) {
+
				/* Empty digits sequence, not a number */
+
				return false;
+
			}
+
			else if (*p == '.') {
+
				if (got_dot) {
+
					/* Double dots, not a number */
+
					return false;
+
				}
+
				else {
+
					got_dot = true;
+
					need_double = true;
+
				}
+
			}
+
			else if (*p == 'e' || *p == 'E') {
+
				if (got_exp) {
+
					/* Double exp, not a number */
+
					return false;
+
				}
+
				else {
+
					got_exp = true;
+
					need_double = true;
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
					if (p >= chunk->end) {
+
						return false;
+
					}
+
					if (!isdigit (*p) && *p != '+' && *p == '-') {
+
						/* Wrong exponent sign */
+
						return false;
+
					}
+
				}
+
			}
+
			else {
+
				/* Got the end of the number, need to check */
+
				break;
+
			}
+
		}
+
	}
+

+
	errno = 0;
+
	if (need_double) {
+
		dv = strtod (c, &endptr);
+
	}
+
	else {
+
		lv = strtoimax (c, &endptr, 10);
+
	}
+
	if (errno == ERANGE) {
+
		ucl_set_err (chunk, UCL_ESYNTAX, "numeric value is out of range", err);
+
		parser->prev_state = parser->state;
+
		parser->state = UCL_STATE_ERROR;
+
		return false;
+
	}
+

+
	/* Now check endptr */
+
	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
+
		chunk->pos = endptr;
+
		goto set_obj;
+
	}
+

+
	if ((unsigned char *)endptr < chunk->end) {
+
		p = endptr;
+
		chunk->pos = p;
+
		switch (*p) {
+
		case 'm':
+
		case 'M':
+
		case 'g':
+
		case 'G':
+
		case 'k':
+
		case 'K':
+
			if (chunk->end - p > 2) {
+
				if (p[1] == 's' || p[1] == 'S') {
+
					/* Milliseconds */
+
					if (!need_double) {
+
						need_double = true;
+
						dv = lv;
+
					}
+
					is_date = true;
+
					if (p[0] == 'm' || p[0] == 'M') {
+
						dv /= 1000.;
+
					}
+
					else {
+
						dv *= ucl_lex_num_multiplier (*p, false);
+
					}
+
					ucl_chunk_skipc (chunk, *p);
+
					ucl_chunk_skipc (chunk, *p);
+
					p += 2;
+
					goto set_obj;
+
				}
+
				else if (p[1] == 'b' || p[1] == 'B') {
+
					/* Megabytes */
+
					if (need_double) {
+
						need_double = false;
+
						lv = dv;
+
					}
+
					lv *= ucl_lex_num_multiplier (*p, true);
+
					ucl_chunk_skipc (chunk, *p);
+
					ucl_chunk_skipc (chunk, *p);
+
					p += 2;
+
					goto set_obj;
+
				}
+
				else if (ucl_lex_is_atom_end (p[1])) {
+
					if (need_double) {
+
						dv *= ucl_lex_num_multiplier (*p, false);
+
					}
+
					else {
+
						lv *= ucl_lex_num_multiplier (*p, false);
+
					}
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
					goto set_obj;
+
				}
+
				else if (chunk->end - p >= 3) {
+
					if (tolower (p[0]) == 'm' &&
+
							tolower (p[1]) == 'i' &&
+
							tolower (p[2]) == 'n') {
+
						/* Minutes */
+
						if (!need_double) {
+
							need_double = true;
+
							dv = lv;
+
						}
+
						is_date = true;
+
						dv *= 60.;
+
						ucl_chunk_skipc (chunk, *p);
+
						ucl_chunk_skipc (chunk, *p);
+
						ucl_chunk_skipc (chunk, *p);
+
						p += 3;
+
						goto set_obj;
+
					}
+
				}
+
			}
+
			else {
+
				if (need_double) {
+
					dv *= ucl_lex_num_multiplier (*p, false);
+
				}
+
				else {
+
					lv *= ucl_lex_num_multiplier (*p, false);
+
				}
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
				goto set_obj;
+
			}
+
			break;
+
		case 'S':
+
		case 's':
+
			if (p == chunk->end - 1 || ucl_lex_is_atom_end (*++p)) {
+
				if (!need_double) {
+
					need_double = true;
+
					dv = lv;
+
				}
+
				ucl_chunk_skipc (chunk, *p);
+
				is_date = true;
+
				goto set_obj;
+
			}
+
			break;
+
		case 'h':
+
		case 'H':
+
		case 'd':
+
		case 'D':
+
		case 'w':
+
		case 'W':
+
		case 'Y':
+
		case 'y':
+
			if (p == chunk->end - 1 || ucl_lex_is_atom_end (p[1])) {
+
				if (!need_double) {
+
					need_double = true;
+
					dv = lv;
+
				}
+
				is_date = true;
+
				dv *= ucl_lex_time_multiplier (*p);
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
				goto set_obj;
+
			}
+
			break;
+
		}
+
	}
+

+
	chunk->pos = c;
+
	return false;
+

+
set_obj:
+
	if (need_double || is_date) {
+
		if (!is_date) {
+
			obj->type = UCL_FLOAT;
+
		}
+
		else {
+
			obj->type = UCL_TIME;
+
		}
+
		obj->value.dv = dv;
+
	}
+
	else {
+
		obj->type = UCL_INT;
+
		obj->value.iv = lv;
+
	}
+
	chunk->pos = p;
+
	return true;
+
}
+

+
/**
+
 * Parse quoted string with possible escapes
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return true if a string has been parsed
+
 */
+
static bool
+
ucl_lex_json_string (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, UT_string **err)
+
{
+
	const unsigned char *p = chunk->pos;
+
	unsigned char c;
+
	int i;
+

+
	while (p < chunk->end) {
+
		c = *p;
+
		if (c < 0x1F) {
+
			/* Unmasked control character */
+
			if (c == '\n') {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", err);
+
			}
+
			else {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", err);
+
			}
+
			return false;
+
		}
+
		if (c == '\\') {
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
			c = *p;
+
			if (p >= chunk->end) {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err);
+
				return false;
+
			}
+
			if (*p == 'u') {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
				for (i = 0; i < 4 && p < chunk->end; i ++) {
+
					if (!isxdigit (*p)) {
+
						ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", err);
+
						return false;
+
					}
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
				}
+
				if (p >= chunk->end) {
+
					ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err);
+
					return false;
+
				}
+
			}
+
			else if (c == '"' || c == '\\' || c == '/' || c == 'b' ||
+
					c == 'f' || c == 'n' || c == 'r' || c == 't') {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			else {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", err);
+
				return false;
+
			}
+
			continue;
+
		}
+
		else if (c == '"') {
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
			return true;
+
		}
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
	}
+

+
	return false;
+
}
+

+
/**
+
 * Parse a key in an object
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return true if a key has been parsed
+
 */
+
static bool
+
ucl_parse_key (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, UT_string **err)
+
{
+
	const unsigned char *p, *c = NULL, *end;
+
	bool got_quote = false, got_eq = false, got_semicolon = false;
+
	ucl_object_t *nobj, *tobj, *container;
+

+
	p = chunk->pos;
+

+
	while (p < chunk->end) {
+
		/*
+
		 * A key must start with alpha and end with space character
+
		 */
+
		if (*p == '.') {
+
			/* It is macro actually */
+
			ucl_chunk_skipc (chunk, *p);
+
			parser->prev_state = parser->state;
+
			parser->state = UCL_STATE_MACRO_NAME;
+
			return true;
+
		}
+
		else if (c == NULL) {
+
			if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
+
				/* The first symbol */
+
				c = p;
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			else if (*p == '"') {
+
				/* JSON style key */
+
				c = p + 1;
+
				got_quote = true;
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			else {
+
				/* Invalid identifier */
+
				ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", err);
+
				return false;
+
			}
+
		}
+
		else {
+
			/* Parse the body of a key */
+
			if (!got_quote) {
+
				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
				}
+
				else if (*p == ' ' || *p == '\t' || *p == ':' || *p == '=') {
+
					end = p;
+
					break;
+
				}
+
				else {
+
					ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", err);
+
					return false;
+
				}
+
			}
+
			else {
+
				/* We need to parse json like quoted string */
+
				if (!ucl_lex_json_string (parser, chunk, err)) {
+
					return false;
+
				}
+
				end = chunk->pos - 1;
+
				p = chunk->pos;
+
				break;
+
			}
+
		}
+
	}
+

+
	if (p >= chunk->end) {
+
		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err);
+
		return false;
+
	}
+

+
	/* We are now at the end of the key, need to parse the rest */
+
	while (p < chunk->end) {
+
		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else if (*p == '=') {
+
			if (!got_eq && !got_semicolon) {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
				got_eq = true;
+
			}
+
			else {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", err);
+
				return false;
+
			}
+
		}
+
		else if (*p == ':') {
+
			if (!got_eq && !got_semicolon) {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
				got_semicolon = true;
+
			}
+
			else {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", err);
+
				return false;
+
			}
+
		}
+
		else if (ucl_lex_is_comment (p[0], p[1])) {
+
			/* Check for comment */
+
			if (!ucl_skip_comments (parser, err)) {
+
				return false;
+
			}
+
			p = chunk->pos;
+
		}
+
		else {
+
			/* Start value */
+
			break;
+
		}
+
	}
+

+
	if (p >= chunk->end) {
+
		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err);
+
		return false;
+
	}
+

+
	/* Create a new object */
+
	nobj = ucl_object_new ();
+
	nobj->key = malloc (end - c + 1);
+
	if (parser->flags & UCL_FLAG_KEY_LOWERCASE) {
+
		ucl_strlcpy_tolower (nobj->key, c, end - c + 1);
+
	}
+
	else {
+
		ucl_strlcpy (nobj->key, c, end - c + 1);
+
	}
+

+
	if (got_quote) {
+
		ucl_unescape_json_string (nobj->key);
+
	}
+

+
	container = parser->stack->obj->value.ov;
+
	HASH_FIND_STR (container, nobj->key, tobj);
+
	if (tobj != NULL) {
+
		/* Just insert a new object as the next element */
+
		LL_PREPEND (tobj, nobj);
+
		HASH_DELETE (hh, container, tobj);
+
	}
+

+
	HASH_ADD_KEYPTR (hh, container, nobj->key, strlen (nobj->key), nobj);
+
	parser->stack->obj->value.ov = container;
+

+
	parser->cur_obj = nobj;
+

+
	return true;
+
}
+

+
/**
+
 * Parse a cl string
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return true if a key has been parsed
+
 */
+
static bool
+
ucl_parse_string_value (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, UT_string **err)
+
{
+
	const unsigned char *p;
+

+
	p = chunk->pos;
+

+
	while (p < chunk->end) {
+
		if (ucl_lex_is_atom_end (*p) || ucl_lex_is_comment (p[0], p[1])) {
+
			break;
+
		}
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
	}
+

+
	if (p >= chunk->end) {
+
		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", err);
+
		return false;
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Check whether a given string contains a boolean value
+
 * @param obj object to set
+
 * @param start start of a string
+
 * @param len length of a string
+
 * @return true if a string is a boolean value
+
 */
+
static inline bool
+
ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
+
{
+
	const unsigned char *p = start;
+
	bool ret = false, val = false;
+

+
	if (len == 5) {
+
		if (tolower (p[0]) == 'f' && strncasecmp (p, "false", 5) == 0) {
+
			ret = true;
+
			val = false;
+
		}
+
	}
+
	else if (len == 4) {
+
		if (tolower (p[0]) == 't' && strncasecmp (p, "true", 4) == 0) {
+
			ret = true;
+
			val = true;
+
		}
+
	}
+
	else if (len == 3) {
+
		if (tolower (p[0]) == 'y' && strncasecmp (p, "yes", 3) == 0) {
+
			ret = true;
+
			val = true;
+
		}
+
		if (tolower (p[0]) == 'o' && strncasecmp (p, "off", 3) == 0) {
+
			ret = true;
+
			val = false;
+
		}
+
	}
+
	else if (len == 2) {
+
		if (tolower (p[0]) == 'n' && strncasecmp (p, "no", 2) == 0) {
+
			ret = true;
+
			val = false;
+
		}
+
		else if (tolower (p[0]) == 'o' && strncasecmp (p, "on", 2) == 0) {
+
			ret = true;
+
			val = true;
+
		}
+
	}
+

+
	if (ret) {
+
		obj->type = UCL_BOOLEAN;
+
		obj->value.iv = val;
+
	}
+

+
	return ret;
+
}
+

+
/**
+
 * Handle value data
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return
+
 */
+
static bool
+
ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err)
+
{
+
	const unsigned char *p, *c;
+
	struct ucl_stack *st;
+
	ucl_object_t *obj = NULL;
+
	unsigned int stripped_spaces;
+

+
	p = chunk->pos;
+

+
	while (p < chunk->end) {
+
		if (obj == NULL) {
+
			if (parser->stack->obj->type == UCL_ARRAY) {
+
				/* Object must be allocated */
+
				obj = ucl_object_new ();
+
				parser->cur_obj = obj;
+
				LL_PREPEND (parser->stack->obj->value.ov, parser->cur_obj);
+
			}
+
			else {
+
				/* Object has been already allocated */
+
				obj = parser->cur_obj;
+
			}
+
		}
+
		c = p;
+
		switch (*p) {
+
		case '"':
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
			if (!ucl_lex_json_string (parser, chunk, err)) {
+
				return false;
+
			}
+
			obj->value.sv = malloc (chunk->pos - c - 1);
+
			ucl_strlcpy (obj->value.sv, c + 1, chunk->pos - c - 1);
+
			ucl_unescape_json_string (obj->value.sv);
+
			obj->type = UCL_STRING;
+
			parser->state = UCL_STATE_AFTER_VALUE;
+
			p = chunk->pos;
+
			return true;
+
			break;
+
		case '{':
+
			/* We have a new object */
+
			obj->type = UCL_OBJECT;
+

+
			parser->state = UCL_STATE_KEY;
+
			st = UCL_ALLOC (sizeof (struct ucl_stack));
+
			st->obj = obj;
+
			LL_PREPEND (parser->stack, st);
+
			parser->cur_obj = obj;
+

+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
			return true;
+
			break;
+
		case '[':
+
			/* We have a new array */
+
			obj = parser->cur_obj;
+
			obj->type = UCL_ARRAY;
+

+
			parser->state = UCL_STATE_VALUE;
+
			st = UCL_ALLOC (sizeof (struct ucl_stack));
+
			st->obj = obj;
+
			LL_PREPEND (parser->stack, st);
+
			parser->cur_obj = obj;
+

+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
			return true;
+
			break;
+
		default:
+
			/* Skip any spaces and comments */
+
			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE) ||
+
					ucl_lex_is_comment (p[0], p[1])) {
+
				while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
				}
+
				if (!ucl_skip_comments (parser, err)) {
+
					return false;
+
				}
+
				p = chunk->pos;
+
				continue;
+
			}
+
			/* Parse atom */
+
			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
+
				if (!ucl_lex_number (parser, chunk, obj, err)) {
+
					if (parser->state == UCL_STATE_ERROR) {
+
						return false;
+
					}
+
					if (!ucl_parse_string_value (parser, chunk, err)) {
+
						return false;
+
					}
+
					if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) {
+
						/* Cut trailing spaces */
+
						stripped_spaces = 0;
+
						while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
+
								UCL_CHARACTER_WHITESPACE)) {
+
							stripped_spaces ++;
+
						}
+
						obj->value.sv = malloc (chunk->pos - c + 1 - stripped_spaces);
+
						ucl_strlcpy (obj->value.sv, c, chunk->pos - c + 1 - stripped_spaces);
+
						ucl_unescape_json_string (obj->value.sv);
+
						obj->type = UCL_STRING;
+
					}
+
					parser->state = UCL_STATE_AFTER_VALUE;
+
					return true;
+
				}
+
				else {
+
					parser->state = UCL_STATE_AFTER_VALUE;
+
					return true;
+
				}
+
			}
+
			else {
+
				if (!ucl_parse_string_value (parser, chunk, err)) {
+
					return false;
+
				}
+
				if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) {
+
					obj->value.sv = malloc (chunk->pos - c + 1);
+
					ucl_strlcpy (obj->value.sv, c, chunk->pos - c + 1);
+
					ucl_unescape_json_string (obj->value.sv);
+
					obj->type = UCL_STRING;
+
				}
+
				parser->state = UCL_STATE_AFTER_VALUE;
+
				return true;
+
			}
+
			p = chunk->pos;
+
			break;
+
		}
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Handle after value data
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return
+
 */
+
static bool
+
ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err)
+
{
+
	const unsigned char *p;
+
	bool got_sep = false, got_comma = false, got_semicolon = false;
+
	struct ucl_stack *st;
+

+
	p = chunk->pos;
+

+
	while (p < chunk->end) {
+
		if (*p == ' ' || *p == '\t') {
+
			/* Skip whitespaces */
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else if (ucl_lex_is_comment (p[0], p[1])) {
+
			/* Skip comment */
+
			if (!ucl_skip_comments (parser, err)) {
+
				return false;
+
			}
+
			/* Treat comment as a separator */
+
			got_sep = true;
+
			p = chunk->pos;
+
		}
+
		else if (*p == ',') {
+
			/* Got a separator */
+
			got_sep = true;
+
			if (got_comma || got_semicolon) {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected comma detected", err);
+
				return false;
+
			}
+
			got_comma = true;
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else if (*p == ';') {
+
			/* Got a separator */
+
			got_sep = true;
+
			if (got_comma || got_semicolon) {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected semicolon detected", err);
+
				return false;
+
			}
+
			got_semicolon = true;
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else if (*p == '\n') {
+
			got_sep = true;
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		else if (*p == '}' || *p == ']') {
+
			if (parser->stack == NULL) {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected } detected", err);
+
				return false;
+
			}
+
			if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
+
					(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
+
				/* Pop object from a stack */
+

+
				st = parser->stack;
+
				parser->stack = st->next;
+
				UCL_FREE (sizeof (struct ucl_stack), st);
+
			}
+
			else {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", err);
+
				return false;
+
			}
+

+
			if (parser->stack == NULL) {
+
				/* Ignore everything after a top object */
+
				return true;
+
			}
+
			else {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			got_sep = true;
+
		}
+
		else {
+
			/* Anything else */
+
			if (!got_sep) {
+
				ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", err);
+
				return false;
+
			}
+
			return true;
+
		}
+
	}
+

+
	return true;
+
}
+

+
/**
+
 * Handle macro data
+
 * @param parser
+
 * @param chunk
+
 * @param err
+
 * @return
+
 */
+
static bool
+
ucl_parse_macro_value (struct ucl_parser *parser,
+
		struct ucl_chunk *chunk, struct ucl_macro *macro,
+
		unsigned char const **macro_start, size_t *macro_len, UT_string **err)
+
{
+
	const unsigned char *p, *c;
+

+
	p = chunk->pos;
+

+
	switch (*p) {
+
	case '"':
+
		/* We have macro value encoded in quotes */
+
		c = p;
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
		if (!ucl_lex_json_string (parser, chunk, err)) {
+
			return false;
+
		}
+

+
		*macro_start = c + 1;
+
		*macro_len = chunk->pos - c - 2;
+
		p = chunk->pos;
+
		break;
+
	case '{':
+
		/* We got a multiline macro body */
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
		/* Skip spaces at the beginning */
+
		while (p < chunk->end) {
+
			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			else {
+
				break;
+
			}
+
		}
+
		c = p;
+
		while (p < chunk->end) {
+
			if (*p == '}') {
+
				break;
+
			}
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		*macro_start = c;
+
		*macro_len = p - c;
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
		break;
+
	default:
+
		/* Macro is not enclosed in quotes or braces */
+
		c = p;
+
		while (p < chunk->end) {
+
			if (ucl_lex_is_atom_end (*p)) {
+
				break;
+
			}
+
			ucl_chunk_skipc (chunk, *p);
+
			p ++;
+
		}
+
		*macro_start = c;
+
		*macro_len = p - c;
+
		break;
+
	}
+

+
	/* We are at the end of a macro */
+
	/* Skip ';' and space characters and return to previous state */
+
	while (p < chunk->end) {
+
		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE) && *p != ';') {
+
			break;
+
		}
+
		ucl_chunk_skipc (chunk, *p);
+
		p ++;
+
	}
+
	return true;
+
}
+

+
/**
+
 * Handle the main states of rcl parser
+
 * @param parser parser structure
+
 * @param data the pointer to the beginning of a chunk
+
 * @param len the length of a chunk
+
 * @param err if *err is NULL it is set to parser error
+
 * @return true if chunk has been parsed and false in case of error
+
 */
+
static bool
+
ucl_state_machine (struct ucl_parser *parser, UT_string **err)
+
{
+
	ucl_object_t *obj;
+
	struct ucl_chunk *chunk = parser->chunks;
+
	struct ucl_stack *st;
+
	const unsigned char *p, *c, *macro_start = NULL;
+
	size_t macro_len = 0;
+
	struct ucl_macro *macro = NULL;
+

+
	p = chunk->pos;
+
	while (chunk->pos < chunk->end) {
+
		switch (parser->state) {
+
		case UCL_STATE_INIT:
+
			/*
+
			 * At the init state we can either go to the parse array or object
+
			 * if we got [ or { correspondingly or can just treat new data as
+
			 * a key of newly created object
+
			 */
+
			if (!ucl_skip_comments (parser, err)) {
+
				parser->prev_state = parser->state;
+
				parser->state = UCL_STATE_ERROR;
+
				return false;
+
			}
+
			else {
+
				p = chunk->pos;
+
				obj = ucl_object_new ();
+
				if (*p == '[') {
+
					parser->state = UCL_STATE_VALUE;
+
					obj->type = UCL_ARRAY;
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
				}
+
				else {
+
					parser->state = UCL_STATE_KEY;
+
					obj->type = UCL_OBJECT;
+
					if (*p == '{') {
+
						ucl_chunk_skipc (chunk, *p);
+
						p ++;
+
					}
+
				};
+
				parser->cur_obj = obj;
+
				parser->top_obj = obj;
+
				st = UCL_ALLOC (sizeof (struct ucl_stack));
+
				st->obj = obj;
+
				LL_PREPEND (parser->stack, st);
+
			}
+
			break;
+
		case UCL_STATE_KEY:
+
			/* Skip any spaces */
+
			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			if (*p == '}') {
+
				/* We have the end of an object */
+
				parser->state = UCL_STATE_AFTER_VALUE;
+
				continue;
+
			}
+
			if (!ucl_parse_key (parser, chunk, err)) {
+
				parser->prev_state = parser->state;
+
				parser->state = UCL_STATE_ERROR;
+
				return false;
+
			}
+
			if (parser->state != UCL_STATE_MACRO_NAME) {
+
				parser->state = UCL_STATE_VALUE;
+
			}
+
			else {
+
				c = chunk->pos;
+
			}
+
			p = chunk->pos;
+
			break;
+
		case UCL_STATE_VALUE:
+
			/* We need to check what we do have */
+
			if (!ucl_parse_value (parser, chunk, err)) {
+
				parser->prev_state = parser->state;
+
				parser->state = UCL_STATE_ERROR;
+
				return false;
+
			}
+
			/* State is set in ucl_parse_value call */
+
			p = chunk->pos;
+
			break;
+
		case UCL_STATE_AFTER_VALUE:
+
			if (!ucl_parse_after_value (parser, chunk, err)) {
+
				parser->prev_state = parser->state;
+
				parser->state = UCL_STATE_ERROR;
+
				return false;
+
			}
+
			if (parser->stack != NULL) {
+
				if (parser->stack->obj->type == UCL_OBJECT) {
+
					parser->state = UCL_STATE_KEY;
+
				}
+
				else {
+
					/* Array */
+
					parser->state = UCL_STATE_VALUE;
+
				}
+
			}
+
			else {
+
				/* Skip everything at the end */
+
				return true;
+
			}
+
			p = chunk->pos;
+
			break;
+
		case UCL_STATE_MACRO_NAME:
+
			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
				ucl_chunk_skipc (chunk, *p);
+
				p ++;
+
			}
+
			else if (p - c > 0) {
+
				/* We got macro name */
+
				HASH_FIND (hh, parser->macroes, c, (p - c), macro);
+
				if (macro == NULL) {
+
					ucl_set_err (chunk, UCL_EMACRO, "unknown macro", err);
+
					parser->state = UCL_STATE_ERROR;
+
					return false;
+
				}
+
				/* Now we need to skip all spaces */
+
				while (p < chunk->end) {
+
					if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+
						if (ucl_lex_is_comment (p[0], p[1])) {
+
							/* Skip comment */
+
							if (!ucl_skip_comments (parser, err)) {
+
								return false;
+
							}
+
							p = chunk->pos;
+
						}
+
						break;
+
					}
+
					ucl_chunk_skipc (chunk, *p);
+
					p ++;
+
				}
+
				parser->state = UCL_STATE_MACRO;
+
			}
+
			break;
+
		case UCL_STATE_MACRO:
+
			if (!ucl_parse_macro_value (parser, chunk, macro,
+
					&macro_start, &macro_len, err)) {
+
				parser->prev_state = parser->state;
+
				parser->state = UCL_STATE_ERROR;
+
				return false;
+
			}
+
			parser->state = parser->prev_state;
+
			if (!macro->handler (macro_start, macro_len, macro->ud, err)) {
+
				return false;
+
			}
+
			p = chunk->pos;
+
			break;
+
		default:
+
			/* TODO: add all states */
+
			return false;
+
		}
+
	}
+

+
	return true;
+
}
+

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

+
	new = UCL_ALLOC (sizeof (struct ucl_parser));
+
	memset (new, 0, sizeof (struct ucl_parser));
+

+
	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
+
	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
+

+
	new->flags = flags;
+

+
	return new;
+
}
+

+

+
void
+
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
+
		ucl_macro_handler handler, void* ud)
+
{
+
	struct ucl_macro *new;
+

+
	new = UCL_ALLOC (sizeof (struct ucl_macro));
+
	memset (new, 0, sizeof (struct ucl_macro));
+
	new->handler = handler;
+
	new->name = strdup (macro);
+
	new->ud = ud;
+
	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
+
}
+

+
bool
+
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
+
		size_t len, UT_string **err)
+
{
+
	struct ucl_chunk *chunk;
+

+
	if (parser->state != UCL_STATE_ERROR) {
+
		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
+
		chunk->begin = data;
+
		chunk->remain = len;
+
		chunk->pos = chunk->begin;
+
		chunk->end = chunk->begin + len;
+
		chunk->line = 1;
+
		chunk->column = 0;
+
		LL_PREPEND (parser->chunks, chunk);
+
		parser->recursion ++;
+
		if (parser->recursion > UCL_MAX_RECURSION) {
+
			ucl_create_err (err, "maximum include nesting limit is reached: %d",
+
					parser->recursion);
+
			return false;
+
		}
+
		return ucl_state_machine (parser, err);
+
	}
+

+
	ucl_create_err (err, "a parser is in an invalid state");
+

+
	return false;
+
}
added external/libucl/src/ucl_util.c
@@ -0,0 +1,664 @@
+
/* Copyright (c) 2013, 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 ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include "ucl.h"
+
#include "ucl_internal.h"
+

+
#ifdef HAVE_OPENSSL
+
#include <openssl/err.h>
+
#include <openssl/sha.h>
+
#include <openssl/rsa.h>
+
#include <openssl/ssl.h>
+
#include <openssl/evp.h>
+
#endif
+

+
/**
+
 * @file rcl_util.c
+
 * Utilities for rcl parsing
+
 */
+

+

+
static void
+
ucl_obj_free_internal (ucl_object_t *obj, bool allow_rec)
+
{
+
	ucl_object_t *sub, *tmp;
+

+
	while (obj != NULL) {
+
		if (obj->key != NULL) {
+
			free (obj->key);
+
		}
+

+
		if (obj->type == UCL_STRING) {
+
			free (obj->value.sv);
+
		}
+
		else if (obj->type == UCL_ARRAY) {
+
			sub = obj->value.ov;
+
			while (sub != NULL) {
+
				tmp = sub->next;
+
				ucl_obj_free_internal (sub, false);
+
				sub = tmp;
+
			}
+
		}
+
		else if (obj->type == UCL_OBJECT) {
+
			HASH_ITER (hh, obj->value.ov, sub, tmp) {
+
				HASH_DELETE (hh, obj->value.ov, sub);
+
				ucl_obj_free_internal (sub, true);
+
			}
+
		}
+
		tmp = obj->next;
+
		UCL_FREE (sizeof (ucl_object_t), obj);
+
		obj = tmp;
+

+
		if (!allow_rec) {
+
			break;
+
		}
+
	}
+
}
+

+
void
+
ucl_obj_free (ucl_object_t *obj)
+
{
+
	ucl_obj_free_internal (obj, true);
+
}
+

+
void
+
ucl_unescape_json_string (char *str)
+
{
+
	char *t = str, *h = str;
+
	int i, uval;
+

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

+
	while (*h != '\0') {
+
		if (*h == '\\') {
+
			h ++;
+
			switch (*h) {
+
			case 'n':
+
				*t++ = '\n';
+
				break;
+
			case 'r':
+
				*t++ = '\r';
+
				break;
+
			case 'b':
+
				*t++ = '\b';
+
				break;
+
			case 't':
+
				*t++ = '\t';
+
				break;
+
			case 'f':
+
				*t++ = '\f';
+
				break;
+
			case '\\':
+
				*t++ = '\\';
+
				break;
+
			case '"':
+
				*t++ = '"';
+
				break;
+
			case 'u':
+
				/* Unicode escape */
+
				uval = 0;
+
				for (i = 0; i < 4; i++) {
+
					uval <<= 4;
+
					if (isdigit (h[i])) {
+
						uval += h[i] - '0';
+
					}
+
					else if (h[i] >= 'a' && h[i] <= 'f') {
+
						uval += h[i] - 'a' + 10;
+
					}
+
					else if (h[i] >= 'A' && h[i] <= 'F') {
+
						uval += h[i] - 'A' + 10;
+
					}
+
				}
+
				h += 3;
+
				/* Encode */
+
				if(uval < 0x80) {
+
					t[0] = (char)uval;
+
					t ++;
+
				}
+
				else if(uval < 0x800) {
+
					t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
+
					t[1] = 0x80 + ((uval & 0x03F));
+
					t += 2;
+
				}
+
				else if(uval < 0x10000) {
+
					t[0] = 0xE0 + ((uval & 0xF000) >> 12);
+
					t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
+
					t[2] = 0x80 + ((uval & 0x003F));
+
					t += 3;
+
				}
+
				else if(uval <= 0x10FFFF) {
+
					t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
+
					t[1] = 0x80 + ((uval & 0x03F000) >> 12);
+
					t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
+
					t[3] = 0x80 + ((uval & 0x00003F));
+
					t += 4;
+
				}
+
				else {
+
					*t++ = '?';
+
				}
+
				break;
+
			default:
+
				*t++ = '?';
+
				break;
+
			}
+
			h ++;
+
		}
+
		else {
+
			*t++ = *h++;
+
		}
+
	}
+
}
+

+
ucl_object_t*
+
ucl_parser_get_object (struct ucl_parser *parser, UT_string **err)
+
{
+
	if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) {
+
		return ucl_obj_ref (parser->top_obj);
+
	}
+

+
	return NULL;
+
}
+

+
void
+
ucl_parser_free (struct ucl_parser *parser)
+
{
+
	struct ucl_stack *stack, *stmp;
+
	struct ucl_macro *macro, *mtmp;
+
	struct ucl_chunk *chunk, *ctmp;
+
	struct ucl_pubkey *key, *ktmp;
+

+
	if (parser->top_obj != NULL) {
+
		ucl_obj_unref (parser->top_obj);
+
	}
+

+
	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
+
		free (stack);
+
	}
+
	HASH_ITER (hh, parser->macroes, macro, mtmp) {
+
		UCL_FREE (sizeof (struct ucl_macro), macro);
+
	}
+
	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
+
		UCL_FREE (sizeof (struct ucl_chunk), chunk);
+
	}
+
	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
+
		UCL_FREE (sizeof (struct ucl_pubkey), key);
+
	}
+

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

+
bool
+
ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err)
+
{
+
	struct ucl_pubkey *nkey;
+
#ifndef HAVE_OPENSSL
+
	ucl_create_err (err, "cannot check signatures without openssl");
+
	return false;
+
#else
+
# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
	ucl_create_err (err, "cannot check signatures, openssl version is unsupported");
+
	return EXIT_FAILURE;
+
# else
+
	BIO *mem;
+

+
	mem = BIO_new_mem_buf ((void *)key, len);
+
	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
+
	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
+
	BIO_free (mem);
+
	if (nkey->key == NULL) {
+
		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
+
		ucl_create_err (err, "%s",
+
				ERR_error_string (ERR_get_error (), NULL));
+
		return false;
+
	}
+
	LL_PREPEND (parser->keys, nkey);
+
# endif
+
#endif
+
	return true;
+
}
+

+
#ifdef CURL_FOUND
+
struct ucl_curl_cbdata {
+
	unsigned char *buf;
+
	size_t buflen;
+
};
+

+
static size_t
+
ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
+
{
+
	struct ucl_curl_cbdata *cbdata = ud;
+
	size_t realsize = size * nmemb;
+

+
	cbdata->buf = g_realloc (cbdata->buf, cbdata->buflen + realsize + 1);
+
	if (cbdata->buf == NULL) {
+
		return 0;
+
	}
+

+
	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
+
	cbdata->buflen += realsize;
+
	cbdata->buf[cbdata->buflen] = 0;
+

+
	return realsize;
+
}
+
#endif
+

+
/**
+
 * Fetch a url and save results to the memory buffer
+
 * @param url url to fetch
+
 * @param len length of url
+
 * @param buf target buffer
+
 * @param buflen target length
+
 * @return
+
 */
+
static bool
+
ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, UT_string **err)
+
{
+

+
#ifdef HAVE_FETCH_H
+
	struct url *fetch_url;
+
	struct url_stat us;
+
	FILE *in;
+

+
	fetch_url = fetchParseURL (url);
+
	if (fetch_url == NULL) {
+
		ucl_create_err (err, "invalid URL %s: %s",
+
				url, strerror (errno));
+
		return false;
+
	}
+
	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
+
		ucl_create_err (err, "cannot fetch URL %s: %s",
+
				url, strerror (errno));
+
		fetchFreeURL (fetch_url);
+
		return false;
+
	}
+

+
	*buflen = us.size;
+
	*buf = g_malloc (*buflen);
+
	if (*buf == NULL) {
+
		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
+
				url, strerror (errno));
+
		fclose (in);
+
		fetchFreeURL (fetch_url);
+
		return false;
+
	}
+

+
	if (fread (*buf, *buflen, 1, in) != 1) {
+
		ucl_create_err (err, "cannot read URL %s: %s",
+
				url, strerror (errno));
+
		fclose (in);
+
		fetchFreeURL (fetch_url);
+
		return false;
+
	}
+

+
	fetchFreeURL (fetch_url);
+
	return true;
+
#elif defined(CURL_FOUND)
+
	CURL *curl;
+
	int r;
+
	struct ucl_curl_cbdata cbdata;
+

+
	curl = curl_easy_init ();
+
	if (curl == NULL) {
+
		ucl_create_err (err, "CURL interface is broken");
+
		return false;
+
	}
+
	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
+
		ucl_create_err (err, "invalid URL %s: %s",
+
				url, curl_easy_strerror (r));
+
		curl_easy_cleanup (curl);
+
		return false;
+
	}
+
	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
+
	cbdata.buf = *buf;
+
	cbdata.buflen = *buflen;
+
	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
+

+
	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
+
		ucl_create_err (err, "error fetching URL %s: %s",
+
				url, curl_easy_strerror (r));
+
		curl_easy_cleanup (curl);
+
		if (buf != NULL) {
+
			free (buf);
+
		}
+
		return false;
+
	}
+
	*buf = cbdata.buf;
+
	*buflen = cbdata.buflen;
+

+
	return true;
+
#else
+
	ucl_create_err (err, "URL support is disabled");
+
	return false;
+
#endif
+
}
+

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

+
	if (stat (filename, &st) == -1) {
+
		ucl_create_err (err, "cannot stat file %s: %s",
+
				filename, strerror (errno));
+
		return false;
+
	}
+
	if ((fd = open (filename, O_RDONLY)) == -1) {
+
		ucl_create_err (err, "cannot open file %s: %s",
+
				filename, strerror (errno));
+
		return false;
+
	}
+
	if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+
		close (fd);
+
		ucl_create_err (err, "cannot mmap file %s: %s",
+
				filename, strerror (errno));
+
		return false;
+
	}
+
	*buflen = st.st_size;
+
	close (fd);
+

+
	return true;
+
}
+

+

+
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
+
static inline bool
+
ucl_sig_check (const unsigned char *data, size_t datalen,
+
		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
+
{
+
	struct ucl_pubkey *key;
+
	char dig[EVP_MAX_MD_SIZE];
+
	unsigned int diglen;
+
	EVP_PKEY_CTX *key_ctx;
+
	EVP_MD_CTX *sign_ctx = NULL;
+

+
	sign_ctx = EVP_MD_CTX_create ();
+

+
	LL_FOREACH (parser->keys, key) {
+
		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
+
		if (key_ctx != NULL) {
+
			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
+
				EVP_PKEY_CTX_free (key_ctx);
+
				continue;
+
			}
+
			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
+
				EVP_PKEY_CTX_free (key_ctx);
+
				continue;
+
			}
+
			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
+
				EVP_PKEY_CTX_free (key_ctx);
+
				continue;
+
			}
+
			EVP_DigestInit (sign_ctx, EVP_sha256 ());
+
			EVP_DigestUpdate (sign_ctx, data, datalen);
+
			EVP_DigestFinal (sign_ctx, dig, &diglen);
+

+
			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
+
				EVP_MD_CTX_destroy (sign_ctx);
+
				EVP_PKEY_CTX_free (key_ctx);
+
				return true;
+
			}
+

+
			EVP_PKEY_CTX_free (key_ctx);
+
		}
+
	}
+

+
	EVP_MD_CTX_destroy (sign_ctx);
+

+
	return false;
+
}
+
#endif
+

+
/**
+
 * Include an url to configuration
+
 * @param data
+
 * @param len
+
 * @param parser
+
 * @param err
+
 * @return
+
 */
+
static bool
+
ucl_include_url (const unsigned char *data, size_t len,
+
		struct ucl_parser *parser, bool check_signature, UT_string **err)
+
{
+

+
	bool res;
+
	unsigned char *buf = NULL, *sigbuf = NULL;
+
	size_t buflen = 0, siglen = 0;
+
	struct ucl_chunk *chunk;
+
	char urlbuf[PATH_MAX];
+

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

+
	if (!ucl_fetch_url (urlbuf, &buf, &buflen, err)) {
+
		return false;
+
	}
+

+
	if (check_signature) {
+
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
+
		/* We need to check signature first */
+
		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
+
		if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, err)) {
+
			return false;
+
		}
+
		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
+
			ucl_create_err (err, "cannot verify url %s: %s",
+
							urlbuf,
+
							ERR_error_string (ERR_get_error (), NULL));
+
			munmap (sigbuf, siglen);
+
			return false;
+
		}
+
		munmap (sigbuf, siglen);
+
#endif
+
	}
+

+
	res = ucl_parser_add_chunk (parser, buf, buflen, err);
+
	if (res == true) {
+
		/* Remove chunk from the stack */
+
		chunk = parser->chunks;
+
		if (chunk != NULL) {
+
			parser->chunks = chunk->next;
+
			UCL_FREE (sizeof (struct ucl_chunk), chunk);
+
		}
+
	}
+
	free (buf);
+

+
	return res;
+
}
+

+
/**
+
 * Include a file to configuration
+
 * @param data
+
 * @param len
+
 * @param parser
+
 * @param err
+
 * @return
+
 */
+
static bool
+
ucl_include_file (const unsigned char *data, size_t len,
+
		struct ucl_parser *parser, bool check_signature, UT_string **err)
+
{
+
	bool res;
+
	struct ucl_chunk *chunk;
+
	unsigned char *buf = NULL, *sigbuf = NULL;
+
	size_t buflen, siglen;
+
	char filebuf[PATH_MAX], realbuf[PATH_MAX];
+

+
	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
+
	if (realpath (filebuf, realbuf) == NULL) {
+
		ucl_create_err (err, "cannot open file %s: %s",
+
									filebuf,
+
									strerror (errno));
+
		return false;
+
	}
+

+
	if (!ucl_fetch_file (realbuf, &buf, &buflen, err)) {
+
		return false;
+
	}
+

+
	if (check_signature) {
+
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
+
		/* We need to check signature first */
+
		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
+
		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, err)) {
+
			return false;
+
		}
+
		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
+
			ucl_create_err (err, "cannot verify file %s: %s",
+
							filebuf,
+
							ERR_error_string (ERR_get_error (), NULL));
+
			munmap (sigbuf, siglen);
+
			return false;
+
		}
+
		munmap (sigbuf, siglen);
+
#endif
+
	}
+

+
	res = ucl_parser_add_chunk (parser, buf, buflen, err);
+
	if (res == true) {
+
		/* Remove chunk from the stack */
+
		chunk = parser->chunks;
+
		if (chunk != NULL) {
+
			parser->chunks = chunk->next;
+
			UCL_FREE (sizeof (struct ucl_chunk), chunk);
+
		}
+
	}
+
	munmap (buf, buflen);
+

+
	return res;
+
}
+

+
/**
+
 * Handle include macro
+
 * @param data include data
+
 * @param len length of data
+
 * @param ud user data
+
 * @param err error ptr
+
 * @return
+
 */
+
bool
+
ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err)
+
{
+
	struct ucl_parser *parser = ud;
+

+
	if (*data == '/' || *data == '.') {
+
		/* Try to load a file */
+
		return ucl_include_file (data, len, parser, false, err);
+
	}
+

+
	return ucl_include_url (data, len, parser, false, err);
+
}
+

+
/**
+
 * Handle includes macro
+
 * @param data include data
+
 * @param len length of data
+
 * @param ud user data
+
 * @param err error ptr
+
 * @return
+
 */
+
bool
+
ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err)
+
{
+
	struct ucl_parser *parser = ud;
+

+
	if (*data == '/' || *data == '.') {
+
		/* Try to load a file */
+
		return ucl_include_file (data, len, parser, true, err);
+
	}
+

+
	return ucl_include_url (data, len, parser, true, err);
+
}
+

+
bool
+
ucl_parser_add_file (struct ucl_parser *parser, const char *filename,
+
		UT_string **err)
+
{
+
	unsigned char *buf;
+
	size_t len;
+
	bool ret;
+

+
	if (!ucl_fetch_file (filename, &buf, &len, err)) {
+
		return false;
+
	}
+

+
	ret = ucl_parser_add_chunk (parser, buf, len, err);
+

+
	munmap (buf, len);
+

+
	return ret;
+
}
+

+
size_t
+
ucl_strlcpy (char *dst, const char *src, size_t siz)
+
{
+
	char *d = dst;
+
	const char *s = src;
+
	size_t n = siz;
+

+
	/* Copy as many bytes as will fit */
+
	if (n != 0) {
+
		while (--n != 0) {
+
			if ((*d++ = *s++) == '\0') {
+
				break;
+
			}
+
		}
+
	}
+

+
	if (n == 0 && siz != 0) {
+
		*d = '\0';
+
	}
+

+
	return (s - src - 1);    /* count does not include NUL */
+
}
+

+
size_t
+
ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
+
{
+
	char *d = dst;
+
	const char *s = src;
+
	size_t n = siz;
+

+
	/* Copy as many bytes as will fit */
+
	if (n != 0) {
+
		while (--n != 0) {
+
			if ((*d++ = tolower (*s++)) == '\0') {
+
				break;
+
			}
+
		}
+
	}
+

+
	if (n == 0 && siz != 0) {
+
		*d = '\0';
+
	}
+

+
	return (s - src - 1);    /* count does not include NUL */
+
}