Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to latest version
Baptiste Daroussin committed 12 years ago
commit 39214d3d87b66fb38346dc1b7a49c7b8134525be
parent 1c506f8
4 files changed +607 -395
modified external/libucl/include/ucl.h
@@ -21,8 +21,8 @@
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

-
#ifndef RCL_H_
-
#define RCL_H_
+
#ifndef UCL_H_
+
#define UCL_H_

#include <string.h>
#include <stddef.h>
@@ -33,34 +33,29 @@
#include <stdio.h>

/**
-
 * @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
+
 * @mainpage
+
 * This is a reference manual for UCL API. You may find the description of UCL format by following this
+
 * [github repository](https://github.com/vstakhov/libucl).
+
 *
+
 * This manual has several main sections:
+
 *  - @ref structures
+
 *  - @ref utils
+
 *  - @ref parser
+
 *  - @ref emitter
 */

/**
-
 * XXX: Poorly named API functions, need to replace them with the appropriate
-
 * named function. All API functions *must* use naming ucl_object_*. Usage of
-
 * ucl_obj* should be avoided.
+
 * @file ucl.h
+
 * @brief UCL parsing and emitting functions
+
 *
+
 * UCL is universal configuration language, which is a form of
+
 * JSON with less strict rules that make it more comfortable for
+
 * using as a configuration language
 */
-
#define ucl_object_todouble_safe ucl_obj_todouble_safe
-
#define ucl_object_todouble ucl_obj_todouble
-
#define ucl_object_tostring ucl_obj_tostring
-
#define ucl_object_tostring_safe ucl_obj_tostring_safe
-
#define ucl_object_tolstring ucl_obj_tolstring
-
#define ucl_object_tolstring_safe ucl_obj_tolstring_safe
-
#define ucl_object_toint ucl_obj_toint
-
#define ucl_object_toint_safe ucl_obj_toint_safe
-
#define ucl_object_toboolean ucl_obj_toboolean
-
#define ucl_object_toboolean_safe ucl_obj_toboolean_safe
-
#define ucl_object_find_key ucl_obj_get_key
-
#define ucl_object_find_keyl ucl_obj_get_keyl
-
#define ucl_object_unref ucl_obj_unref
-
#define ucl_object_ref ucl_obj_ref
-
#define ucl_object_free ucl_obj_free
-

-
/**
+
#ifdef  __cplusplus
+
extern "C" {
+
#endif
+
/*
 * Memory allocation utilities
 * UCL_ALLOC(size) - allocate memory for UCL
 * UCL_FREE(size, ptr) - free memory of specified size at ptr
@@ -80,101 +75,127 @@
#define UCL_WARN_UNUSED_RESULT
#endif

-
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
-
};
+
/**
+
 * @defgroup structures Structures and types
+
 * UCL defines several enumeration types used for error reporting or specifying flags and attributes.
+
 *
+
 * @{
+
 */

/**
-
 * Object types
+
 * The common error codes returned by ucl parser
 */
-
enum ucl_type {
-
	UCL_OBJECT = 0,//!< UCL_OBJECT
-
	UCL_ARRAY,     //!< UCL_ARRAY
-
	UCL_INT,       //!< UCL_INT
-
	UCL_FLOAT,     //!< UCL_FLOAT
-
	UCL_STRING,    //!< UCL_STRING
-
	UCL_BOOLEAN,   //!< UCL_BOOLEAN
-
	UCL_TIME,      //!< UCL_TIME
-
	UCL_USERDATA,  //!< UCL_USERDATA
-
	UCL_NULL       //!< UCL_NULL
-
};
+
typedef enum ucl_error {
+
	UCL_EOK = 0, /**< No error */
+
	UCL_ESYNTAX, /**< Syntax error occurred during parsing */
+
	UCL_EIO, /**< IO error occurred during parsing */
+
	UCL_ESTATE, /**< Invalid state machine state */
+
	UCL_ENESTED, /**< Input has too many recursion levels */
+
	UCL_EMACRO, /**< Error processing a macro */
+
	UCL_EINTERNAL, /**< Internal unclassified error */
+
	UCL_ESSL /**< SSL error */
+
} ucl_error_t;

/**
-
 * Emitting types
+
 * #ucl_object_t may have one of specified types, some types are compatible with each other and some are not.
+
 * For example, you can always convert #UCL_TIME to #UCL_FLOAT. Also you can convert #UCL_FLOAT to #UCL_INTEGER
+
 * by loosing floating point. Every object may be converted to a string by #ucl_object_tostring_forced() function.
+
 *
 */
-
enum ucl_emitter {
-
	UCL_EMIT_JSON = 0,    //!< UCL_EMIT_JSON
-
	UCL_EMIT_JSON_COMPACT,//!< UCL_EMIT_JSON_COMPACT
-
	UCL_EMIT_CONFIG,      //!< UCL_EMIT_CONFIG
-
	UCL_EMIT_YAML         //!< UCL_EMIT_YAML
-
};
+
typedef enum ucl_type {
+
	UCL_OBJECT = 0, /**< UCL object - key/value pairs */
+
	UCL_ARRAY, /**< UCL array */
+
	UCL_INT, /**< Integer number */
+
	UCL_FLOAT, /**< Floating point number */
+
	UCL_STRING, /**< Null terminated string */
+
	UCL_BOOLEAN, /**< Boolean value */
+
	UCL_TIME, /**< Time value (floating point number of seconds) */
+
	UCL_USERDATA, /**< Opaque userdata pointer (may be used in macros) */
+
	UCL_NULL /**< Null value */
+
} ucl_type_t;

/**
-
 * Parsing flags
+
 * You can use one of these types to serialise #ucl_object_t by using ucl_object_emit().
 */
