1 /* Copyright (c) 2013, Vsevolod Stakhov
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "ucl_internal.h"
30 #include "ucl_chartable.h"
40 * Serialise UCL object to various of output formats
43 static void ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
44 const ucl_object_t *obj, bool first, bool print_key, bool compact);
46 #define UCL_EMIT_TYPE_OPS(type) \
47 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
48 const ucl_object_t *obj, bool first, bool print_key); \
49 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
50 const ucl_object_t *obj, bool print_key); \
51 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
52 const ucl_object_t *obj, bool print_key); \
53 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
54 const ucl_object_t *obj); \
55 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
56 const ucl_object_t *obj)
59 * JSON format operations
61 UCL_EMIT_TYPE_OPS(json);
62 UCL_EMIT_TYPE_OPS(json_compact);
63 UCL_EMIT_TYPE_OPS(config);
64 UCL_EMIT_TYPE_OPS(yaml);
65 UCL_EMIT_TYPE_OPS(msgpack);
67 #define UCL_EMIT_TYPE_CONTENT(type) { \
68 .ucl_emitter_write_elt = ucl_emit_ ## type ## _elt, \
69 .ucl_emitter_start_object = ucl_emit_ ## type ##_start_obj, \
70 .ucl_emitter_start_array = ucl_emit_ ## type ##_start_array, \
71 .ucl_emitter_end_object = ucl_emit_ ## type ##_end_object, \
72 .ucl_emitter_end_array = ucl_emit_ ## type ##_end_array \
75 const struct ucl_emitter_operations ucl_standartd_emitter_ops[] = {
76 [UCL_EMIT_JSON] = UCL_EMIT_TYPE_CONTENT(json),
77 [UCL_EMIT_JSON_COMPACT] = UCL_EMIT_TYPE_CONTENT(json_compact),
78 [UCL_EMIT_CONFIG] = UCL_EMIT_TYPE_CONTENT(config),
79 [UCL_EMIT_YAML] = UCL_EMIT_TYPE_CONTENT(yaml),
80 [UCL_EMIT_MSGPACK] = UCL_EMIT_TYPE_CONTENT(msgpack)
84 * Utility to check whether we need a top object
86 #define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \
87 ((ctx)->id == UCL_EMIT_JSON_COMPACT || (ctx)->id == UCL_EMIT_JSON))
91 * Add tabulation to the output buffer
92 * @param buf target buffer
93 * @param tabs number of tabs to add
96 ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs,
99 if (!compact && tabs > 0) {
100 func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
105 * Print key for the element
110 ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
111 const ucl_object_t *obj, bool compact)
113 const struct ucl_emitter_functions *func = ctx->func;
119 if (ctx->id == UCL_EMIT_CONFIG) {
120 if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
121 ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
124 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
127 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
128 func->ucl_emitter_append_len (" = ", 3, func->ud);
131 func->ucl_emitter_append_character (' ', 1, func->ud);
134 else if (ctx->id == UCL_EMIT_YAML) {
135 if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
136 ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
138 else if (obj->keylen > 0) {
139 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
142 func->ucl_emitter_append_len ("null", 4, func->ud);
145 func->ucl_emitter_append_len (": ", 2, func->ud);
148 if (obj->keylen > 0) {
149 ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
152 func->ucl_emitter_append_len ("null", 4, func->ud);
156 func->ucl_emitter_append_character (':', 1, func->ud);
159 func->ucl_emitter_append_len (": ", 2, func->ud);
165 ucl_emitter_finish_object (struct ucl_emitter_context *ctx,
166 const ucl_object_t *obj, bool compact, bool is_array)
168 const struct ucl_emitter_functions *func = ctx->func;
170 if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
171 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
173 /* Objects are split by ';' */
174 func->ucl_emitter_append_len (";\n", 2, func->ud);
177 /* Use commas for arrays */
178 func->ucl_emitter_append_len (",\n", 2, func->ud);
182 func->ucl_emitter_append_character ('\n', 1, func->ud);
188 * End standard ucl object
189 * @param ctx emitter context
190 * @param compact compact flag
193 ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
194 const ucl_object_t *obj, bool compact)
196 const struct ucl_emitter_functions *func = ctx->func;
198 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
201 func->ucl_emitter_append_character ('}', 1, func->ud);
204 if (ctx->id != UCL_EMIT_CONFIG) {
205 /* newline is already added for this format */
206 func->ucl_emitter_append_character ('\n', 1, func->ud);
208 ucl_add_tabs (func, ctx->indent, compact);
209 func->ucl_emitter_append_character ('}', 1, func->ud);
213 ucl_emitter_finish_object (ctx, obj, compact, false);
217 * End standard ucl array
218 * @param ctx emitter context
219 * @param compact compact flag
222 ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
223 const ucl_object_t *obj, bool compact)
225 const struct ucl_emitter_functions *func = ctx->func;
229 func->ucl_emitter_append_character (']', 1, func->ud);
232 if (ctx->id != UCL_EMIT_CONFIG) {
233 /* newline is already added for this format */
234 func->ucl_emitter_append_character ('\n', 1, func->ud);
236 ucl_add_tabs (func, ctx->indent, compact);
237 func->ucl_emitter_append_character (']', 1, func->ud);
240 ucl_emitter_finish_object (ctx, obj, compact, true);
244 * Start emit standard UCL array
245 * @param ctx emitter context
246 * @param obj object to write
247 * @param compact compact flag
250 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
251 const ucl_object_t *obj, bool print_key, bool compact)
253 const ucl_object_t *cur;
254 ucl_object_iter_t iter = NULL;
255 const struct ucl_emitter_functions *func = ctx->func;
258 ucl_emitter_print_key (print_key, ctx, obj, compact);
261 func->ucl_emitter_append_character ('[', 1, func->ud);
264 func->ucl_emitter_append_len ("[\n", 2, func->ud);
269 if (obj->type == UCL_ARRAY) {
271 while ((cur = ucl_iterate_object (obj, &iter, true)) != NULL) {
272 ucl_emitter_common_elt (ctx, cur, first, false, compact);
280 ucl_emitter_common_elt (ctx, cur, first, false, compact);
290 * Start emit standard UCL object
291 * @param ctx emitter context
292 * @param obj object to write
293 * @param compact compact flag
296 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
297 const ucl_object_t *obj, bool print_key, bool compact)
299 ucl_hash_iter_t it = NULL;
300 const ucl_object_t *cur, *elt;
301 const struct ucl_emitter_functions *func = ctx->func;
304 ucl_emitter_print_key (print_key, ctx, obj, compact);
306 * Print <ident_level>{
307 * <ident_level + 1><object content>
309 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
311 func->ucl_emitter_append_character ('{', 1, func->ud);
314 func->ucl_emitter_append_len ("{\n", 2, func->ud);
319 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
321 if (ctx->id == UCL_EMIT_CONFIG) {
322 LL_FOREACH (cur, elt) {
323 ucl_emitter_common_elt (ctx, elt, first, true, compact);
327 /* Expand implicit arrays */
328 if (cur->next != NULL) {
331 func->ucl_emitter_append_character (',', 1, func->ud);
334 func->ucl_emitter_append_len (",\n", 2, func->ud);
337 ucl_add_tabs (func, ctx->indent, compact);
338 ucl_emitter_common_start_array (ctx, cur, true, compact);
339 ucl_emitter_common_end_array (ctx, cur, compact);
342 ucl_emitter_common_elt (ctx, cur, first, true, compact);
351 * Common choice of object emitting
352 * @param ctx emitter context
353 * @param obj object to print
354 * @param first flag to mark the first element
355 * @param print_key print key of an object
356 * @param compact compact output
359 ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
360 const ucl_object_t *obj, bool first, bool print_key, bool compact)
362 const struct ucl_emitter_functions *func = ctx->func;
364 struct ucl_object_userdata *ud;
365 const char *ud_out = "";
367 if (ctx->id != UCL_EMIT_CONFIG && !first) {
369 func->ucl_emitter_append_character (',', 1, func->ud);
372 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
373 func->ucl_emitter_append_len ("\n", 1, func->ud);
375 func->ucl_emitter_append_len (",\n", 2, func->ud);
380 ucl_add_tabs (func, ctx->indent, compact);
384 ucl_emitter_print_key (print_key, ctx, obj, compact);
385 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
386 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
390 ucl_emitter_print_key (print_key, ctx, obj, compact);
391 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
392 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
395 ucl_emitter_print_key (print_key, ctx, obj, compact);
396 flag = ucl_object_toboolean (obj);
398 func->ucl_emitter_append_len ("true", 4, func->ud);
401 func->ucl_emitter_append_len ("false", 5, func->ud);
403 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
406 ucl_emitter_print_key (print_key, ctx, obj, compact);
407 if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
408 ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
411 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
413 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
416 ucl_emitter_print_key (print_key, ctx, obj, compact);
417 func->ucl_emitter_append_len ("null", 4, func->ud);
418 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
421 ucl_emitter_common_start_object (ctx, obj, print_key, compact);
422 ucl_emitter_common_end_object (ctx, obj, compact);
425 ucl_emitter_common_start_array (ctx, obj, print_key, compact);
426 ucl_emitter_common_end_array (ctx, obj, compact);
429 ud = (struct ucl_object_userdata *)obj;
430 ucl_emitter_print_key (print_key, ctx, obj, compact);
432 ud_out = ud->emitter (obj->value.ud);
433 if (ud_out == NULL) {
437 ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
438 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
444 * Specific standard implementations of the emitter functions
446 #define UCL_EMIT_TYPE_IMPL(type, compact) \
447 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
448 const ucl_object_t *obj, bool first, bool print_key) { \
449 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
451 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
452 const ucl_object_t *obj, bool print_key) { \
453 ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \
455 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
456 const ucl_object_t *obj, bool print_key) { \
457 ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \
459 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
460 const ucl_object_t *obj) { \
461 ucl_emitter_common_end_object (ctx, obj, (compact)); \
463 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
464 const ucl_object_t *obj) { \
465 ucl_emitter_common_end_array (ctx, obj, (compact)); \
468 UCL_EMIT_TYPE_IMPL(json, false)
469 UCL_EMIT_TYPE_IMPL(json_compact, true)
470 UCL_EMIT_TYPE_IMPL(config, false)
471 UCL_EMIT_TYPE_IMPL(yaml, false)
474 ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
475 const ucl_object_t *obj, bool first, bool print_key)
477 ucl_object_iter_t it;
478 struct ucl_object_userdata *ud;
480 const ucl_object_t *cur, *celt;
484 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
485 ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj));
490 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
491 ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj));
495 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
496 ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj));
500 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
502 if (obj->flags & UCL_OBJECT_BINARY) {
503 ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
507 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
512 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
513 ucl_emitter_print_null_msgpack (ctx);
517 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
518 ucl_emit_msgpack_start_obj (ctx, obj, print_key);
521 while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
522 LL_FOREACH (cur, celt) {
523 ucl_emit_msgpack_elt (ctx, celt, false, true);
525 * in msgpack the length of objects is encoded within a single elt
526 * so in case of multi-value keys we are using merely the first
527 * element ignoring others
536 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
537 ucl_emit_msgpack_start_array (ctx, obj, print_key);
540 while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
541 ucl_emit_msgpack_elt (ctx, cur, false, false);
547 ud = (struct ucl_object_userdata *)obj;
548 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
551 ud_out = ud->emitter (obj->value.ud);
552 if (ud_out == NULL) {
556 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
562 ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx,
563 const ucl_object_t *obj, bool print_key)
565 ucl_emitter_print_object_msgpack (ctx, obj->len);
569 ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx,
570 const ucl_object_t *obj, bool print_key)
572 ucl_emitter_print_array_msgpack (ctx, obj->len);
576 ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx,
577 const ucl_object_t *obj)
583 ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx,
584 const ucl_object_t *obj)
590 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
592 return ucl_object_emit_len (obj, emit_type, NULL);
596 ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
599 unsigned char *res = NULL;
600 struct ucl_emitter_functions *func;
607 func = ucl_object_emit_memory_funcs ((void **)&res);
611 ucl_object_emit_full (obj, emit_type, func);
613 if (outlen != NULL) {
617 ucl_object_emit_funcs_free (func);
624 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
625 struct ucl_emitter_functions *emitter)
627 const struct ucl_emitter_context *ctx;
628 struct ucl_emitter_context my_ctx;
631 ctx = ucl_emit_get_standard_context (emit_type);
633 memcpy (&my_ctx, ctx, sizeof (my_ctx));
634 my_ctx.func = emitter;
638 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);