1 /* Copyright (c) 2013, Vsevolod Stakhov
2 * All rights reserved.
3 *
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.
11 *
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.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "ucl.h"
29 #include "ucl_internal.h"
30 #include "ucl_chartable.h"
31 #ifdef HAVE_FLOAT_H
32 #include <float.h>
33 #endif
34 #ifdef HAVE_MATH_H
35 #include <math.h>
36 #endif
37
38 /**
39 * @file ucl_emitter.c
40 * Serialise UCL object to various of output formats
41 */
42
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);
45
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 first, bool print_key); \
51 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
52 const ucl_object_t *obj, bool first, 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)
57
58 /*
59 * JSON format operations
60 */
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);
66
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 \
73 }
74
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)
81 };
82
83 /*
84 * Utility to check whether we need a top object
85 */
86 #define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \
87 ((ctx)->id == UCL_EMIT_JSON_COMPACT || (ctx)->id == UCL_EMIT_JSON))
88
89
90 /**
91 * Add tabulation to the output buffer
92 * @param buf target buffer
93 * @param tabs number of tabs to add
94 */
95 static inline void
ucl_add_tabs(const struct ucl_emitter_functions * func,unsigned int tabs,bool compact)96 ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs,
97 bool compact)
98 {
99 if (!compact && tabs > 0) {
100 func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
101 }
102 }
103
104 /**
105 * Print key for the element
106 * @param ctx
107 * @param obj
108 */
109 static void
ucl_emitter_print_key(bool print_key,struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool compact)110 ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
111 const ucl_object_t *obj, bool compact)
112 {
113 const struct ucl_emitter_functions *func = ctx->func;
114
115 if (!print_key) {
116 return;
117 }
118
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);
122 }
123 else {
124 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
125 }
126
127 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
128 func->ucl_emitter_append_len (" = ", 3, func->ud);
129 }
130 else {
131 func->ucl_emitter_append_character (' ', 1, func->ud);
132 }
133 }
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);
137 }
138 else if (obj->keylen > 0) {
139 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
140 }
141 else {
142 func->ucl_emitter_append_len ("null", 4, func->ud);
143 }
144
145 func->ucl_emitter_append_len (": ", 2, func->ud);
146 }
147 else {
148 if (obj->keylen > 0) {
149 ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
150 }
151 else {
152 func->ucl_emitter_append_len ("null", 4, func->ud);
153 }
154
155 if (compact) {
156 func->ucl_emitter_append_character (':', 1, func->ud);
157 }
158 else {
159 func->ucl_emitter_append_len (": ", 2, func->ud);
160 }
161 }
162 }
163
164 static void
ucl_emitter_finish_object(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool compact,bool is_array)165 ucl_emitter_finish_object (struct ucl_emitter_context *ctx,
166 const ucl_object_t *obj, bool compact, bool is_array)
167 {
168 const struct ucl_emitter_functions *func = ctx->func;
169
170 if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
171 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
172 if (!is_array) {
173 /* Objects are split by ';' */
174 func->ucl_emitter_append_len (";\n", 2, func->ud);
175 }
176 else {
177 /* Use commas for arrays */
178 func->ucl_emitter_append_len (",\n", 2, func->ud);
179 }
180 }
181 else {
182 func->ucl_emitter_append_character ('\n', 1, func->ud);
183 }
184 }
185 }
186
187 /**
188 * End standard ucl object
189 * @param ctx emitter context
190 * @param compact compact flag
191 */
192 static void
ucl_emitter_common_end_object(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool compact)193 ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
194 const ucl_object_t *obj, bool compact)
195 {
196 const struct ucl_emitter_functions *func = ctx->func;
197
198 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
199 ctx->indent --;
200 if (compact) {
201 func->ucl_emitter_append_character ('}', 1, func->ud);
202 }
203 else {
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);
207 }
208 ucl_add_tabs (func, ctx->indent, compact);
209 func->ucl_emitter_append_character ('}', 1, func->ud);
210 }
211 }
212
213 ucl_emitter_finish_object (ctx, obj, compact, false);
214 }
215
216 /**
217 * End standard ucl array
218 * @param ctx emitter context
219 * @param compact compact flag
220 */
221 static void
ucl_emitter_common_end_array(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool compact)222 ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
223 const ucl_object_t *obj, bool compact)
224 {
225 const struct ucl_emitter_functions *func = ctx->func;
226
227 ctx->indent --;
228 if (compact) {
229 func->ucl_emitter_append_character (']', 1, func->ud);
230 }
231 else {
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);
235 }
236 ucl_add_tabs (func, ctx->indent, compact);
237 func->ucl_emitter_append_character (']', 1, func->ud);
238 }
239
240 ucl_emitter_finish_object (ctx, obj, compact, true);
241 }
242
243 /**
244 * Start emit standard UCL array
245 * @param ctx emitter context
246 * @param obj object to write
247 * @param compact compact flag
248 */
249 static void
ucl_emitter_common_start_array(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool first,bool print_key,bool compact)250 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
251 const ucl_object_t *obj, bool first, bool print_key, bool compact)
252 {
253 const ucl_object_t *cur;
254 ucl_object_iter_t iter = NULL;
255 const struct ucl_emitter_functions *func = ctx->func;
256 bool first_key = true;
257
258 if (ctx->id != UCL_EMIT_CONFIG && !first) {
259 if (compact) {
260 func->ucl_emitter_append_character (',', 1, func->ud);
261 }
262 else {
263 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
264 func->ucl_emitter_append_len ("\n", 1, func->ud);
265 } else {
266 func->ucl_emitter_append_len (",\n", 2, func->ud);
267 }
268 }
269 ucl_add_tabs (func, ctx->indent, compact);
270 }
271
272 ucl_emitter_print_key (print_key, ctx, obj, compact);
273
274 if (compact) {
275 func->ucl_emitter_append_character ('[', 1, func->ud);
276 }
277 else {
278 func->ucl_emitter_append_len ("[\n", 2, func->ud);
279 }
280
281 ctx->indent ++;
282
283 if (obj->type == UCL_ARRAY) {
284 /* explicit array */
285 while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) {
286 ucl_emitter_common_elt (ctx, cur, first_key, false, compact);
287 first_key = false;
288 }
289 }
290 else {
291 /* implicit array */
292 cur = obj;
293 while (cur) {
294 ucl_emitter_common_elt (ctx, cur, first_key, false, compact);
295 first_key = false;
296 cur = cur->next;
297 }
298 }
299
300
301 }
302
303 /**
304 * Start emit standard UCL object
305 * @param ctx emitter context
306 * @param obj object to write
307 * @param compact compact flag
308 */
309 static void
ucl_emitter_common_start_object(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool first,bool print_key,bool compact)310 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
311 const ucl_object_t *obj, bool first, bool print_key, bool compact)
312 {
313 ucl_hash_iter_t it = NULL;
314 const ucl_object_t *cur, *elt;
315 const struct ucl_emitter_functions *func = ctx->func;
316 bool first_key = true;
317
318 if (ctx->id != UCL_EMIT_CONFIG && !first) {
319 if (compact) {
320 func->ucl_emitter_append_character (',', 1, func->ud);
321 }
322 else {
323 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
324 func->ucl_emitter_append_len ("\n", 1, func->ud);
325 } else {
326 func->ucl_emitter_append_len (",\n", 2, func->ud);
327 }
328 }
329 ucl_add_tabs (func, ctx->indent, compact);
330 }
331
332 ucl_emitter_print_key (print_key, ctx, obj, compact);
333 /*
334 * Print <ident_level>{
335 * <ident_level + 1><object content>
336 */
337 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
338 if (compact) {
339 func->ucl_emitter_append_character ('{', 1, func->ud);
340 }
341 else {
342 func->ucl_emitter_append_len ("{\n", 2, func->ud);
343 }
344 ctx->indent ++;
345 }
346
347 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
348
349 if (ctx->id == UCL_EMIT_CONFIG) {
350 LL_FOREACH (cur, elt) {
351 ucl_emitter_common_elt (ctx, elt, first_key, true, compact);
352 }
353 }
354 else {
355 /* Expand implicit arrays */
356 if (cur->next != NULL) {
357 if (!first_key) {
358 if (compact) {
359 func->ucl_emitter_append_character (',', 1, func->ud);
360 }
361 else {
362 func->ucl_emitter_append_len (",\n", 2, func->ud);
363 }
364 }
365 ucl_add_tabs (func, ctx->indent, compact);
366 ucl_emitter_common_start_array (ctx, cur, first_key, true, compact);
367 ucl_emitter_common_end_array (ctx, cur, compact);
368 }
369 else {
370 ucl_emitter_common_elt (ctx, cur, first_key, true, compact);
371 }
372 }
373
374 first_key = false;
375 }
376 }
377
378 /**
379 * Common choice of object emitting
380 * @param ctx emitter context
381 * @param obj object to print
382 * @param first flag to mark the first element
383 * @param print_key print key of an object
384 * @param compact compact output
385 */
386 static void
ucl_emitter_common_elt(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool first,bool print_key,bool compact)387 ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
388 const ucl_object_t *obj, bool first, bool print_key, bool compact)
389 {
390 const struct ucl_emitter_functions *func = ctx->func;
391 bool flag;
392 struct ucl_object_userdata *ud;
393 const ucl_object_t *comment = NULL, *cur_comment;
394 const char *ud_out = "";
395
396 if (ctx->id != UCL_EMIT_CONFIG && !first) {
397 if (compact) {
398 func->ucl_emitter_append_character (',', 1, func->ud);
399 }
400 else {
401 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
402 func->ucl_emitter_append_len ("\n", 1, func->ud);
403 } else {
404 func->ucl_emitter_append_len (",\n", 2, func->ud);
405 }
406 }
407 }
408
409 ucl_add_tabs (func, ctx->indent, compact);
410
411 if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
412 comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj,
413 sizeof (void *));
414
415 if (comment) {
416 if (!(comment->flags & UCL_OBJECT_INHERITED)) {
417 DL_FOREACH (comment, cur_comment) {
418 func->ucl_emitter_append_len (cur_comment->value.sv,
419 cur_comment->len,
420 func->ud);
421 func->ucl_emitter_append_character ('\n', 1, func->ud);
422 ucl_add_tabs (func, ctx->indent, compact);
423 }
424
425 comment = NULL;
426 }
427 }
428 }
429
430 switch (obj->type) {
431 case UCL_INT:
432 ucl_emitter_print_key (print_key, ctx, obj, compact);
433 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
434 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
435 break;
436 case UCL_FLOAT:
437 case UCL_TIME:
438 ucl_emitter_print_key (print_key, ctx, obj, compact);
439 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
440 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
441 break;
442 case UCL_BOOLEAN:
443 ucl_emitter_print_key (print_key, ctx, obj, compact);
444 flag = ucl_object_toboolean (obj);
445 if (flag) {
446 func->ucl_emitter_append_len ("true", 4, func->ud);
447 }
448 else {
449 func->ucl_emitter_append_len ("false", 5, func->ud);
450 }
451 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
452 break;
453 case UCL_STRING:
454 ucl_emitter_print_key (print_key, ctx, obj, compact);
455 if (ctx->id == UCL_EMIT_CONFIG) {
456 if (ucl_maybe_long_string (obj)) {
457 ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
458 } else {
459 if (obj->flags & UCL_OBJECT_SQUOTED) {
460 ucl_elt_string_write_squoted (obj->value.sv, obj->len, ctx);
461 } else {
462 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
463 }
464 }
465 }
466 else {
467 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
468 }
469 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
470 break;
471 case UCL_NULL:
472 ucl_emitter_print_key (print_key, ctx, obj, compact);
473 func->ucl_emitter_append_len ("null", 4, func->ud);
474 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
475 break;
476 case UCL_OBJECT:
477 ucl_emitter_common_start_object (ctx, obj, true, print_key, compact);
478 ucl_emitter_common_end_object (ctx, obj, compact);
479 break;
480 case UCL_ARRAY:
481 ucl_emitter_common_start_array (ctx, obj, true, print_key, compact);
482 ucl_emitter_common_end_array (ctx, obj, compact);
483 break;
484 case UCL_USERDATA:
485 ud = (struct ucl_object_userdata *)obj;
486 ucl_emitter_print_key (print_key, ctx, obj, compact);
487 if (ud->emitter) {
488 ud_out = ud->emitter (obj->value.ud);
489 if (ud_out == NULL) {
490 ud_out = "null";
491 }
492 }
493 ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
494 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
495 break;
496 }
497
498 if (comment) {
499 DL_FOREACH (comment, cur_comment) {
500 func->ucl_emitter_append_len (cur_comment->value.sv,
501 cur_comment->len,
502 func->ud);
503 func->ucl_emitter_append_character ('\n', 1, func->ud);
504
505 if (cur_comment->next) {
506 ucl_add_tabs (func, ctx->indent, compact);
507 }
508 }
509 }
510 }
511
512 /*
513 * Specific standard implementations of the emitter functions
514 */
515 #define UCL_EMIT_TYPE_IMPL(type, compact) \
516 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
517 const ucl_object_t *obj, bool first, bool print_key) { \
518 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
519 } \
520 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
521 const ucl_object_t *obj, bool first, bool print_key) { \
522 ucl_emitter_common_start_object (ctx, obj, first, print_key, (compact)); \
523 } \
524 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
525 const ucl_object_t *obj, bool first, bool print_key) { \
526 ucl_emitter_common_start_array (ctx, obj, first, print_key, (compact)); \
527 } \
528 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
529 const ucl_object_t *obj) { \
530 ucl_emitter_common_end_object (ctx, obj, (compact)); \
531 } \
532 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
533 const ucl_object_t *obj) { \
534 ucl_emitter_common_end_array (ctx, obj, (compact)); \
535 }
536
UCL_EMIT_TYPE_IMPL(json,false)537 UCL_EMIT_TYPE_IMPL(json, false)
538 UCL_EMIT_TYPE_IMPL(json_compact, true)
539 UCL_EMIT_TYPE_IMPL(config, false)
540 UCL_EMIT_TYPE_IMPL(yaml, false)
541
542 static void
543 ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
544 const ucl_object_t *obj, bool _first, bool print_key)
545 {
546 ucl_object_iter_t it;
547 struct ucl_object_userdata *ud;
548 const char *ud_out;
549 const ucl_object_t *cur, *celt;
550
551 switch (obj->type) {
552 case UCL_INT:
553 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
554 ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj));
555 break;
556
557 case UCL_FLOAT:
558 case UCL_TIME:
559 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
560 ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj));
561 break;
562
563 case UCL_BOOLEAN:
564 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
565 ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj));
566 break;
567
568 case UCL_STRING:
569 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
570
571 if (obj->flags & UCL_OBJECT_BINARY) {
572 ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
573 obj->len);
574 }
575 else {
576 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
577 }
578 break;
579
580 case UCL_NULL:
581 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
582 ucl_emitter_print_null_msgpack (ctx);
583 break;
584
585 case UCL_OBJECT:
586 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
587 ucl_emit_msgpack_start_obj (ctx, obj, false, print_key);
588 it = NULL;
589
590 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
591 LL_FOREACH (cur, celt) {
592 ucl_emit_msgpack_elt (ctx, celt, false, true);
593 /* XXX:
594 * in msgpack the length of objects is encoded within a single elt
595 * so in case of multi-value keys we are using merely the first
596 * element ignoring others
597 */
598 break;
599 }
600 }
601
602 break;
603
604 case UCL_ARRAY:
605 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
606 ucl_emit_msgpack_start_array (ctx, obj, false, print_key);
607 it = NULL;
608
609 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
610 ucl_emit_msgpack_elt (ctx, cur, false, false);
611 }
612
613 break;
614
615 case UCL_USERDATA:
616 ud = (struct ucl_object_userdata *)obj;
617 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
618
619 if (ud->emitter) {
620 ud_out = ud->emitter (obj->value.ud);
621 if (ud_out == NULL) {
622 ud_out = "null";
623 }
624 }
625 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
626 break;
627 }
628 }
629
630 static void
ucl_emit_msgpack_start_obj(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool _first,bool _print_key)631 ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx,
632 const ucl_object_t *obj, bool _first, bool _print_key)
633 {
634 ucl_emitter_print_object_msgpack (ctx, obj->len);
635 }
636
637 static void
ucl_emit_msgpack_start_array(struct ucl_emitter_context * ctx,const ucl_object_t * obj,bool _first,bool _print_key)638 ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx,
639 const ucl_object_t *obj, bool _first, bool _print_key)
640 {
641 ucl_emitter_print_array_msgpack (ctx, obj->len);
642 }
643
644 static void
ucl_emit_msgpack_end_object(struct ucl_emitter_context * ctx,const ucl_object_t * obj)645 ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx,
646 const ucl_object_t *obj)
647 {
648
649 }
650
651 static void
ucl_emit_msgpack_end_array(struct ucl_emitter_context * ctx,const ucl_object_t * obj)652 ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx,
653 const ucl_object_t *obj)
654 {
655
656 }
657
658 unsigned char *
ucl_object_emit(const ucl_object_t * obj,enum ucl_emitter emit_type)659 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
660 {
661 return ucl_object_emit_len (obj, emit_type, NULL);
662 }
663
664 unsigned char *
ucl_object_emit_len(const ucl_object_t * obj,enum ucl_emitter emit_type,size_t * outlen)665 ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
666 size_t *outlen)
667 {
668 unsigned char *res = NULL;
669 struct ucl_emitter_functions *func;
670 UT_string *s;
671
672 if (obj == NULL) {
673 return NULL;
674 }
675
676 func = ucl_object_emit_memory_funcs ((void **)&res);
677
678 if (func != NULL) {
679 s = func->ud;
680 ucl_object_emit_full (obj, emit_type, func, NULL);
681
682 if (outlen != NULL) {
683 *outlen = s->i;
684 }
685
686 ucl_object_emit_funcs_free (func);
687 }
688
689 return res;
690 }
691
692 bool
ucl_object_emit_full(const ucl_object_t * obj,enum ucl_emitter emit_type,struct ucl_emitter_functions * emitter,const ucl_object_t * comments)693 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
694 struct ucl_emitter_functions *emitter,
695 const ucl_object_t *comments)
696 {
697 const struct ucl_emitter_context *ctx;
698 struct ucl_emitter_context my_ctx;
699 bool res = false;
700
701 ctx = ucl_emit_get_standard_context (emit_type);
702 if (ctx != NULL) {
703 memcpy (&my_ctx, ctx, sizeof (my_ctx));
704 my_ctx.func = emitter;
705 my_ctx.indent = 0;
706 my_ctx.top = obj;
707 my_ctx.comments = comments;
708
709 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
710 res = true;
711 }
712
713 return res;
714 }
715