-
enum ucl_parser_flags {
-
	UCL_PARSER_KEY_LOWERCASE = 0x1,//!< UCL_FLAG_KEY_LOWERCASE
-
	UCL_PARSER_ZEROCOPY = 0x2      //!< UCL_FLAG_ZEROCOPY
-
};
+
typedef enum ucl_emitter {
+
	UCL_EMIT_JSON = 0, /**< Emit fine formatted JSON */
+
	UCL_EMIT_JSON_COMPACT, /**< Emit compacted JSON */
+
	UCL_EMIT_CONFIG, /**< Emit human readable config format */
+
	UCL_EMIT_YAML /**< Emit embedded YAML format */
+
} ucl_emitter_t;

/**
-
 * String conversion flags
+
 * These flags defines parser behaviour. If you specify #UCL_PARSER_ZEROCOPY you must ensure
+
 * that the input memory is not freed if an object is in use. Moreover, if you want to use
+
 * zero-terminated keys and string values then you should not use zero-copy mode, as in this case
+
 * UCL still has to perform copying implicitly.
 */
-
enum ucl_string_flags {
-
	UCL_STRING_ESCAPE = 0x1,  /**< UCL_STRING_ESCAPE perform JSON escape */
-
	UCL_STRING_TRIM = 0x2,    /**< UCL_STRING_TRIM trim leading and trailing whitespaces */
-
	UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */
-
	UCL_STRING_PARSE_INT = 0x8,    /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */
-
	UCL_STRING_PARSE_DOUBLE = 0x10,    /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */
+
typedef enum ucl_parser_flags {
+
	UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
+
	UCL_PARSER_ZEROCOPY = 0x2 /**< Parse input in zero-copy mode if possible */
+
} ucl_parser_flags_t;
+

+
/**
+
 * String conversion flags, that are used in #ucl_object_fromstring_common function.
+
 */
+
typedef enum ucl_string_flags {
+
	UCL_STRING_ESCAPE = 0x1,  /**< Perform JSON escape */
+
	UCL_STRING_TRIM = 0x2,    /**< Trim leading and trailing whitespaces */
+
	UCL_STRING_PARSE_BOOLEAN = 0x4,    /**< Parse passed string and detect boolean */
+
	UCL_STRING_PARSE_INT = 0x8,    /**< Parse passed string and detect integer number */
+
	UCL_STRING_PARSE_DOUBLE = 0x10,    /**< Parse passed string and detect integer or float number */
	UCL_STRING_PARSE_NUMBER =  UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE ,  /**<
-
									UCL_STRING_PARSE_NUMBER parse passed string and detect number */
+
									Parse passed string and detect number */
	UCL_STRING_PARSE =  UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER,   /**<
-
									UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */
+
									Parse passed string (and detect booleans and numbers) */
	UCL_STRING_PARSE_BYTES = 0x20  /**< Treat numbers as bytes */
-
};
+
} ucl_string_flags_t;

/**
 * Basic flags for an object
 */
-
enum ucl_object_flags {
-
	UCL_OBJECT_ALLOCATED_KEY = 1, //!< UCL_OBJECT_ALLOCATED_KEY
-
	UCL_OBJECT_ALLOCATED_VALUE = 2, //!< UCL_OBJECT_ALLOCATED_VALUE
-
	UCL_OBJECT_NEED_KEY_ESCAPE = 4 //!< UCL_OBJECT_NEED_KEY_ESCAPE
-
};
+
typedef enum ucl_object_flags {
+
	UCL_OBJECT_ALLOCATED_KEY = 1, /**< An object has key allocated internally */
+
	UCL_OBJECT_ALLOCATED_VALUE = 2, /**< An object has a string value allocated internally */
+
	UCL_OBJECT_NEED_KEY_ESCAPE = 4 /**< The key of an object need to be escaped on output */
+
} ucl_object_flags_t;

/**
-
 * UCL object
+
 * UCL object structure. Please mention that the most of fields should not be touched by
+
 * UCL users. In future, this structure may be converted to private one.
 */
typedef struct ucl_object_s {
+
	/**
+
	 * Variant value type
+
	 */
	union {
-
		int64_t iv;							/**< int value of an object */
-
		const char *sv;					/**< string value of an object */
-
		double dv;							/**< double value of an object */
-
		struct ucl_object_s *av;			/**< array					*/
-
		void *ov;							/**< object					*/
-
		void* ud;							/**< opaque user data		*/
+
		int64_t iv;							/**< Int value of an object */
+
		const char *sv;					/**< String value of an object */
+
		double dv;							/**< Double value of an object */
+
		struct ucl_object_s *av;			/**< Array					*/
+
		void *ov;							/**< Object					*/
+
		void* ud;							/**< Opaque user data		*/
	} value;
-
	const char *key;						/**< key of an object		*/
-
	struct ucl_object_s *next;				/**< array handle			*/
-
	struct ucl_object_s *prev;				/**< array handle			*/
-
	unsigned char* trash_stack[2];			/**< pointer to allocated chunks */
-
	unsigned keylen;						/**< lenght of a key		*/
-
	unsigned len;							/**< size of an object		*/
-
	enum ucl_type type;						/**< real type				*/
-
	uint16_t ref;							/**< reference count		*/
-
	uint16_t flags;							/**< object flags			*/
+
	const char *key;						/**< Key of an object		*/
+
	struct ucl_object_s *next;				/**< Array handle			*/
+
	struct ucl_object_s *prev;				/**< Array handle			*/
+
	unsigned char* trash_stack[2];			/**< Pointer to allocated chunks */
+
	unsigned keylen;						/**< Lenght of a key		*/
+
	unsigned len;							/**< Size of an object		*/
+
	enum ucl_type type;						/**< Real type				*/
+
	uint16_t ref;							/**< Reference count		*/
+
	uint16_t flags;							/**< Object flags			*/
} ucl_object_t;

+
/** @} */

/**
+
 * @defgroup utils Utility functions
+
 * A number of utility functions simplify handling of UCL objects
+
 *
+
 * @{
+
 */
