summaryrefslogtreecommitdiffstats
path: root/contrib/libucl/src
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2014-07-18 06:58:01 +0000
committerbapt <bapt@FreeBSD.org>2014-07-18 06:58:01 +0000
commit2c479407e0afce2c05606d6d9c052858196fcea2 (patch)
tree96497f945ddb4dfe861d3b28b15907997f8d7e30 /contrib/libucl/src
parentd8612e9432a6a6bdeb374817db86445640e36cd4 (diff)
parentf900132171b58516e797b158ec4ae0f93501bed4 (diff)
downloadFreeBSD-src-2c479407e0afce2c05606d6d9c052858196fcea2.zip
FreeBSD-src-2c479407e0afce2c05606d6d9c052858196fcea2.tar.gz
Update libucl to the 2014-07-16 snapshot
This update brings streamlined ucl emitter support
Diffstat (limited to 'contrib/libucl/src')
-rw-r--r--contrib/libucl/src/Makefile.am2
-rw-r--r--contrib/libucl/src/ucl_emitter.c934
-rw-r--r--contrib/libucl/src/ucl_emitter_streamline.c166
-rw-r--r--contrib/libucl/src/ucl_emitter_utils.c466
-rw-r--r--contrib/libucl/src/ucl_internal.h16
-rw-r--r--contrib/libucl/src/ucl_parser.c13
6 files changed, 944 insertions, 653 deletions
diff --git a/contrib/libucl/src/Makefile.am b/contrib/libucl/src/Makefile.am
index 76391cd..417d34e 100644
--- a/contrib/libucl/src/Makefile.am
+++ b/contrib/libucl/src/Makefile.am
@@ -4,6 +4,8 @@ libucl_common_cflags= -I$(top_srcdir)/src \
-Wall -W -Wno-unused-parameter -Wno-pointer-sign
lib_LTLIBRARIES= libucl.la
libucl_la_SOURCES= ucl_emitter.c \
+ ucl_emitter_streamline.c \
+ ucl_emitter_utils.c \
ucl_hash.c \
ucl_parser.c \
ucl_schema.c \
diff --git a/contrib/libucl/src/ucl_emitter.c b/contrib/libucl/src/ucl_emitter.c
index 04c3d4b..11fe50c 100644
--- a/contrib/libucl/src/ucl_emitter.c
+++ b/contrib/libucl/src/ucl_emitter.c
@@ -36,38 +36,55 @@
#endif
/**
- * @file rcl_emitter.c
+ * @file ucl_emitter.c
* Serialise UCL object to various of output formats
*/
+static void ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool first, bool print_key, bool compact);
+
+#define UCL_EMIT_TYPE_OPS(type) \
+ static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool first, bool print_key); \
+ static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool print_key); \
+ static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool print_key); \
+ static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj); \
+ static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj)
+
+/*
+ * JSON format operations
+ */
+UCL_EMIT_TYPE_OPS(json);
+UCL_EMIT_TYPE_OPS(json_compact);
+UCL_EMIT_TYPE_OPS(config);
+UCL_EMIT_TYPE_OPS(yaml);
+
+#define UCL_EMIT_TYPE_CONTENT(type) { \
+ .ucl_emitter_write_elt = ucl_emit_ ## type ## _elt, \
+ .ucl_emitter_start_object = ucl_emit_ ## type ##_start_obj, \
+ .ucl_emitter_start_array = ucl_emit_ ## type ##_start_array, \
+ .ucl_emitter_end_object = ucl_emit_ ## type ##_end_object, \
+ .ucl_emitter_end_array = ucl_emit_ ## type ##_end_array \
+}
+
+
+const struct ucl_emitter_operations ucl_standartd_emitter_ops[] = {
+ [UCL_EMIT_JSON] = UCL_EMIT_TYPE_CONTENT(json),
+ [UCL_EMIT_JSON_COMPACT] = UCL_EMIT_TYPE_CONTENT(json_compact),
+ [UCL_EMIT_CONFIG] = UCL_EMIT_TYPE_CONTENT(config),
+ [UCL_EMIT_YAML] = UCL_EMIT_TYPE_CONTENT(yaml)
+};
+
+/*
+ * Utility to check whether we need a top object
+ */
+#define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \
+ ((ctx)->id == UCL_EMIT_JSON_COMPACT || (ctx)->id == UCL_EMIT_JSON))
-static void ucl_obj_write_json (const ucl_object_t *obj,
- struct ucl_emitter_functions *func,
- unsigned int tabs,
- bool start_tabs,
- bool compact);
-static void ucl_elt_write_json (const ucl_object_t *obj,
- struct ucl_emitter_functions *func,
- unsigned int tabs,
- bool start_tabs,
- bool compact);
-static void ucl_elt_write_config (const 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 (const 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 (const ucl_object_t *obj,
- struct ucl_emitter_functions *func,
- unsigned int tabs,
- bool start_tabs,
- bool is_top);
/**
* Add tabulation to the output buffer
@@ -75,689 +92,358 @@ static void ucl_elt_array_write_yaml (const ucl_object_t *obj,
* @param tabs number of tabs to add
*/
static inline void
-ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact)
+ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs,
+ bool compact)
{
- if (!compact) {
+ if (!compact && tabs > 0) {
func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
}
}
/**
- * Serialise string
- * @param str string to emit
- * @param buf target buffer
+ * Print key for the element
+ * @param ctx
+ * @param obj
*/
static void
-ucl_elt_string_write_json (const char *str, size_t size,
- struct ucl_emitter_functions *func)
+ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool compact)
{
- const char *p = str, *c = str;
- size_t len = 0;
-
- func->ucl_emitter_append_character ('"', 1, func->ud);
- while (size) {
- if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
- if (len > 0) {
- func->ucl_emitter_append_len (c, len, func->ud);
- }
- switch (*p) {
- case '\n':
- func->ucl_emitter_append_len ("\\n", 2, func->ud);
- break;
- case '\r':
- func->ucl_emitter_append_len ("\\r", 2, func->ud);
- break;
- case '\b':
- func->ucl_emitter_append_len ("\\b", 2, func->ud);
- break;
- case '\t':
- func->ucl_emitter_append_len ("\\t", 2, func->ud);
- break;
- case '\f':
- func->ucl_emitter_append_len ("\\f", 2, func->ud);
- break;
- case '\\':
- func->ucl_emitter_append_len ("\\\\", 2, func->ud);
- break;
- case '"':
- func->ucl_emitter_append_len ("\\\"", 2, func->ud);
- break;
- }
- len = 0;
- c = ++p;
+ const struct ucl_emitter_functions *func = ctx->func;
+
+ if (!print_key) {
+ return;
+ }
+
+ if (ctx->id == UCL_EMIT_CONFIG) {
+ if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
+ ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
}
else {
- p ++;
- len ++;
+ func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
}
- size --;
- }
- if (len > 0) {
- func->ucl_emitter_append_len (c, len, func->ud);
- }
- func->ucl_emitter_append_character ('"', 1, func->ud);
-}
-/**
- * Write a single object to the buffer
- * @param obj object to write
- * @param buf target buffer
- */
-static void
-ucl_elt_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool compact)
-{
- const ucl_object_t *cur;
- ucl_hash_iter_t it = NULL;
-
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
- }
- if (compact) {
- func->ucl_emitter_append_character ('{', 1, func->ud);
+ if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
+ func->ucl_emitter_append_len (" = ", 3, func->ud);
+ }
+ else {
+ func->ucl_emitter_append_character (' ', 1, func->ud);
+ }
}
else {
- func->ucl_emitter_append_len ("{\n", 2, func->ud);
- }
- while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
- ucl_add_tabs (func, tabs + 1, compact);
- if (cur->keylen > 0) {
- ucl_elt_string_write_json (cur->key, cur->keylen, func);
+ if (obj->keylen > 0) {
+ ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
}
else {
func->ucl_emitter_append_len ("null", 4, func->ud);
}
+
if (compact) {
func->ucl_emitter_append_character (':', 1, func->ud);
}
else {
func->ucl_emitter_append_len (": ", 2, func->ud);
}
- ucl_obj_write_json (cur, func, tabs + 1, false, compact);
- if (ucl_hash_iter_has_next (it)) {
- if (compact) {
- func->ucl_emitter_append_character (',', 1, func->ud);
- }
- else {
- func->ucl_emitter_append_len (",\n", 2, func->ud);
- }
- }
- else if (!compact) {
- func->ucl_emitter_append_character ('\n', 1, func->ud);
- }
}
- ucl_add_tabs (func, tabs, compact);
- func->ucl_emitter_append_character ('}', 1, func->ud);
}
-/**
- * Write a single array to the buffer
- * @param obj array to write
- * @param buf target buffer
- */
static void
-ucl_elt_array_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool compact)
+ucl_emitter_finish_object (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool compact, bool is_array)
{
- const ucl_object_t *cur = obj;
+ const struct ucl_emitter_functions *func = ctx->func;
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
- }
- if (compact) {
- func->ucl_emitter_append_character ('[', 1, func->ud);
- }
- else {
- func->ucl_emitter_append_len ("[\n", 2, func->ud);
- }
- while (cur) {
- ucl_elt_write_json (cur, func, tabs + 1, true, compact);
- if (cur->next != NULL) {
- if (compact) {
- func->ucl_emitter_append_character (',', 1, func->ud);
+ if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
+ if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
+ if (!is_array) {
+ /* Objects are split by ';' */
+ func->ucl_emitter_append_len (";\n", 2, func->ud);
}
else {
+ /* Use commas for arrays */
func->ucl_emitter_append_len (",\n", 2, func->ud);
}
}
- else if (!compact) {
- func->ucl_emitter_append_character ('\n', 1, func->ud);
- }
- cur = cur->next;
- }
- ucl_add_tabs (func, tabs, compact);
- func->ucl_emitter_append_character (']', 1, func->ud);
-}
-
-/**
- * Emit a single element
- * @param obj object
- * @param buf buffer
- */
-static void
-ucl_elt_write_json (const 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 (func, tabs, compact);
- }
- func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
- break;
- case UCL_FLOAT:
- case UCL_TIME:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
- }
- func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
- break;
- case UCL_BOOLEAN:
- if (start_tabs) {
- 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);
- }
- break;
- case UCL_STRING:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
- }
- ucl_elt_string_write_json (obj->value.sv, obj->len, func);
- break;
- case UCL_NULL:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
}
- func->ucl_emitter_append_len ("null", 4, func->ud);
- break;
- case UCL_OBJECT:
- ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact);
- break;
- case UCL_ARRAY:
- ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact);
- break;
- case UCL_USERDATA:
- break;
}
}
/**
- * Write a single object to the buffer
- * @param obj object
- * @param buf target buffer
+ * End standard ucl object
+ * @param ctx emitter context
+ * @param compact compact flag
*/
static void
-ucl_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool compact)
+ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool compact)
{
- const ucl_object_t *cur;
- bool is_array = (obj->next != NULL);
-
- if (is_array) {
- /* This is an array actually */
- if (start_tabs) {
- ucl_add_tabs (func, tabs, compact);
- }
+ const struct ucl_emitter_functions *func = ctx->func;
+ if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
+ ctx->ident --;
if (compact) {
- func->ucl_emitter_append_character ('[', 1, func->ud);
+ func->ucl_emitter_append_character ('}', 1, func->ud);
}
else {
- func->ucl_emitter_append_len ("[\n", 2, func->ud);
- }
- cur = obj;
- while (cur != NULL) {
- ucl_elt_write_json (cur, func, tabs + 1, true, compact);
- if (cur->next) {
- func->ucl_emitter_append_character (',', 1, func->ud);
- }
- if (!compact) {
+ if (ctx->id != UCL_EMIT_CONFIG) {
+ /* newline is already added for this format */
func->ucl_emitter_append_character ('\n', 1, func->ud);
}
- cur = cur->next;
+ ucl_add_tabs (func, ctx->ident, compact);
+ func->ucl_emitter_append_character ('}', 1, func->ud);
}
- ucl_add_tabs (func, tabs, compact);
- func->ucl_emitter_append_character (']', 1, func->ud);
- }
- else {
- ucl_elt_write_json (obj, func, tabs, start_tabs, compact);
}
+ ucl_emitter_finish_object (ctx, obj, compact, false);
}
/**
- * Emit an object to json
- * @param obj object
- * @return json output (should be freed after using)
+ * End standard ucl array
+ * @param ctx emitter context
+ * @param compact compact flag
*/
static void
-ucl_object_emit_json (const ucl_object_t *obj, bool compact,
- struct ucl_emitter_functions *func)
+ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool compact)
{
- ucl_obj_write_json (obj, func, 0, false, compact);
-}
-
-/**
- * Write a single object to the buffer
- * @param obj object to write
- * @param buf target buffer
- */
-static void
-ucl_elt_obj_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool is_top)
-{
- const ucl_object_t *cur, *cur_obj;
- ucl_hash_iter_t it = NULL;
+ const struct ucl_emitter_functions *func = ctx->func;
- if (start_tabs) {
- ucl_add_tabs (func, tabs, is_top);
- }
- if (!is_top) {
- func->ucl_emitter_append_len ("{\n", 2, func->ud);
+ ctx->ident --;
+ if (compact) {
+ func->ucl_emitter_append_character (']', 1, func->ud);
}
-
- while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
- LL_FOREACH (cur, cur_obj) {
- 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, func);
- }
- else {
- func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud);
- }
- if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
- func->ucl_emitter_append_len (" = ", 3, func->ud);
- }
- else {
- func->ucl_emitter_append_character (' ', 1, func->ud);
- }
- 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) {
- func->ucl_emitter_append_len (";\n", 2, func->ud);
- }
- else {
- func->ucl_emitter_append_character ('\n', 1, func->ud);
- }
+ else {
+ if (ctx->id != UCL_EMIT_CONFIG) {
+ /* newline is already added for this format */
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
}
+ ucl_add_tabs (func, ctx->ident, compact);
+ func->ucl_emitter_append_character (']', 1, func->ud);
}
- ucl_add_tabs (func, tabs, is_top);
- if (!is_top) {
- func->ucl_emitter_append_character ('}', 1, func->ud);
- }
+ ucl_emitter_finish_object (ctx, obj, compact, true);
}
/**
- * Write a single array to the buffer
- * @param obj array to write
- * @param buf target buffer
+ * Start emit standard UCL array
+ * @param ctx emitter context
+ * @param obj object to write
+ * @param compact compact flag
*/
static void
-ucl_elt_array_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool is_top)
+ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool print_key, bool compact)
{
- const ucl_object_t *cur = obj;
-
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
+ const ucl_object_t *cur;
+ const struct ucl_emitter_functions *func = ctx->func;
+ bool first = true;
- func->ucl_emitter_append_len ("[\n", 2, func->ud);
- while (cur) {
- 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 (func, tabs, false);
- func->ucl_emitter_append_character (']', 1, func->ud);
-}
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
-/**
- * Emit a single element
- * @param obj object
- * @param buf buffer
- */
-static void
-ucl_elt_write_config (const 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_config (obj, func, tabs, start_tabs, is_top);
+ if (compact) {
+ func->ucl_emitter_append_character ('[', 1, func->ud);
}
else {
- switch (obj->type) {
- case UCL_INT:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
- break;
- case UCL_FLOAT:
- case UCL_TIME:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
- break;
- case UCL_BOOLEAN:
- if (start_tabs) {
- 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);
- }
- break;
- case UCL_STRING:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- ucl_elt_string_write_json (obj->value.sv, obj->len, func);
- break;
- case UCL_NULL:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- func->ucl_emitter_append_len ("null", 4, func->ud);
- break;
- case UCL_OBJECT:
- ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top);
- break;
- case UCL_ARRAY:
- ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top);
- break;
- case UCL_USERDATA:
- break;
- }
+ func->ucl_emitter_append_len ("[\n", 2, func->ud);
}
-}
-/**
- * Emit an object to rcl
- * @param obj object
- * @return rcl output (should be freed after using)
- */
-static void
-ucl_object_emit_config (const ucl_object_t *obj, struct ucl_emitter_functions *func)
-{
- ucl_elt_write_config (obj, func, 0, false, true, true);
-}
+ ctx->ident ++;
-
-static void
-ucl_obj_write_yaml (const 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, func, tabs, start_tabs, false);
+ if (obj->type == UCL_ARRAY) {
+ /* explicit array */
+ cur = obj->value.av;
}
else {
- ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true);
+ /* implicit array */
+ cur = obj;
+ }
+
+ while (cur) {
+ ucl_emitter_common_elt (ctx, cur, first, false, compact);
+ first = false;
+ cur = cur->next;
}
}
/**
- * Write a single object to the buffer
+ * Start emit standard UCL object
+ * @param ctx emitter context
* @param obj object to write
- * @param buf target buffer
+ * @param compact compact flag
*/
static void
-ucl_elt_obj_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool is_top)
+ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool print_key, bool compact)
{
- const ucl_object_t *cur;
ucl_hash_iter_t it = NULL;
-
- if (start_tabs) {
- ucl_add_tabs (func, tabs, is_top);
- }
- if (!is_top) {
- func->ucl_emitter_append_len ("{\n", 2, func->ud);
+ const ucl_object_t *cur, *elt;
+ const struct ucl_emitter_functions *func = ctx->func;
+ bool first = true;
+
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ /*
+ * Print <ident_level>{
+ * <ident_level + 1><object content>
+ */
+ if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
+ if (compact) {
+ func->ucl_emitter_append_character ('{', 1, func->ud);
+ }
+ else {
+ func->ucl_emitter_append_len ("{\n", 2, func->ud);
+ }
+ ctx->ident ++;
}
while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
- ucl_add_tabs (func, tabs + 1, is_top);
- if (cur->keylen > 0) {
- ucl_elt_string_write_json (cur->key, cur->keylen, func);
+
+ if (ctx->id == UCL_EMIT_CONFIG) {
+ LL_FOREACH (cur, elt) {
+ ucl_emitter_common_elt (ctx, elt, first, true, compact);
+ }
}
else {
- func->ucl_emitter_append_len ("null", 4, func->ud);
- }
- 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) {
- func->ucl_emitter_append_len (",\n", 2, func->ud);
+ /* Expand implicit arrays */
+ if (cur->next != NULL) {
+ if (!first) {
+ if (compact) {
+ func->ucl_emitter_append_character (',', 1, func->ud);
+ }
+ else {
+ func->ucl_emitter_append_len (",\n", 2, func->ud);
+ }
+ }
+ ucl_add_tabs (func, ctx->ident, compact);
+ ucl_emitter_common_start_array (ctx, cur, true, compact);
+ ucl_emitter_common_end_array (ctx, cur, compact);
}
else {
- func->ucl_emitter_append_character ('\n', 1, func->ud);
+ ucl_emitter_common_elt (ctx, cur, first, true, compact);
}
}
- else {
- func->ucl_emitter_append_character ('\n', 1, func->ud);
- }
- }
- ucl_add_tabs (func, tabs, is_top);
- if (!is_top) {
- func->ucl_emitter_append_character ('}', 1, func->ud);
+ first = false;
}
}
/**
- * Write a single array to the buffer
- * @param obj array to write
- * @param buf target buffer
+ * Common choice of object emitting
+ * @param ctx emitter context
+ * @param obj object to print
+ * @param first flag to mark the first element
+ * @param print_key print key of an object
+ * @param compact compact output
*/
static void
-ucl_elt_array_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool is_top)
+ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj, bool first, bool print_key, bool compact)
{
- const ucl_object_t *cur = obj;
-
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
+ const struct ucl_emitter_functions *func = ctx->func;
+ bool flag;
- func->ucl_emitter_append_len ("[\n", 2, func->ud);
- while (cur) {
- ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false);
- func->ucl_emitter_append_len (",\n", 2, func->ud);
- cur = cur->next;
+ if (ctx->id != UCL_EMIT_CONFIG && !first) {
+ if (compact) {
+ func->ucl_emitter_append_character (',', 1, func->ud);
+ }
+ else {
+ func->ucl_emitter_append_len (",\n", 2, func->ud);
+ }
}
- ucl_add_tabs (func, tabs, false);
- func->ucl_emitter_append_character (']', 1, func->ud);
-}
-/**
- * Emit a single element
- * @param obj object
- * @param buf buffer
- */
-static void
-ucl_elt_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
- unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
-{
- bool flag;
+ ucl_add_tabs (func, ctx->ident, compact);
- 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 (func, tabs, false);
- }
- func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
- break;
- case UCL_FLOAT:
- case UCL_TIME:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
- break;
- case UCL_BOOLEAN:
- if (start_tabs) {
- 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);
- }
- break;
- case UCL_STRING:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- ucl_elt_string_write_json (obj->value.sv, obj->len, func);
- break;
- case UCL_NULL:
- if (start_tabs) {
- ucl_add_tabs (func, tabs, false);
- }
- func->ucl_emitter_append_len ("null", 4, func->ud);
- break;
- case UCL_OBJECT:
- ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top);
- break;
- case UCL_ARRAY:
- ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top);
- break;
- case UCL_USERDATA:
- break;
+ switch (obj->type) {
+ case UCL_INT:
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
+ break;
+ case UCL_FLOAT:
+ case UCL_TIME:
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
+ break;
+ case UCL_BOOLEAN:
+ ucl_emitter_print_key (print_key, ctx, obj, 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);
}
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
+ break;
+ case UCL_STRING:
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
+ break;
+ case UCL_NULL:
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ func->ucl_emitter_append_len ("null", 4, func->ud);
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
+ break;
+ case UCL_OBJECT:
+ ucl_emitter_common_start_object (ctx, obj, print_key, compact);
+ ucl_emitter_common_end_object (ctx, obj, compact);
+ break;
+ case UCL_ARRAY:
+ ucl_emitter_common_start_array (ctx, obj, print_key, compact);
+ ucl_emitter_common_end_array (ctx, obj, compact);
+ break;
+ case UCL_USERDATA:
+ break;
}
}
-/**
- * Emit an object to rcl
- * @param obj object
- * @return rcl output (should be freed after using)
- */
-static void
-ucl_object_emit_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func)
-{
- ucl_elt_write_yaml (obj, func, 0, false, true, true);
-}
-
/*
- * Generic utstring output
+ * Specific standard implementations of the emitter functions
*/
-static int
-ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
-{
- UT_string *buf = ud;
-
- 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 0;
-}
-
+#define UCL_EMIT_TYPE_IMPL(type, compact) \
+ static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool first, bool print_key) { \
+ ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
+ } \
+ static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool print_key) { \
+ ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \
+ } \
+ static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj, bool print_key) { \
+ ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \
+ } \
+ static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj) { \
+ ucl_emitter_common_end_object (ctx, obj, (compact)); \
+ } \
+ static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
+ const ucl_object_t *obj) { \
+ ucl_emitter_common_end_array (ctx, obj, (compact)); \
+ }
+
+UCL_EMIT_TYPE_IMPL(json, false);
+UCL_EMIT_TYPE_IMPL(json_compact, true);
+UCL_EMIT_TYPE_IMPL(config, false);
+UCL_EMIT_TYPE_IMPL(yaml, false);
unsigned char *
ucl_object_emit (const 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
- };
-
+ struct ucl_emitter_functions *func;
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);
- }
+ func = ucl_object_emit_memory_funcs ((void **)&res);
- res = utstring_body (buf);
- free (buf);
+ if (func != NULL) {
+ ucl_object_emit_full (obj, emit_type, func);
+ ucl_object_emit_funcs_free (func);
}
return res;
@@ -767,71 +453,19 @@ bool
ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
struct ucl_emitter_functions *emitter)
{
- if (emit_type == UCL_EMIT_JSON) {
- ucl_object_emit_json (obj, false, emitter);
- }
- else if (emit_type == UCL_EMIT_JSON_COMPACT) {
- ucl_object_emit_json (obj, true, emitter);
- }
- else if (emit_type == UCL_EMIT_YAML) {
- ucl_object_emit_yaml (obj, emitter);
- }
- else {
- ucl_object_emit_config (obj, emitter);
- }
-
- /* XXX: need some error checks here */
- return true;
-}
-
-
-unsigned char *
-ucl_object_emit_single_json (const ucl_object_t *obj)
-{
- UT_string *buf = NULL;
- unsigned char *res = NULL;
-
- if (obj == NULL) {
- return NULL;
- }
-
- utstring_new (buf);
-
- if (buf != NULL) {
- switch (obj->type) {
- case UCL_OBJECT:
- ucl_utstring_append_len ("object", 6, buf);
- break;
- case UCL_ARRAY:
- ucl_utstring_append_len ("array", 5, buf);
- break;
- case UCL_INT:
- ucl_utstring_append_int (obj->value.iv, buf);
- break;
- case UCL_FLOAT:
- case UCL_TIME:
- ucl_utstring_append_double (obj->value.dv, buf);
- break;
- case UCL_NULL:
- ucl_utstring_append_len ("null", 4, buf);
- break;
- case UCL_BOOLEAN:
- if (obj->value.iv) {
- ucl_utstring_append_len ("true", 4, buf);
- }
- else {
- ucl_utstring_append_len ("false", 5, buf);
- }
- break;
- case UCL_STRING:
- ucl_utstring_append_len (obj->value.sv, obj->len, buf);
- break;
- case UCL_USERDATA:
- ucl_utstring_append_len ("userdata", 8, buf);
- break;
- }
- res = utstring_body (buf);
- free (buf);
+ const struct ucl_emitter_context *ctx;
+ struct ucl_emitter_context my_ctx;
+ bool res = false;
+
+ ctx = ucl_emit_get_standard_context (emit_type);
+ if (ctx != NULL) {
+ memcpy (&my_ctx, ctx, sizeof (my_ctx));
+ my_ctx.func = emitter;
+ my_ctx.ident = 0;
+ my_ctx.top = obj;
+
+ my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
+ res = true;
}
return res;
diff --git a/contrib/libucl/src/ucl_emitter_streamline.c b/contrib/libucl/src/ucl_emitter_streamline.c
new file mode 100644
index 0000000..acf4a30
--- /dev/null
+++ b/contrib/libucl/src/ucl_emitter_streamline.c
@@ -0,0 +1,166 @@
+/* Copyright (c) 2014, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ucl.h"
+#include "ucl_internal.h"
+#include "ucl_chartable.h"
+
+struct ucl_emitter_streamline_stack {
+ bool is_array;
+ bool empty;
+ const ucl_object_t *obj;
+ struct ucl_emitter_streamline_stack *next;
+};
+
+struct ucl_emitter_context_streamline {
+ /* Inherited from the main context */
+ const char *name;
+ int id;
+ const struct ucl_emitter_functions *func;
+ const struct ucl_emitter_operations *ops;
+ unsigned int ident;
+ const ucl_object_t *top;
+
+ /* Streamline specific fields */
+ struct ucl_emitter_streamline_stack *containers;
+};
+
+#define TO_STREAMLINE(ctx) (struct ucl_emitter_context_streamline *)(ctx)
+
+struct ucl_emitter_context*
+ucl_object_emit_streamline_new (const ucl_object_t *obj,
+ enum ucl_emitter emit_type,
+ struct ucl_emitter_functions *emitter)
+{
+ const struct ucl_emitter_context *ctx;
+ struct ucl_emitter_context_streamline *sctx;
+
+ ctx = ucl_emit_get_standard_context (emit_type);
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ sctx = calloc (1, sizeof (*sctx));
+ if (sctx == NULL) {
+ return NULL;
+ }
+
+ memcpy (sctx, ctx, sizeof (*ctx));
+ sctx->func = emitter;
+ sctx->top = obj;
+
+ ucl_object_emit_streamline_start_container ((struct ucl_emitter_context *)sctx,
+ obj);
+
+ return (struct ucl_emitter_context *)sctx;
+}
+
+void
+ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx,
+ const ucl_object_t *obj)
+{
+ struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
+ struct ucl_emitter_streamline_stack *st, *top;
+ bool print_key = false;
+
+ /* Check top object presence */
+ if (sctx->top == NULL) {
+ sctx->top = obj;
+ }
+
+ top = sctx->containers;
+ st = malloc (sizeof (*st));
+ if (st != NULL) {
+ if (top != NULL && !top->is_array) {
+ print_key = true;
+ }
+ st->empty = true;
+ st->obj = obj;
+ if (obj != NULL && obj->type == UCL_ARRAY) {
+ st->is_array = true;
+ sctx->ops->ucl_emitter_start_array (ctx, obj, print_key);
+ }
+ else {
+ st->is_array = false;
+ sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
+ }
+ }
+
+ LL_PREPEND (sctx->containers, st);
+}
+
+void
+ucl_object_emit_streamline_add_object (
+ struct ucl_emitter_context *ctx, const ucl_object_t *obj)
+{
+ struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
+ bool is_array = false, is_first = false;
+
+ if (sctx->containers != NULL) {
+ if (sctx->containers->is_array) {
+ is_array = true;
+ }
+ if (sctx->containers->empty) {
+ is_first = true;
+ sctx->containers->empty = false;
+ }
+ }
+
+ sctx->ops->ucl_emitter_write_elt (ctx, obj, is_first, !is_array);
+}
+
+void
+ucl_object_emit_streamline_end_container (struct ucl_emitter_context *ctx)
+{
+ struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
+ struct ucl_emitter_streamline_stack *st;
+
+ if (sctx->containers != NULL) {
+ st = sctx->containers;
+
+ if (st->is_array) {
+ sctx->ops->ucl_emitter_end_array (ctx, st->obj);
+ }
+ else {
+ sctx->ops->ucl_emitter_end_object (ctx, st->obj);
+ }
+ sctx->containers = st->next;
+ free (st);
+ }
+}
+
+void
+ucl_object_emit_streamline_finish (struct ucl_emitter_context *ctx)
+{
+ struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
+
+ while (sctx->containers != NULL) {
+ ucl_object_emit_streamline_end_container (ctx);
+ }
+
+ free (sctx);
+}
diff --git a/contrib/libucl/src/ucl_emitter_utils.c b/contrib/libucl/src/ucl_emitter_utils.c
new file mode 100644
index 0000000..c619ab9
--- /dev/null
+++ b/contrib/libucl/src/ucl_emitter_utils.c
@@ -0,0 +1,466 @@
+/* Copyright (c) 2014, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ucl.h"
+#include "ucl_internal.h"
+#include "ucl_chartable.h"
+
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
+
+static const struct ucl_emitter_context ucl_standard_emitters[] = {
+ [UCL_EMIT_JSON] = {
+ .name = "json",
+ .id = UCL_EMIT_JSON,
+ .func = NULL,
+ .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]
+ },
+ [UCL_EMIT_JSON_COMPACT] = {
+ .name = "json_compact",
+ .id = UCL_EMIT_JSON_COMPACT,
+ .func = NULL,
+ .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
+ },
+ [UCL_EMIT_CONFIG] = {
+ .name = "config",
+ .id = UCL_EMIT_CONFIG,
+ .func = NULL,
+ .ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
+ },
+ [UCL_EMIT_YAML] = {
+ .name = "yaml",
+ .id = UCL_EMIT_YAML,
+ .func = NULL,
+ .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
+ }
+};
+
+/**
+ * Get standard emitter context for a specified emit_type
+ * @param emit_type type of emitter
+ * @return context or NULL if input is invalid
+ */
+const struct ucl_emitter_context *
+ucl_emit_get_standard_context (enum ucl_emitter emit_type)
+{
+ if (emit_type >= UCL_EMIT_JSON && emit_type <= UCL_EMIT_YAML) {
+ return &ucl_standard_emitters[emit_type];
+ }
+
+ return NULL;
+}
+
+/**
+ * Serialise string
+ * @param str string to emit
+ * @param buf target buffer
+ */
+void
+ucl_elt_string_write_json (const char *str, size_t size,
+ struct ucl_emitter_context *ctx)
+{
+ const char *p = str, *c = str;
+ size_t len = 0;
+ const struct ucl_emitter_functions *func = ctx->func;
+
+ if (ctx->id != UCL_EMIT_YAML) {
+ func->ucl_emitter_append_character ('"', 1, func->ud);
+ }
+
+ while (size) {
+ if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
+ if (len > 0) {
+ func->ucl_emitter_append_len (c, len, func->ud);
+ }
+ switch (*p) {
+ case '\n':
+ func->ucl_emitter_append_len ("\\n", 2, func->ud);
+ break;
+ case '\r':
+ func->ucl_emitter_append_len ("\\r", 2, func->ud);
+ break;
+ case '\b':
+ func->ucl_emitter_append_len ("\\b", 2, func->ud);
+ break;
+ case '\t':
+ func->ucl_emitter_append_len ("\\t", 2, func->ud);
+ break;
+ case '\f':
+ func->ucl_emitter_append_len ("\\f", 2, func->ud);
+ break;
+ case '\\':
+ func->ucl_emitter_append_len ("\\\\", 2, func->ud);
+ break;
+ case '"':
+ func->ucl_emitter_append_len ("\\\"", 2, func->ud);
+ break;
+ }
+ len = 0;
+ c = ++p;
+ }
+ else {
+ p ++;
+ len ++;
+ }
+ size --;
+ }
+ if (len > 0) {
+ func->ucl_emitter_append_len (c, len, func->ud);
+ }
+ if (ctx->id != UCL_EMIT_YAML) {
+ func->ucl_emitter_append_character ('"', 1, func->ud);
+ }
+}
+
+/*
+ * Generic utstring output
+ */
+static int
+ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
+{
+ UT_string *buf = ud;
+
+ 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 0;
+}
+
+/*
+ * Generic file output
+ */
+static int
+ucl_file_append_character (unsigned char c, size_t len, void *ud)
+{
+ FILE *fp = ud;
+
+ while (len --) {
+ fputc (c, fp);
+ }
+
+ return 0;
+}
+
+static int
+ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
+{
+ FILE *fp = ud;
+
+ fwrite (str, len, 1, fp);
+
+ return 0;
+}
+
+static int
+ucl_file_append_int (int64_t val, void *ud)
+{
+ FILE *fp = ud;
+
+ fprintf (fp, "%jd", (intmax_t)val);
+
+ return 0;
+}
+
+static int
+ucl_file_append_double (double val, void *ud)
+{
+ FILE *fp = ud;
+ const double delta = 0.0000001;
+
+ if (val == (double)(int)val) {
+ fprintf (fp, "%.1lf", val);
+ }
+ else if (fabs (val - (double)(int)val) < delta) {
+ /* Write at maximum precision */
+ fprintf (fp, "%.*lg", DBL_DIG, val);
+ }
+ else {
+ fprintf (fp, "%lf", val);
+ }
+
+ return 0;
+}
+
+/*
+ * Generic file descriptor writing functions
+ */
+static int
+ucl_fd_append_character (unsigned char c, size_t len, void *ud)
+{
+ int fd = *(int *)ud;
+ unsigned char *buf;
+
+ if (len == 1) {
+ write (fd, &c, 1);
+ }
+ else {
+ buf = malloc (len);
+ if (buf == NULL) {
+ /* Fallback */
+ while (len --) {
+ write (fd, &c, 1);
+ }
+ }
+ else {
+ memset (buf, c, len);
+ write (fd, buf, len);
+ free (buf);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
+{
+ int fd = *(int *)ud;
+
+ write (fd, str, len);
+
+ return 0;
+}
+
+static int
+ucl_fd_append_int (int64_t val, void *ud)
+{
+ int fd = *(int *)ud;
+ char intbuf[64];
+
+ snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
+ write (fd, intbuf, strlen (intbuf));
+
+ return 0;
+}
+
+static int
+ucl_fd_append_double (double val, void *ud)
+{
+ int fd = *(int *)ud;
+ const double delta = 0.0000001;
+ char nbuf[64];
+
+ if (val == (double)(int)val) {
+ snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
+ }
+ else if (fabs (val - (double)(int)val) < delta) {
+ /* Write at maximum precision */
+ snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
+ }
+ else {
+ snprintf (nbuf, sizeof (nbuf), "%lf", val);
+ }
+
+ write (fd, nbuf, strlen (nbuf));
+
+ return 0;
+}
+
+struct ucl_emitter_functions*
+ucl_object_emit_memory_funcs (void **pmem)
+{
+ struct ucl_emitter_functions *f;
+ UT_string *s;
+
+ f = calloc (1, sizeof (*f));
+
+ if (f != NULL) {
+ f->ucl_emitter_append_character = ucl_utstring_append_character;
+ f->ucl_emitter_append_double = ucl_utstring_append_double;
+ f->ucl_emitter_append_int = ucl_utstring_append_int;
+ f->ucl_emitter_append_len = ucl_utstring_append_len;
+ f->ucl_emitter_free_func = free;
+ utstring_new (s);
+ f->ud = s;
+ *pmem = s->d;
+ s->pd = pmem;
+ }
+
+ return f;
+}
+
+struct ucl_emitter_functions*
+ucl_object_emit_file_funcs (FILE *fp)
+{
+ struct ucl_emitter_functions *f;
+
+ f = calloc (1, sizeof (*f));
+
+ if (f != NULL) {
+ f->ucl_emitter_append_character = ucl_file_append_character;
+ f->ucl_emitter_append_double = ucl_file_append_double;
+ f->ucl_emitter_append_int = ucl_file_append_int;
+ f->ucl_emitter_append_len = ucl_file_append_len;
+ f->ucl_emitter_free_func = NULL;
+ f->ud = fp;
+ }
+
+ return f;
+}
+
+struct ucl_emitter_functions*
+ucl_object_emit_fd_funcs (int fd)
+{
+ struct ucl_emitter_functions *f;
+ int *ip;
+
+ f = calloc (1, sizeof (*f));
+
+ if (f != NULL) {
+ ip = malloc (sizeof (fd));
+ if (ip == NULL) {
+ free (f);
+ return NULL;
+ }
+
+ memcpy (ip, &fd, sizeof (fd));
+ f->ucl_emitter_append_character = ucl_fd_append_character;
+ f->ucl_emitter_append_double = ucl_fd_append_double;
+ f->ucl_emitter_append_int = ucl_fd_append_int;
+ f->ucl_emitter_append_len = ucl_fd_append_len;
+ f->ucl_emitter_free_func = free;
+ f->ud = ip;
+ }
+
+ return f;
+}
+
+void
+ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
+{
+ if (f != NULL) {
+ if (f->ucl_emitter_free_func != NULL) {
+ f->ucl_emitter_free_func (f->ud);
+ }
+ free (f);
+ }
+}
+
+
+unsigned char *
+ucl_object_emit_single_json (const ucl_object_t *obj)
+{
+ UT_string *buf = NULL;
+ unsigned char *res = NULL;
+
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ utstring_new (buf);
+
+ if (buf != NULL) {
+ switch (obj->type) {
+ case UCL_OBJECT:
+ ucl_utstring_append_len ("object", 6, buf);
+ break;
+ case UCL_ARRAY:
+ ucl_utstring_append_len ("array", 5, buf);
+ break;
+ case UCL_INT:
+ ucl_utstring_append_int (obj->value.iv, buf);
+ break;
+ case UCL_FLOAT:
+ case UCL_TIME:
+ ucl_utstring_append_double (obj->value.dv, buf);
+ break;
+ case UCL_NULL:
+ ucl_utstring_append_len ("null", 4, buf);
+ break;
+ case UCL_BOOLEAN:
+ if (obj->value.iv) {
+ ucl_utstring_append_len ("true", 4, buf);
+ }
+ else {
+ ucl_utstring_append_len ("false", 5, buf);
+ }
+ break;
+ case UCL_STRING:
+ ucl_utstring_append_len (obj->value.sv, obj->len, buf);
+ break;
+ case UCL_USERDATA:
+ ucl_utstring_append_len ("userdata", 8, buf);
+ break;
+ }
+ res = utstring_body (buf);
+ free (buf);
+ }
+
+ return res;
+}
diff --git a/contrib/libucl/src/ucl_internal.h b/contrib/libucl/src/ucl_internal.h
index 0e3ecd0..0ac8de8 100644
--- a/contrib/libucl/src/ucl_internal.h
+++ b/contrib/libucl/src/ucl_internal.h
@@ -343,6 +343,22 @@ ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj)
}
/**
+ * Get standard emitter context for a specified emit_type
+ * @param emit_type type of emitter
+ * @return context or NULL if input is invalid
+ */
+const struct ucl_emitter_context *
+ucl_emit_get_standard_context (enum ucl_emitter emit_type);
+
+/**
+ * Serialise string
+ * @param str string to emit
+ * @param buf target buffer
+ */
+void ucl_elt_string_write_json (const char *str, size_t size,
+ struct ucl_emitter_context *ctx);
+
+/**
* Emit a single object to string
* @param obj
* @return
diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c
index b4fe5af..8768574 100644
--- a/contrib/libucl/src/ucl_parser.c
+++ b/contrib/libucl/src/ucl_parser.c
@@ -393,9 +393,16 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
/* Leave variable as is */
if (!found) {
- memcpy (d, ptr, 2);
- d += 2;
- ret --;
+ if (strict) {
+ /* Copy '${' */
+ memcpy (d, ptr, 2);
+ d += 2;
+ ret --;
+ }
+ else {
+ memcpy (d, ptr, 1);
+ d ++;
+ }
}
}
OpenPOWER on IntegriCloud