diff options
Diffstat (limited to 'contrib/libucl/src')
-rw-r--r-- | contrib/libucl/src/Makefile.am | 2 | ||||
-rw-r--r-- | contrib/libucl/src/ucl_emitter.c | 934 | ||||
-rw-r--r-- | contrib/libucl/src/ucl_emitter_streamline.c | 166 | ||||
-rw-r--r-- | contrib/libucl/src/ucl_emitter_utils.c | 466 | ||||
-rw-r--r-- | contrib/libucl/src/ucl_internal.h | 16 | ||||
-rw-r--r-- | contrib/libucl/src/ucl_parser.c | 13 |
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 ++; + } } } |