+
/**
 * Copy and return a key of an object, returned key is zero-terminated
 * @param obj CL object
 * @return zero terminated key
@@ -328,6 +349,19 @@ ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
		const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;

/**
+
 * Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed,
+
 * if no object has been found this function works like ucl_object_insert_key()
+
 * @param top destination object (will be created automatically if top is NULL)
+
 * @param elt element to insert (must NOT be NULL)
+
 * @param key key to associate with this object (either const or preallocated)
+
 * @param keylen length of the key (or 0 for NULL terminated keys)
+
 * @param copy_key make an internal copy of key
+
 * @return new value of top object
+
 */
+
ucl_object_t* ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
+
		const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;
+

+
/**
 * Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist,
 * try to merge its content
 * @param top destination object (will be created automatically if top is NULL)
@@ -409,7 +443,7 @@ ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
 * @return true if conversion was successful
 */
static inline bool
-
ucl_obj_todouble_safe (ucl_object_t *obj, double *target)
+
ucl_object_todouble_safe (ucl_object_t *obj, double *target)
{
	if (obj == NULL) {
		return false;
@@ -435,7 +469,7 @@ ucl_obj_todouble_safe (ucl_object_t *obj, double *target)
 * @return double value
 */
static inline double
-
ucl_obj_todouble (ucl_object_t *obj)
+
ucl_object_todouble (ucl_object_t *obj)
{
	double result = 0.;

@@ -450,7 +484,7 @@ ucl_obj_todouble (ucl_object_t *obj)
 * @return true if conversion was successful
 */
static inline bool
-
ucl_obj_toint_safe (ucl_object_t *obj, int64_t *target)
+
ucl_object_toint_safe (ucl_object_t *obj, int64_t *target)
{
	if (obj == NULL) {
		return false;
@@ -476,7 +510,7 @@ ucl_obj_toint_safe (ucl_object_t *obj, int64_t *target)
 * @return int value
 */
static inline int64_t
-
ucl_obj_toint (ucl_object_t *obj)
+
ucl_object_toint (ucl_object_t *obj)
{
	int64_t result = 0;

@@ -491,7 +525,7 @@ ucl_obj_toint (ucl_object_t *obj)
 * @return true if conversion was successful
 */
static inline bool
-
ucl_obj_toboolean_safe (ucl_object_t *obj, bool *target)
+
ucl_object_toboolean_safe (ucl_object_t *obj, bool *target)
{
	if (obj == NULL) {
		return false;
@@ -513,7 +547,7 @@ ucl_obj_toboolean_safe (ucl_object_t *obj, bool *target)
 * @return boolean value
 */
static inline bool
-
ucl_obj_toboolean (ucl_object_t *obj)
+
ucl_object_toboolean (ucl_object_t *obj)
{
	bool result = false;

@@ -528,7 +562,7 @@ ucl_obj_toboolean (ucl_object_t *obj)
 * @return true if conversion was successful
 */
static inline bool
-
ucl_obj_tostring_safe (ucl_object_t *obj, const char **target)
+
ucl_object_tostring_safe (ucl_object_t *obj, const char **target)
{
	if (obj == NULL) {
		return false;
@@ -551,7 +585,7 @@ ucl_obj_tostring_safe (ucl_object_t *obj, const char **target)
 * @return string value
 */
static inline const char *
-
ucl_obj_tostring (ucl_object_t *obj)
+
ucl_object_tostring (ucl_object_t *obj)
{
	const char *result = NULL;

@@ -571,15 +605,15 @@ ucl_object_tostring_forced (ucl_object_t *obj)
}

/**
-
 * Return string as char * and len, string may be not zero terminated, more efficient that tostring as it
-
 * allows zero-copy
+
 * Return string as char * and len, string may be not zero terminated, more efficient that \ref ucl_obj_tostring as it
+
 * allows zero-copy (if #UCL_PARSER_ZEROCOPY has been used during parsing)
 * @param obj CL object
 * @param target target string variable, no need to free value
 * @param tlen target length
 * @return true if conversion was successful
 */
static inline bool
-
ucl_obj_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
+
ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
{
	if (obj == NULL) {
		return false;
@@ -602,7 +636,7 @@ ucl_obj_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
 * @return string value
 */
static inline const char *
-
ucl_obj_tolstring (ucl_object_t *obj, size_t *tlen)
+
ucl_object_tolstring (ucl_object_t *obj, size_t *tlen)
{
	const char *result = NULL;

@@ -616,7 +650,7 @@ ucl_obj_tolstring (ucl_object_t *obj, size_t *tlen)
 * @param key key to search
 * @return object matched the specified key or NULL if key is not found
 */
-
ucl_object_t * ucl_obj_get_key (ucl_object_t *obj, const char *key);
+
ucl_object_t * ucl_object_find_key (ucl_object_t *obj, const char *key);

/**
 * Return object identified by a fixed size key in the specified object
@@ -625,7 +659,7 @@ ucl_object_t * ucl_obj_get_key (ucl_object_t *obj, const char *key);
 * @param klen length of a key
 * @return object matched the specified key or NULL if key is not found
 */
-
ucl_object_t *ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen);
+
ucl_object_t *ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen);

/**
 * Returns a key of an object as a NULL terminated string
@@ -652,6 +686,56 @@ ucl_object_keyl (ucl_object_t *obj, size_t *len)
}

/**
+
 * Free ucl object
+
 * @param obj ucl object to free
+
 */
+
void ucl_object_free (ucl_object_t *obj);
+

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

+
/**
+
 * Decrease reference count for an object
+
 * @param obj object to unref
+
 */
+
static inline void
+
ucl_object_unref (ucl_object_t *obj) {
+
	if (--obj->ref <= 0) {
+
		ucl_object_free (obj);
+
	}
+
}
+
/**
+
 * Opaque iterator object
+
 */
+
typedef void* ucl_object_iter_t;
+

+
/**
+
 * Get next key from an object
+
 * @param obj object to iterate
+
 * @param iter opaque iterator, must be set to NULL on the first call:
+
 * ucl_object_iter_t it = NULL;
+
 * while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
+
 * @return the next object or NULL
+
 */
+
ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values);
+
/** @} */
+

+

+
/**
+
 * @defgroup parser Parsing functions
+
 * These functions are used to parse UCL objects
+
 *
+
 * @{
+
 */
+

+
/**
 * Macro handler for a parser
 * @param data the content of macro
 * @param len the length of content
@@ -723,48 +807,12 @@ ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
 */
const char *ucl_parser_get_error(struct ucl_parser *parser);
/**
-
 * Free cl parser object
+
 * Free ucl 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
@@ -784,16 +832,73 @@ bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t
bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename,
		bool need_expand);

-
typedef void* ucl_object_iter_t;
+
/** @} */

/**
-
 * Get next key from an object
-
 * @param obj object to iterate
-
 * @param iter opaque iterator, must be set to NULL on the first call:
-
 * ucl_object_iter_t it = NULL;
-
 * while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
-
 * @return the next object or NULL
+
 * @defgroup emitter Emitting functions
+
 * These functions are used to serialise UCL objects to some string representation.
+
 *
+
 * @{
 */
-
ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values);

-
#endif /* RCL_H_ */
+
/**
+
 * Structure using for emitter callbacks
+
 */
+
struct ucl_emitter_functions {
+
	/** Append a single character */
+
	int (*ucl_emitter_append_character) (unsigned char c, size_t nchars, void *ud);
+
	/** Append a string of a specified length */
+
	int (*ucl_emitter_append_len) (unsigned const char *str, size_t len, void *ud);
+
	/** Append a 64 bit integer */
+
	int (*ucl_emitter_append_int) (int64_t elt, void *ud);
+
	/** Append floating point element */
+
	int (*ucl_emitter_append_double) (double elt, void *ud);
+
	/** Opaque userdata pointer */
+
	void *ud;
+
};
+

+
/**
+
 * 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);
+

+
/**
+
 * 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
+
 */
+
bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
+
		struct ucl_emitter_functions *emitter);
+
/** @} */
+

+
#ifdef  __cplusplus
+
}
+
#endif
+
/*
+
 * XXX: Poorly named API functions, need to replace them with the appropriate
+
 * named function. All API functions *must* use naming ucl_object_*. Usage of
+
 * ucl_obj* should be avoided.
+
 */
+
#define ucl_obj_todouble_safe ucl_object_todouble_safe
+
#define ucl_obj_todouble ucl_object_todouble
+
#define ucl_obj_tostring ucl_object_tostring
+
#define ucl_obj_tostring_safe ucl_object_tostring_safe
+
#define ucl_obj_tolstring ucl_object_tolstring
+
#define ucl_obj_tolstring_safe ucl_object_tolstring_safe
+
#define ucl_obj_toint ucl_object_toint
+
#define ucl_obj_toint_safe ucl_object_toint_safe
+
#define ucl_obj_toboolean ucl_object_toboolean
+
#define ucl_obj_toboolean_safe ucl_object_toboolean_safe
+
#define ucl_obj_get_key ucl_object_find_key
+
#define ucl_obj_get_keyl ucl_object_find_keyl
+
#define ucl_obj_unref ucl_object_unref
+
#define ucl_obj_ref ucl_object_ref
+
#define ucl_obj_free ucl_object_free
+

+
#endif /* UCL_H_ */
modified external/libucl/src/ucl_emitter.c
@@ -29,16 +29,37 @@

/**
 * @file rcl_emitter.c
-
 * Serialise RCL object to the RCL format
+
 * Serialise UCL object to various of output formats
 */


-
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, bool expand_array);
-
static void ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
-
		bool start_tabs, bool compact, bool expand_array);
-
static void ucl_elt_array_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top);
+
static void ucl_obj_write_json (ucl_object_t *obj,
+
		struct ucl_emitter_functions *func,
+
		unsigned int tabs,
+
		bool start_tabs,
+
		bool compact);
+
static void ucl_elt_write_json (ucl_object_t *obj,
+
		struct ucl_emitter_functions *func,
+
		unsigned int tabs,
+
		bool start_tabs,
+
		bool compact);
+
static void ucl_elt_write_config (ucl_object_t *obj,
+
		struct ucl_emitter_functions *func,
+
		unsigned int tabs,
+
		bool start_tabs,
+
		bool is_top,
+
		bool expand_array);
+
static void ucl_elt_write_yaml (ucl_object_t *obj,
+
		struct ucl_emitter_functions *func,
+
		unsigned int tabs,
+
		bool start_tabs,
+
		bool compact,
+
		bool expand_array);
+
static void ucl_elt_array_write_yaml (ucl_object_t *obj,
+
		struct ucl_emitter_functions *func,
+
		unsigned int tabs,
+
		bool start_tabs,
+
		bool is_top);

/**
 * Add tabulation to the output buffer
@@ -46,21 +67,10 @@ static void ucl_elt_array_write_yaml (ucl_object_t *obj, UT_string *buf, unsigne
 * @param tabs number of tabs to add
 */
static inline void
-
ucl_add_tabs (UT_string *buf, unsigned int tabs, bool compact)
+
ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact)
{
-
	char *p;
-
	unsigned int i;
-

	if (!compact) {
-
		while (buf->n - buf->i <= tabs * 4) {
-
			utstring_reserve (buf, buf->n * 2);
-
		}
-
		p = &buf->d[buf->i];
-
		for (i = 0; i < tabs; i ++) {
-
			memset (&p[i * 4], ' ', 4);
-
		}
-
		buf->i += i * 4;
-
		buf->d[buf->i] = '\0';
+
		func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
	}
}

@@ -70,38 +80,39 @@ ucl_add_tabs (UT_string *buf, unsigned int tabs, bool compact)
 * @param buf target buffer
 */
static void
-
ucl_elt_string_write_json (const char *str, size_t size, UT_string *buf)
+
ucl_elt_string_write_json (const char *str, size_t size,
+
		struct ucl_emitter_functions *func)
{
	const char *p = str, *c = str;
	size_t len = 0;

-
	utstring_append_c (buf, '"');
+
	func->ucl_emitter_append_character ('"', 1, func->ud);
	while (size) {
		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
			if (len > 0) {
-
				utstring_append_len (buf, c, len);
+
				func->ucl_emitter_append_len (c, len, func->ud);
			}
			switch (*p) {
			case '\n':
-
				utstring_append_len (buf, "\\n", 2);
+
				func->ucl_emitter_append_len ("\\n", 2, func->ud);
				break;
			case '\r':
-
				utstring_append_len (buf, "\\r", 2);
+
				func->ucl_emitter_append_len ("\\r", 2, func->ud);
				break;
			case '\b':
-
				utstring_append_len (buf, "\\b", 2);
+
				func->ucl_emitter_append_len ("\\b", 2, func->ud);
				break;
			case '\t':
-
				utstring_append_len (buf, "\\t", 2);
+
				func->ucl_emitter_append_len ("\\t", 2, func->ud);
				break;
			case '\f':
-
				utstring_append_len (buf, "\\f", 2);
+
				func->ucl_emitter_append_len ("\\f", 2, func->ud);
				break;
			case '\\':
-
				utstring_append_len (buf, "\\\\", 2);
+
				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
				break;
			case '"':
-
				utstring_append_len (buf, "\\\"", 2);
+
				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
				break;
			}
			len = 0;
@@ -114,24 +125,9 @@ ucl_elt_string_write_json (const char *str, size_t size, UT_string *buf)
		size --;
	}
	if (len > 0) {
-
		utstring_append_len (buf, c, len);
-
	}
-
	utstring_append_c (buf, '"');
-
}
-

-
static inline void
-
ucl_print_float (UT_string *buf, double val)
-
{
-
	if (val == (double)(int)val) {
-
		utstring_printf (buf, "%.1lf", val);
-
	}
-
	else if (fabs (val - (double)(int)val) < 0.0000001) {
-
		/* Write at maximum precision */
-
		utstring_printf (buf, "%.*lg", DBL_DIG, val);
-
	}
-
	else {
-
		utstring_printf (buf, "%lf", val);
+
		func->ucl_emitter_append_len (c, len, func->ud);
	}
+
	func->ucl_emitter_append_character ('"', 1, func->ud);
}

/**
@@ -140,49 +136,50 @@ ucl_print_float (UT_string *buf, double val)
 * @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_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool compact)
{
	ucl_object_t *cur;
	ucl_hash_iter_t it = NULL;

	if (start_tabs) {
-
		ucl_add_tabs (buf, tabs, compact);
+
		ucl_add_tabs (func, tabs, compact);
	}
	if (compact) {
-
		utstring_append_c (buf, '{');
+
		func->ucl_emitter_append_character ('{', 1, func->ud);
	}
	else {
-
		utstring_append_len (buf, "{\n", 2);
+
		func->ucl_emitter_append_len ("{\n", 2, func->ud);
	}
	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
-
		ucl_add_tabs (buf, tabs + 1, compact);
+
		ucl_add_tabs (func, tabs + 1, compact);
		if (cur->keylen > 0) {
-
			ucl_elt_string_write_json (cur->key, cur->keylen, buf);
+
			ucl_elt_string_write_json (cur->key, cur->keylen, func);
		}
		else {
-
			utstring_append_len (buf, "null", 4);
+
			func->ucl_emitter_append_len ("null", 4, func->ud);
		}
		if (compact) {
-
			utstring_append_c (buf, ':');
+
			func->ucl_emitter_append_character (':', 1, func->ud);
		}
		else {
-
			utstring_append_len (buf, ": ", 2);
+
			func->ucl_emitter_append_len (": ", 2, func->ud);
		}
-
		ucl_obj_write_json (cur, buf, tabs + 1, false, compact);
+
		ucl_obj_write_json (cur, func, tabs + 1, false, compact);
		if (ucl_hash_iter_has_next (it)) {
			if (compact) {
-
				utstring_append_c (buf, ',');
+
				func->ucl_emitter_append_character (',', 1, func->ud);
			}
			else {
-
				utstring_append_len (buf, ",\n", 2);
+
				func->ucl_emitter_append_len (",\n", 2, func->ud);
			}
		}
		else if (!compact) {
-
			utstring_append_c (buf, '\n');
+
			func->ucl_emitter_append_character ('\n', 1, func->ud);
		}
	}
-
	ucl_add_tabs (buf, tabs, compact);
-
	utstring_append_c (buf, '}');
+
	ucl_add_tabs (func, tabs, compact);
+
	func->ucl_emitter_append_character ('}', 1, func->ud);
}

/**
@@ -191,36 +188,37 @@ ucl_elt_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
 * @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_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool compact)
{
	ucl_object_t *cur = obj;

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

/**
@@ -228,46 +226,55 @@ ucl_elt_array_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
 * @param obj object
 * @param buf buffer
 */
-
void
-
ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool compact)
+
static void
+
ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool compact)
{
+
	bool flag;
+

	switch (obj->type) {
	case UCL_INT:
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
		}
-
		utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
+
		func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
		break;
	case UCL_FLOAT:
	case UCL_TIME:
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
		}
-
		ucl_print_float (buf, ucl_object_todouble (obj));
+
		func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
		break;
	case UCL_BOOLEAN:
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
+
		}
+
		flag = ucl_object_toboolean (obj);
+
		if (flag) {
+
			func->ucl_emitter_append_len ("true", 4, func->ud);
+
		}
+
		else {
+
			func->ucl_emitter_append_len ("false", 5, func->ud);
		}
-
		utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
		break;
	case UCL_STRING:
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
		}
