xref: /freebsd/contrib/libucl/src/ucl_emitter.c (revision 2326db40a1d2dd98631d70aae200ca52575139fb)
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