]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/src/ucl_emitter.c
dts: Import DTS for arm64
[FreeBSD/FreeBSD.git] / contrib / libucl / src / ucl_emitter.c
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 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)
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
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
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
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
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
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
250 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
251                 const ucl_object_t *obj, 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 = true;
257
258         ucl_emitter_print_key (print_key, ctx, obj, compact);
259
260         if (compact) {
261                 func->ucl_emitter_append_character ('[', 1, func->ud);
262         }
263         else {
264                 func->ucl_emitter_append_len ("[\n", 2, func->ud);
265         }
266
267         ctx->indent ++;
268
269         if (obj->type == UCL_ARRAY) {
270                 /* explicit array */
271                 while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) {
272                         ucl_emitter_common_elt (ctx, cur, first, false, compact);
273                         first = false;
274                 }
275         }
276         else {
277                 /* implicit array */
278                 cur = obj;
279                 while (cur) {
280                         ucl_emitter_common_elt (ctx, cur, first, false, compact);
281                         first = false;
282                         cur = cur->next;
283                 }
284         }
285
286
287 }
288
289 /**
290  * Start emit standard UCL object
291  * @param ctx emitter context
292  * @param obj object to write
293  * @param compact compact flag
294  */
295 static void
296 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
297                 const ucl_object_t *obj, bool print_key, bool compact)
298 {
299         ucl_hash_iter_t it = NULL;
300         const ucl_object_t *cur, *elt;
301         const struct ucl_emitter_functions *func = ctx->func;
302         bool first = true;
303
304         ucl_emitter_print_key (print_key, ctx, obj, compact);
305         /*
306          * Print <ident_level>{
307          * <ident_level + 1><object content>
308          */
309         if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
310                 if (compact) {
311                         func->ucl_emitter_append_character ('{', 1, func->ud);
312                 }
313                 else {
314                         func->ucl_emitter_append_len ("{\n", 2, func->ud);
315                 }
316                 ctx->indent ++;
317         }
318
319         while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
320
321                 if (ctx->id == UCL_EMIT_CONFIG) {
322                         LL_FOREACH (cur, elt) {
323                                 ucl_emitter_common_elt (ctx, elt, first, true, compact);
324                         }
325                 }
326                 else {
327                         /* Expand implicit arrays */
328                         if (cur->next != NULL) {
329                                 if (!first) {
330                                         if (compact) {
331                                                 func->ucl_emitter_append_character (',', 1, func->ud);
332                                         }
333                                         else {
334                                                 func->ucl_emitter_append_len (",\n", 2, func->ud);
335                                         }
336                                 }
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);
340                         }
341                         else {
342                                 ucl_emitter_common_elt (ctx, cur, first, true, compact);
343                         }
344                 }
345
346                 first = false;
347         }
348 }
349
350 /**
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
357  */
358 static void
359 ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
360                 const ucl_object_t *obj, bool first, bool print_key, bool compact)
361 {
362         const struct ucl_emitter_functions *func = ctx->func;
363         bool flag;
364         struct ucl_object_userdata *ud;
365         const ucl_object_t *comment = NULL, *cur_comment;
366         const char *ud_out = "";
367
368         if (ctx->id != UCL_EMIT_CONFIG && !first) {
369                 if (compact) {
370                         func->ucl_emitter_append_character (',', 1, func->ud);
371                 }
372                 else {
373                         if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
374                                 func->ucl_emitter_append_len ("\n", 1, func->ud);
375                         } else {
376                                 func->ucl_emitter_append_len (",\n", 2, func->ud);
377                         }
378                 }
379         }
380
381         ucl_add_tabs (func, ctx->indent, compact);
382
383         if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
384                 comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj,
385                                 sizeof (void *));
386
387                 if (comment) {
388                         if (!(comment->flags & UCL_OBJECT_INHERITED)) {
389                                 DL_FOREACH (comment, cur_comment) {
390                                         func->ucl_emitter_append_len (cur_comment->value.sv,
391                                                         cur_comment->len,
392                                                         func->ud);
393                                         func->ucl_emitter_append_character ('\n', 1, func->ud);
394                                         ucl_add_tabs (func, ctx->indent, compact);
395                                 }
396
397                                 comment = NULL;
398                         }
399                 }
400         }
401
402         switch (obj->type) {
403         case UCL_INT:
404                 ucl_emitter_print_key (print_key, ctx, obj, compact);
405                 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
406                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
407                 break;
408         case UCL_FLOAT:
409         case UCL_TIME:
410                 ucl_emitter_print_key (print_key, ctx, obj, compact);
411                 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
412                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
413                 break;
414         case UCL_BOOLEAN:
415                 ucl_emitter_print_key (print_key, ctx, obj, compact);
416                 flag = ucl_object_toboolean (obj);
417                 if (flag) {
418                         func->ucl_emitter_append_len ("true", 4, func->ud);
419                 }
420                 else {
421                         func->ucl_emitter_append_len ("false", 5, func->ud);
422                 }
423                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
424                 break;
425         case UCL_STRING:
426                 ucl_emitter_print_key (print_key, ctx, obj, compact);
427                 if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
428                         ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
429                 }
430                 else {
431                         ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
432                 }
433                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
434                 break;
435         case UCL_NULL:
436                 ucl_emitter_print_key (print_key, ctx, obj, compact);
437                 func->ucl_emitter_append_len ("null", 4, func->ud);
438                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
439                 break;
440         case UCL_OBJECT:
441                 ucl_emitter_common_start_object (ctx, obj, print_key, compact);
442                 ucl_emitter_common_end_object (ctx, obj, compact);
443                 break;
444         case UCL_ARRAY:
445                 ucl_emitter_common_start_array (ctx, obj, print_key, compact);
446                 ucl_emitter_common_end_array (ctx, obj, compact);
447                 break;
448         case UCL_USERDATA:
449                 ud = (struct ucl_object_userdata *)obj;
450                 ucl_emitter_print_key (print_key, ctx, obj, compact);
451                 if (ud->emitter) {
452                         ud_out = ud->emitter (obj->value.ud);
453                         if (ud_out == NULL) {
454                                 ud_out = "null";
455                         }
456                 }
457                 ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
458                 ucl_emitter_finish_object (ctx, obj, compact, !print_key);
459                 break;
460         }
461
462         if (comment) {
463                 DL_FOREACH (comment, cur_comment) {
464                         func->ucl_emitter_append_len (cur_comment->value.sv,
465                                         cur_comment->len,
466                                         func->ud);
467                         func->ucl_emitter_append_character ('\n', 1, func->ud);
468
469                         if (cur_comment->next) {
470                                 ucl_add_tabs (func, ctx->indent, compact);
471                         }
472                 }
473         }
474 }
475
476 /*
477  * Specific standard implementations of the emitter functions
478  */
479 #define UCL_EMIT_TYPE_IMPL(type, compact)               \
480         static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
481                 const ucl_object_t *obj, bool first, bool print_key) {  \
482                 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
483         }       \
484         static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx,   \
485                 const ucl_object_t *obj, bool print_key) {      \
486                 ucl_emitter_common_start_object (ctx, obj, print_key, (compact));       \
487         }       \
488         static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx,  \
489                 const ucl_object_t *obj, bool print_key) {      \
490                 ucl_emitter_common_start_array (ctx, obj, print_key, (compact));        \
491         }       \
492         static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx,    \
493                 const ucl_object_t *obj) {      \
494                 ucl_emitter_common_end_object (ctx, obj, (compact));    \
495         }       \
496         static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx,     \
497                 const ucl_object_t *obj) {      \
498                 ucl_emitter_common_end_array (ctx, obj, (compact));     \
499         }
500
501 UCL_EMIT_TYPE_IMPL(json, false)
502 UCL_EMIT_TYPE_IMPL(json_compact, true)
503 UCL_EMIT_TYPE_IMPL(config, false)
504 UCL_EMIT_TYPE_IMPL(yaml, false)
505
506 static void
507 ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
508                 const ucl_object_t *obj, bool first, bool print_key)
509 {
510         ucl_object_iter_t it;
511         struct ucl_object_userdata *ud;
512         const char *ud_out;
513         const ucl_object_t *cur, *celt;
514
515         switch (obj->type) {
516         case UCL_INT:
517                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
518                 ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj));
519                 break;
520
521         case UCL_FLOAT:
522         case UCL_TIME:
523                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
524                 ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj));
525                 break;
526
527         case UCL_BOOLEAN:
528                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
529                 ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj));
530                 break;
531
532         case UCL_STRING:
533                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
534
535                 if (obj->flags & UCL_OBJECT_BINARY) {
536                         ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
537                                         obj->len);
538                 }
539                 else {
540                         ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
541                 }
542                 break;
543
544         case UCL_NULL:
545                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
546                 ucl_emitter_print_null_msgpack (ctx);
547                 break;
548
549         case UCL_OBJECT:
550                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
551                 ucl_emit_msgpack_start_obj (ctx, obj, print_key);
552                 it = NULL;
553
554                 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
555                         LL_FOREACH (cur, celt) {
556                                 ucl_emit_msgpack_elt (ctx, celt, false, true);
557                                 /* XXX:
558                                  * in msgpack the length of objects is encoded within a single elt
559                                  * so in case of multi-value keys we are using merely the first
560                                  * element ignoring others
561                                  */
562                                 break;
563                         }
564                 }
565
566                 break;
567
568         case UCL_ARRAY:
569                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
570                 ucl_emit_msgpack_start_array (ctx, obj, print_key);
571                 it = NULL;
572
573                 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
574                         ucl_emit_msgpack_elt (ctx, cur, false, false);
575                 }
576
577                 break;
578
579         case UCL_USERDATA:
580                 ud = (struct ucl_object_userdata *)obj;
581                 ucl_emitter_print_key_msgpack (print_key, ctx, obj);
582
583                 if (ud->emitter) {
584                         ud_out = ud->emitter (obj->value.ud);
585                         if (ud_out == NULL) {
586                                 ud_out = "null";
587                         }
588                 }
589                 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
590                 break;
591         }
592 }
593
594 static void
595 ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx,
596                 const ucl_object_t *obj, bool print_key)
597 {
598         ucl_emitter_print_object_msgpack (ctx, obj->len);
599 }
600
601 static void
602 ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx,
603                 const ucl_object_t *obj, bool print_key)
604 {
605         ucl_emitter_print_array_msgpack (ctx, obj->len);
606 }
607
608 static void
609 ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx,
610                 const ucl_object_t *obj)
611 {
612
613 }
614
615 static void
616 ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx,
617                 const ucl_object_t *obj)
618 {
619
620 }
621
622 unsigned char *
623 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
624 {
625         return ucl_object_emit_len (obj, emit_type, NULL);
626 }
627
628 unsigned char *
629 ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
630                 size_t *outlen)
631 {
632         unsigned char *res = NULL;
633         struct ucl_emitter_functions *func;
634         UT_string *s;
635
636         if (obj == NULL) {
637                 return NULL;
638         }
639
640         func = ucl_object_emit_memory_funcs ((void **)&res);
641
642         if (func != NULL) {
643                 s = func->ud;
644                 ucl_object_emit_full (obj, emit_type, func, NULL);
645
646                 if (outlen != NULL) {
647                         *outlen = s->i;
648                 }
649
650                 ucl_object_emit_funcs_free (func);
651         }
652
653         return res;
654 }
655
656 bool
657 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
658                 struct ucl_emitter_functions *emitter,
659                 const ucl_object_t *comments)
660 {
661         const struct ucl_emitter_context *ctx;
662         struct ucl_emitter_context my_ctx;
663         bool res = false;
664
665         ctx = ucl_emit_get_standard_context (emit_type);
666         if (ctx != NULL) {
667                 memcpy (&my_ctx, ctx, sizeof (my_ctx));
668                 my_ctx.func = emitter;
669                 my_ctx.indent = 0;
670                 my_ctx.top = obj;
671                 my_ctx.comments = comments;
672
673                 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
674                 res = true;
675         }
676
677         return res;
678 }