-
		ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
+
		ucl_elt_string_write_json (obj->value.sv, obj->len, func);
		break;
	case UCL_NULL:
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
		}
-
		utstring_printf (buf, "null");
+
		func->ucl_emitter_append_len ("null", 4, func->ud);
		break;
	case UCL_OBJECT:
-
		ucl_elt_obj_write_json (obj, buf, tabs, start_tabs, compact);
+
		ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact);
		break;
	case UCL_ARRAY:
-
		ucl_elt_array_write_json (obj->value.av, buf, tabs, start_tabs, compact);
+
		ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact);
		break;
	case UCL_USERDATA:
		break;
@@ -280,7 +287,8 @@ ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
 * @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_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool compact)
{
	ucl_object_t *cur;
	bool is_array = (obj->next != NULL);
@@ -288,31 +296,31 @@ ucl_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
	if (is_array) {
		/* This is an array actually */
		if (start_tabs) {
-
			ucl_add_tabs (buf, tabs, compact);
+
			ucl_add_tabs (func, tabs, compact);
		}

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

}
@@ -322,17 +330,10 @@ ucl_obj_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
 * @param obj object
 * @return json output (should be freed after using)
 */
-
static UT_string *
-
ucl_object_emit_json (ucl_object_t *obj, bool compact)
+
static void
+
ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func)
{
-
	UT_string *buf;
-

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

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

-
	return buf;
+
	ucl_obj_write_json (obj, func, 0, false, compact);
}

/**
@@ -341,46 +342,49 @@ ucl_object_emit_json (ucl_object_t *obj, bool compact)
 * @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_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top)
{
	ucl_object_t *cur, *cur_obj;
	ucl_hash_iter_t it = NULL;

	if (start_tabs) {
-
		ucl_add_tabs (buf, tabs, is_top);
+
		ucl_add_tabs (func, tabs, is_top);
	}
	if (!is_top) {
-
		utstring_append_len (buf, "{\n", 2);
+
		func->ucl_emitter_append_len ("{\n", 2, func->ud);
	}

	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
		LL_FOREACH (cur, cur_obj) {
-
			ucl_add_tabs (buf, tabs + 1, is_top);
+
			ucl_add_tabs (func, tabs + 1, is_top);
			if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
-
				ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, buf);
+
				ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func);
			}
			else {
-
				utstring_append_len (buf, cur_obj->key, cur_obj->keylen);
+
				func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud);
			}
			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
-
				utstring_append_len (buf, " = ", 3);
+
				func->ucl_emitter_append_len (" = ", 3, func->ud);
			}
			else {
-
				utstring_append_c (buf, ' ');
+
				func->ucl_emitter_append_character (' ', 1, func->ud);
			}
-
			ucl_elt_write_rcl (cur_obj, buf, is_top ? tabs : tabs + 1, false, false, false);
+
			ucl_elt_write_config (cur_obj, func,
+
					is_top ? tabs : tabs + 1,
+
					false, false, false);
			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
-
				utstring_append_len (buf, ";\n", 2);
+
				func->ucl_emitter_append_len (";\n", 2, func->ud);
			}
			else {
-
				utstring_append_c (buf, '\n');
+
				func->ucl_emitter_append_character ('\n', 1, func->ud);
			}
		}
	}

-
	ucl_add_tabs (buf, tabs, is_top);
+
	ucl_add_tabs (func, tabs, is_top);
	if (!is_top) {
-
		utstring_append_c (buf, '}');
+
		func->ucl_emitter_append_character ('}', 1, func->ud);
	}
}

@@ -390,22 +394,23 @@ ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, boo
 * @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_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top)
{
	ucl_object_t *cur = obj;

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

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

/**
@@ -414,50 +419,58 @@ ucl_elt_array_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, b
 * @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, bool expand_array)
+
ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
{
+
	bool flag;
+

	if (expand_array && obj->next != NULL) {
-
		ucl_elt_array_write_rcl (obj, buf, tabs, start_tabs, is_top);
+
		ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top);
	}
	else {
		switch (obj->type) {
		case UCL_INT:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
+
			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
			break;
		case UCL_FLOAT:
		case UCL_TIME:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			ucl_print_float (buf, ucl_object_todouble (obj));
+
			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
			break;
		case UCL_BOOLEAN:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
+
			}
+
			flag = ucl_object_toboolean (obj);
+
			if (flag) {
+
				func->ucl_emitter_append_len ("true", 4, func->ud);
+
			}
+
			else {
+
				func->ucl_emitter_append_len ("false", 5, func->ud);
			}
-
			utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
			break;
		case UCL_STRING:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
+
			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
			break;
		case UCL_NULL:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			utstring_printf (buf, "null");
+
			func->ucl_emitter_append_len ("null", 4, func->ud);
			break;
		case UCL_OBJECT:
-
			ucl_elt_obj_write_rcl (obj, buf, tabs, start_tabs, is_top);
+
			ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top);
			break;
		case UCL_ARRAY:
-
			ucl_elt_array_write_rcl (obj->value.av, buf, tabs, start_tabs, is_top);
+
			ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top);
			break;
		case UCL_USERDATA:
			break;
@@ -470,30 +483,24 @@ ucl_elt_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
 * @param obj object
 * @return rcl output (should be freed after using)
 */
-
static UT_string *
-
ucl_object_emit_rcl (ucl_object_t *obj)
+
static void
+
ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func)
{
-
	UT_string *buf;
-

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

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

-
	return buf;
+
	ucl_elt_write_config (obj, func, 0, false, true, true);
}


static void
-
ucl_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs)
+
ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs)
{
	bool is_array = (obj->next != NULL);

	if (is_array) {
-
		ucl_elt_array_write_yaml (obj, buf, tabs, start_tabs, false);
+
		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false);
	}
	else {
-
		ucl_elt_write_yaml(obj, buf, tabs, start_tabs, false, true);
+
		ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true);
	}
}

@@ -503,44 +510,45 @@ ucl_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool s
 * @param buf target buffer
 */
static void
-
ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
+
ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top)
{
	ucl_object_t *cur;
	ucl_hash_iter_t it = NULL;

	if (start_tabs) {
-
		ucl_add_tabs (buf, tabs, is_top);
+
		ucl_add_tabs (func, tabs, is_top);
	}
	if (!is_top) {
-
		utstring_append_len (buf, "{\n", 2);
+
		func->ucl_emitter_append_len ("{\n", 2, func->ud);
	}

	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
-
		ucl_add_tabs (buf, tabs + 1, is_top);
+
		ucl_add_tabs (func, tabs + 1, is_top);
		if (cur->keylen > 0) {
-
			ucl_elt_string_write_json (cur->key, cur->keylen, buf);
+
			ucl_elt_string_write_json (cur->key, cur->keylen, func);
		}
		else {
-
			utstring_append_len (buf, "null", 4);
+
			func->ucl_emitter_append_len ("null", 4, func->ud);
		}
-
		utstring_append_len(buf, ": ", 2);
-
		ucl_obj_write_yaml (cur, buf, is_top ? tabs : tabs + 1, false);
+
		func->ucl_emitter_append_len (": ", 2, func->ud);
+
		ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false);
		if (ucl_hash_iter_has_next(it)) {
			if (!is_top) {
-
				utstring_append_len (buf, ",\n", 2);
+
				func->ucl_emitter_append_len (",\n", 2, func->ud);
			}
			else {
-
				utstring_append_c (buf, '\n');
+
				func->ucl_emitter_append_character ('\n', 1, func->ud);
			}
		}
		else {
-
			utstring_append_c (buf, '\n');
+
			func->ucl_emitter_append_character ('\n', 1, func->ud);
		}
	}

-
	ucl_add_tabs (buf, tabs, is_top);
+
	ucl_add_tabs (func, tabs, is_top);
	if (!is_top) {
-
		utstring_append_c (buf, '}');
+
		func->ucl_emitter_append_character ('}', 1, func->ud);
	}
}

@@ -550,22 +558,23 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo
 * @param buf target buffer
 */
static void
-
ucl_elt_array_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bool start_tabs, bool is_top)
+
ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top)
{
	ucl_object_t *cur = obj;

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

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

/**
@@ -574,50 +583,58 @@ ucl_elt_array_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
 * @param buf buffer
 */
static void
-
ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
-
		bool start_tabs, bool is_top, bool expand_array)
+
ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
+
		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
{
-
	if (expand_array && obj->next != NULL) {
-
		ucl_elt_array_write_yaml (obj, buf, tabs, start_tabs, is_top);
-
		}
+
	bool flag;
+

+
	if (expand_array && obj->next != NULL ) {
+
		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top);
+
	}
	else {
		switch (obj->type) {
		case UCL_INT:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			utstring_printf (buf, "%jd", (intmax_t)ucl_object_toint (obj));
+
			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
			break;
		case UCL_FLOAT:
		case UCL_TIME:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			ucl_print_float (buf, ucl_object_todouble (obj));
+
			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
			break;
		case UCL_BOOLEAN:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
+
			}
+
			flag = ucl_object_toboolean (obj);
+
			if (flag) {
+
				func->ucl_emitter_append_len ("true", 4, func->ud);
+
			}
+
			else {
+
				func->ucl_emitter_append_len ("false", 5, func->ud);
			}
-
			utstring_printf (buf, "%s", ucl_object_toboolean (obj) ? "true" : "false");
			break;
		case UCL_STRING:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			ucl_elt_string_write_json (obj->value.sv, obj->len, buf);
+
			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
			break;
		case UCL_NULL:
			if (start_tabs) {
-
				ucl_add_tabs (buf, tabs, false);
+
				ucl_add_tabs (func, tabs, false);
			}
-
			utstring_printf (buf, "null");
+
			func->ucl_emitter_append_len ("null", 4, func->ud);
			break;
		case UCL_OBJECT:
-
			ucl_elt_obj_write_yaml (obj, buf, tabs, start_tabs, is_top);
+
			ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top);
			break;
		case UCL_ARRAY:
-
			ucl_elt_array_write_yaml (obj->value.av, buf, tabs, start_tabs, is_top);
+
			ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top);
			break;
		case UCL_USERDATA:
			break;
@@ -630,46 +647,129 @@ ucl_elt_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
 * @param obj object
 * @return rcl output (should be freed after using)
 */
-
static UT_string *
-
ucl_object_emit_yaml (ucl_object_t *obj)
+
static void
+
ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func)
{
-
	UT_string *buf;
+
	ucl_elt_write_yaml (obj, func, 0, false, true, true);
+
}

-
	/* Allocate large enough buffer */
-
	utstring_new (buf);
+
/*
+
 * Generic utstring output
+
 */
+
static int
+
ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
+
{
+
	UT_string *buf = ud;

-
	ucl_elt_write_yaml (obj, buf, 0, false, true, true);
+
	if (len == 1) {
+
		utstring_append_c (buf, c);
+
	}
+
	else {
+
		utstring_reserve (buf, len);
+
		memset (&buf->d[buf->i], c, len);
+
		buf->i += len;
+
		buf->d[buf->i] = '\0';
+
	}
+

+
	return 0;
+
}
+

+
static int
+
ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
+
{
+
	UT_string *buf = ud;
+

+
	utstring_append_len (buf, str, len);
+

+
	return 0;
+
}
+

+
static int
+
ucl_utstring_append_int (int64_t val, void *ud)
+
{
+
	UT_string *buf = ud;
+

+
	utstring_printf (buf, "%jd", (intmax_t)val);
+
	return 0;
+
}
+

+
static int
+
ucl_utstring_append_double (double val, void *ud)
+
{
+
	UT_string *buf = ud;
+
	const double delta = 0.0000001;
+

+
	if (val == (double)(int)val) {
+
		utstring_printf (buf, "%.1lf", val);
+
	}
+
	else if (fabs (val - (double)(int)val) < delta) {
+
		/* Write at maximum precision */
+
		utstring_printf (buf, "%.*lg", DBL_DIG, val);
+
	}
+
	else {
+
		utstring_printf (buf, "%lf", val);
+
	}

-
	return buf;
+
	return 0;
}

+

unsigned char *
ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
{
	UT_string *buf = NULL;
	unsigned char *res = NULL;
+
	struct ucl_emitter_functions func = {
+
		.ucl_emitter_append_character = ucl_utstring_append_character,
+
		.ucl_emitter_append_len = ucl_utstring_append_len,
+
		.ucl_emitter_append_int = ucl_utstring_append_int,
+
		.ucl_emitter_append_double = ucl_utstring_append_double
+
	};

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

+
	utstring_new (buf);
+
	func.ud = buf;
+

+
	if (buf != NULL) {
+
		if (emit_type == UCL_EMIT_JSON) {
+
			ucl_object_emit_json (obj, false, &func);
+
		}
+
		else if (emit_type == UCL_EMIT_JSON_COMPACT) {
+
			ucl_object_emit_json (obj, true, &func);
+
		}
+
		else if (emit_type == UCL_EMIT_YAML) {
+
			ucl_object_emit_yaml (obj, &func);
+
		}
+
		else {
+
			ucl_object_emit_config (obj, &func);
+
		}
+

+
		res = utstring_body (buf);
+
		free (buf);
+
	}
+

+
	return res;
+
}
+

+
bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
+
		struct ucl_emitter_functions *emitter)
+
{
	if (emit_type == UCL_EMIT_JSON) {
-
		buf = ucl_object_emit_json (obj, false);
+
		ucl_object_emit_json (obj, false, emitter);
	}
	else if (emit_type == UCL_EMIT_JSON_COMPACT) {
-
		buf = ucl_object_emit_json (obj, true);
+
		ucl_object_emit_json (obj, true, emitter);
	}
	else if (emit_type == UCL_EMIT_YAML) {
-
		buf = ucl_object_emit_yaml (obj);
+
		ucl_object_emit_yaml (obj, emitter);
	}
	else {
-
		buf = ucl_object_emit_rcl (obj);
+
		ucl_object_emit_config (obj, emitter);
	}

-
	if (buf != NULL) {
-
		res = utstring_body (buf);
-
		free (buf);
-
	}
-

-
	return res;
+
	/* XXX: need some error checks here */
+
	return true;
}
modified external/libucl/src/ucl_internal.h
@@ -174,9 +174,6 @@ size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);


-
void ucl_elt_write_json (ucl_object_t *obj, UT_string *buf, unsigned int tabs,
-
		bool start_tabs, bool compact);
-

#ifdef __GNUC__
static inline void
ucl_create_err (UT_string **err, const char *fmt, ...)
modified external/libucl/src/ucl_util.c
@@ -78,7 +78,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
}

void
-
ucl_obj_free (ucl_object_t *obj)
+
ucl_object_free (ucl_object_t *obj)
{
	ucl_object_free_internal (obj, true);
}
@@ -196,7 +196,6 @@ ucl_copy_key_trash (ucl_object_t *obj)
char *
ucl_copy_value_trash (ucl_object_t *obj)
{
-
	UT_string *emitted;
	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
		if (obj->type == UCL_STRING) {
			/* Special case for strings */
@@ -209,14 +208,9 @@ ucl_copy_value_trash (ucl_object_t *obj)
		}
		else {
			/* Just emit value in json notation */
-
			utstring_new (emitted);
-

-
			if (emitted != NULL) {
-
				ucl_elt_write_json (obj, emitted, 0, 0, true);
-
				obj->trash_stack[UCL_TRASH_VALUE] = emitted->d;
-
				obj->len = emitted->i;
-
				free (emitted);
-
			}
+
			obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit (obj,
+
					UCL_EMIT_JSON_COMPACT);
+
			obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
		}
		obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
	}
@@ -943,7 +937,7 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags

static ucl_object_t *
ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
-
		const char *key, size_t keylen, bool copy_key, bool merge)
+
		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
{
	ucl_object_t *found, *cur;
	ucl_object_iter_t it = NULL;
@@ -997,30 +991,39 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
		DL_APPEND (found, elt);
	}
-
	else if (!merge) {
-
		DL_APPEND (found, elt);
-
	}
	else {
-
		if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
-
			/* Insert old elt to new one */
-
			elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false);
+
		if (replace) {
			ucl_hash_delete (top->value.ov, found);
+
			ucl_object_unref (found);
			top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
+
			found = NULL;
+
			DL_APPEND (found, elt);
		}
-
		else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
-
			/* Insert new to old */
-
			found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false);
-
		}
-
		else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
-
			/* Mix two hashes */
-
			while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
-
				ucl_object_ref (cur);
-
				found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false);
+
		else if (merge) {
+
			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
+
				/* Insert old elt to new one */
+
				elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false);
+
				ucl_hash_delete (top->value.ov, found);
+
				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
+
			}
+
			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
+
				/* Insert new to old */
+
				found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false);
+
			}
+
			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
+
				/* Mix two hashes */
+
				while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
+
					ucl_object_ref (cur);
+
					found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false);
+
				}
+
				ucl_object_unref (elt);
+
			}
+
			else {
+
				/* Just make a list of scalars */
+
				DL_APPEND (found, elt);
			}
-
			ucl_object_unref (elt);
		}
		else {
-
			/* Just make a list of scalars */
			DL_APPEND (found, elt);
		}
	}
@@ -1032,18 +1035,25 @@ ucl_object_t *
ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
		const char *key, size_t keylen, bool copy_key)
{
-
	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false);
+
	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
}

ucl_object_t *
ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
		const char *key, size_t keylen, bool copy_key)
{
-
	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true);
+
	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
+
}
+

+
ucl_object_t *
+
ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
+
		const char *key, size_t keylen, bool copy_key)
+
{
+
	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
}

ucl_object_t *
-
ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen)
+
ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen)
{
	ucl_object_t *ret, srch;

@@ -1059,7 +1069,7 @@ ucl_obj_get_keyl (ucl_object_t *obj, const char *key, size_t klen)
}

ucl_object_t *
-
ucl_obj_get_key (ucl_object_t *obj, const char *key)
+
ucl_object_find_key (ucl_object_t *obj, const char *key)
{
	size_t klen;
	ucl_object_t *ret, srch;