Branch data Line data Source code
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 : 46098 : ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs,
97 : : bool compact)
98 : : {
99 [ + + + + ]: 46098 : if (!compact && tabs > 0) {
100 : 1065 : func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
101 : 1065 : }
102 : 46098 : }
103 : :
104 : : /**
105 : : * Print key for the element
106 : : * @param ctx
107 : : * @param obj
108 : : */
109 : : static void
110 : 45638 : ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
111 : : const ucl_object_t *obj, bool compact)
112 : : {
113 : 45638 : const struct ucl_emitter_functions *func = ctx->func;
114 : :
115 [ + + ]: 45638 : if (!print_key) {
116 : 5984 : return;
117 : : }
118 : :
119 [ + + ]: 39654 : if (ctx->id == UCL_EMIT_CONFIG) {
120 [ - + ]: 6583 : if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
121 : 0 : ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
122 : 0 : }
123 : : else {
124 : 6583 : func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
125 : : }
126 : :
127 [ + + + + ]: 6583 : if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
128 : 6135 : func->ucl_emitter_append_len (" = ", 3, func->ud);
129 : 6135 : }
130 : : else {
131 : 448 : func->ucl_emitter_append_character (' ', 1, func->ud);
132 : : }
133 : 6583 : }
134 [ + + ]: 33071 : else if (ctx->id == UCL_EMIT_YAML) {
135 [ + - - + ]: 64 : if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
136 : 0 : ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
137 : 0 : }
138 [ + - ]: 64 : else if (obj->keylen > 0) {
139 : 64 : func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
140 : 64 : }
141 : : else {
142 : 0 : func->ucl_emitter_append_len ("null", 4, func->ud);
143 : : }
144 : :
145 : 64 : func->ucl_emitter_append_len (": ", 2, func->ud);
146 : 64 : }
147 : : else {
148 [ + - ]: 33007 : if (obj->keylen > 0) {
149 : 33007 : ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
150 : 33007 : }
151 : : else {
152 : 0 : func->ucl_emitter_append_len ("null", 4, func->ud);
153 : : }
154 : :
155 [ + - ]: 33007 : if (compact) {
156 : 33007 : func->ucl_emitter_append_character (':', 1, func->ud);
157 : 33007 : }
158 : : else {
159 : 0 : func->ucl_emitter_append_len (": ", 2, func->ud);
160 : : }
161 : : }
162 : 45638 : }
163 : :
164 : : static void
165 : 45638 : ucl_emitter_finish_object (struct ucl_emitter_context *ctx,
166 : : const ucl_object_t *obj, bool compact, bool is_array)
167 : : {
168 : 45638 : const struct ucl_emitter_functions *func = ctx->func;
169 : :
170 [ + + + + ]: 45638 : if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
171 [ + + + + ]: 7148 : if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
172 [ + + ]: 6700 : if (!is_array) {
173 : : /* Objects are split by ';' */
174 : 6135 : func->ucl_emitter_append_len (";\n", 2, func->ud);
175 : 6135 : }
176 : : else {
177 : : /* Use commas for arrays */
178 : 565 : func->ucl_emitter_append_len (",\n", 2, func->ud);
179 : : }
180 : 6700 : }
181 : : else {
182 : 448 : func->ucl_emitter_append_character ('\n', 1, func->ud);
183 : : }
184 : 7148 : }
185 : 45638 : }
186 : :
187 : : /**
188 : : * End standard ucl object
189 : : * @param ctx emitter context
190 : : * @param compact compact flag
191 : : */
192 : : static void
193 : 6635 : ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
194 : : const ucl_object_t *obj, bool compact)
195 : : {
196 : 6635 : const struct ucl_emitter_functions *func = ctx->func;
197 : :
198 [ + + + + : 6635 : if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
+ - ]
199 : 6012 : ctx->indent --;
200 [ + + ]: 6012 : if (compact) {
201 : 5836 : func->ucl_emitter_append_character ('}', 1, func->ud);
202 : 5836 : }
203 : : else {
204 [ + + ]: 176 : if (ctx->id != UCL_EMIT_CONFIG) {
205 : : /* newline is already added for this format */
206 : 8 : func->ucl_emitter_append_character ('\n', 1, func->ud);
207 : 8 : }
208 : 176 : ucl_add_tabs (func, ctx->indent, compact);
209 : 176 : func->ucl_emitter_append_character ('}', 1, func->ud);
210 : : }
211 : 6012 : }
212 : :
213 : 6635 : ucl_emitter_finish_object (ctx, obj, compact, false);
214 : 6635 : }
215 : :
216 : : /**
217 : : * End standard ucl array
218 : : * @param ctx emitter context
219 : : * @param compact compact flag
220 : : */
221 : : static void
222 : 2594 : ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
223 : : const ucl_object_t *obj, bool compact)
224 : : {
225 : 2594 : const struct ucl_emitter_functions *func = ctx->func;
226 : :
227 : 2594 : ctx->indent --;
228 [ + + ]: 2594 : if (compact) {
229 : 2310 : func->ucl_emitter_append_character (']', 1, func->ud);
230 : 2310 : }
231 : : else {
232 [ + + ]: 284 : if (ctx->id != UCL_EMIT_CONFIG) {
233 : : /* newline is already added for this format */
234 : 4 : func->ucl_emitter_append_character ('\n', 1, func->ud);
235 : 4 : }
236 : 284 : ucl_add_tabs (func, ctx->indent, compact);
237 : 284 : func->ucl_emitter_append_character (']', 1, func->ud);
238 : : }
239 : :
240 : 2594 : ucl_emitter_finish_object (ctx, obj, compact, true);
241 : 2594 : }
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 : 2594 : 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 : 2594 : ucl_object_iter_t iter = NULL;
255 : 2594 : const struct ucl_emitter_functions *func = ctx->func;
256 : 2594 : bool first = true;
257 : :
258 : 2594 : ucl_emitter_print_key (print_key, ctx, obj, compact);
259 : :
260 [ + + ]: 2594 : if (compact) {
261 : 2310 : func->ucl_emitter_append_character ('[', 1, func->ud);
262 : 2310 : }
263 : : else {
264 : 284 : func->ucl_emitter_append_len ("[\n", 2, func->ud);
265 : : }
266 : :
267 : 2594 : ctx->indent ++;
268 : :
269 [ + - ]: 2594 : if (obj->type == UCL_ARRAY) {
270 : : /* explicit array */
271 [ + + ]: 5669 : while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) {
272 : 3075 : ucl_emitter_common_elt (ctx, cur, first, false, compact);
273 : 3075 : first = false;
274 : : }
275 : 2594 : }
276 : : else {
277 : : /* implicit array */
278 : 0 : cur = obj;
279 [ # # ]: 0 : while (cur) {
280 : 0 : ucl_emitter_common_elt (ctx, cur, first, false, compact);
281 : 0 : first = false;
282 : 0 : cur = cur->next;
283 : : }
284 : : }
285 : :
286 : :
287 : 2594 : }
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 : 6635 : ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
297 : : const ucl_object_t *obj, bool print_key, bool compact)
298 : : {
299 : 6635 : ucl_hash_iter_t it = NULL;
300 : : const ucl_object_t *cur, *elt;
301 : 6635 : const struct ucl_emitter_functions *func = ctx->func;
302 : 6635 : bool first = true;
303 : :
304 : 6635 : ucl_emitter_print_key (print_key, ctx, obj, compact);
305 : : /*
306 : : * Print <ident_level>{
307 : : * <ident_level + 1><object content>
308 : : */
309 [ + + + + : 6635 : if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
+ - ]
310 [ + + ]: 6012 : if (compact) {
311 : 5836 : func->ucl_emitter_append_character ('{', 1, func->ud);
312 : 5836 : }
313 : : else {
314 : 176 : func->ucl_emitter_append_len ("{\n", 2, func->ud);
315 : : }
316 : 6012 : ctx->indent ++;
317 : 6012 : }
318 : :
319 [ + + ]: 46289 : while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
320 : :
321 [ + + ]: 39654 : if (ctx->id == UCL_EMIT_CONFIG) {
322 [ + + ]: 13166 : LL_FOREACH (cur, elt) {
323 : 6583 : ucl_emitter_common_elt (ctx, elt, first, true, compact);
324 : 6583 : }
325 : 6583 : }
326 : : else {
327 : : /* Expand implicit arrays */
328 [ + - ]: 33071 : if (cur->next != NULL) {
329 [ # # ]: 0 : if (!first) {
330 [ # # ]: 0 : if (compact) {
331 : 0 : func->ucl_emitter_append_character (',', 1, func->ud);
332 : 0 : }
333 : : else {
334 : 0 : func->ucl_emitter_append_len (",\n", 2, func->ud);
335 : : }
336 : 0 : }
337 : 0 : ucl_add_tabs (func, ctx->indent, compact);
338 : 0 : ucl_emitter_common_start_array (ctx, cur, true, compact);
339 : 0 : ucl_emitter_common_end_array (ctx, cur, compact);
340 : 0 : }
341 : : else {
342 : 33071 : ucl_emitter_common_elt (ctx, cur, first, true, compact);
343 : : }
344 : : }
345 : :
346 : 39654 : first = false;
347 : : }
348 : 6635 : }
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 : 45638 : ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
360 : : const ucl_object_t *obj, bool first, bool print_key, bool compact)
361 : : {
362 : 45638 : const struct ucl_emitter_functions *func = ctx->func;
363 : : bool flag;
364 : : struct ucl_object_userdata *ud;
365 : 45638 : const ucl_object_t *comment = NULL, *cur_comment;
366 : 45638 : const char *ud_out = "";
367 : :
368 [ + + + + ]: 45638 : if (ctx->id != UCL_EMIT_CONFIG && !first) {
369 [ + + ]: 27419 : if (compact) {
370 : 27367 : func->ucl_emitter_append_character (',', 1, func->ud);
371 : 27367 : }
372 : : else {
373 [ + - - + ]: 52 : if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
374 : 52 : func->ucl_emitter_append_len ("\n", 1, func->ud);
375 : 52 : } else {
376 : 0 : func->ucl_emitter_append_len (",\n", 2, func->ud);
377 : : }
378 : : }
379 : 27419 : }
380 : :
381 : 45638 : ucl_add_tabs (func, ctx->indent, compact);
382 : :
383 [ - + # # ]: 45638 : if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
384 : 0 : comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj,
385 : : sizeof (void *));
386 : :
387 [ # # ]: 0 : if (comment) {
388 [ # # ]: 0 : if (!(comment->flags & UCL_OBJECT_INHERITED)) {
389 [ # # ]: 0 : DL_FOREACH (comment, cur_comment) {
390 : 0 : func->ucl_emitter_append_len (cur_comment->value.sv,
391 : 0 : cur_comment->len,
392 : 0 : func->ud);
393 : 0 : func->ucl_emitter_append_character ('\n', 1, func->ud);
394 : 0 : ucl_add_tabs (func, ctx->indent, compact);
395 : 0 : }
396 : :
397 : 0 : comment = NULL;
398 : 0 : }
399 : 0 : }
400 : 0 : }
401 : :
402 [ - - + + : 45638 : switch (obj->type) {
+ - + +
- ]
403 : : case UCL_INT:
404 : 3159 : ucl_emitter_print_key (print_key, ctx, obj, compact);
405 : 3159 : func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
406 : 3159 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
407 : 3159 : break;
408 : : case UCL_FLOAT:
409 : : case UCL_TIME:
410 : 0 : ucl_emitter_print_key (print_key, ctx, obj, compact);
411 : 0 : func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
412 : 0 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
413 : 0 : break;
414 : : case UCL_BOOLEAN:
415 : 862 : ucl_emitter_print_key (print_key, ctx, obj, compact);
416 : 862 : flag = ucl_object_toboolean (obj);
417 [ + + ]: 862 : if (flag) {
418 : 229 : func->ucl_emitter_append_len ("true", 4, func->ud);
419 : 229 : }
420 : : else {
421 : 633 : func->ucl_emitter_append_len ("false", 5, func->ud);
422 : : }
423 : 862 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
424 : 862 : break;
425 : : case UCL_STRING:
426 : 32388 : ucl_emitter_print_key (print_key, ctx, obj, compact);
427 [ + + ]: 32388 : if (ctx->id == UCL_EMIT_CONFIG) {
428 [ - + ]: 4921 : if (ucl_maybe_long_string (obj)) {
429 : 0 : ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
430 : 0 : } else {
431 [ - + ]: 4921 : if (obj->flags & UCL_OBJECT_SQUOTED) {
432 : 0 : ucl_elt_string_write_squoted (obj->value.sv, obj->len, ctx);
433 : 0 : } else {
434 : 4921 : ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
435 : : }
436 : : }
437 : 4921 : }
438 : : else {
439 : 27467 : ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
440 : : }
441 : 32388 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
442 : 32388 : break;
443 : : case UCL_NULL:
444 : 0 : ucl_emitter_print_key (print_key, ctx, obj, compact);
445 : 0 : func->ucl_emitter_append_len ("null", 4, func->ud);
446 : 0 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
447 : 0 : break;
448 : : case UCL_OBJECT:
449 : 6635 : ucl_emitter_common_start_object (ctx, obj, print_key, compact);
450 : 6635 : ucl_emitter_common_end_object (ctx, obj, compact);
451 : 6635 : break;
452 : : case UCL_ARRAY:
453 : 2594 : ucl_emitter_common_start_array (ctx, obj, print_key, compact);
454 : 2594 : ucl_emitter_common_end_array (ctx, obj, compact);
455 : 2594 : break;
456 : : case UCL_USERDATA:
457 : 0 : ud = (struct ucl_object_userdata *)obj;
458 : 0 : ucl_emitter_print_key (print_key, ctx, obj, compact);
459 [ # # ]: 0 : if (ud->emitter) {
460 : 0 : ud_out = ud->emitter (obj->value.ud);
461 [ # # ]: 0 : if (ud_out == NULL) {
462 : 0 : ud_out = "null";
463 : 0 : }
464 : 0 : }
465 : 0 : ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
466 : 0 : ucl_emitter_finish_object (ctx, obj, compact, !print_key);
467 : 0 : break;
468 : : }
469 : :
470 [ + - ]: 45638 : if (comment) {
471 [ # # ]: 0 : DL_FOREACH (comment, cur_comment) {
472 : 0 : func->ucl_emitter_append_len (cur_comment->value.sv,
473 : 0 : cur_comment->len,
474 : 0 : func->ud);
475 : 0 : func->ucl_emitter_append_character ('\n', 1, func->ud);
476 : :
477 [ # # ]: 0 : if (cur_comment->next) {
478 : 0 : ucl_add_tabs (func, ctx->indent, compact);
479 : 0 : }
480 : 0 : }
481 : 0 : }
482 : 45638 : }
483 : :
484 : : /*
485 : : * Specific standard implementations of the emitter functions
486 : : */
487 : : #define UCL_EMIT_TYPE_IMPL(type, compact) \
488 : : static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \
489 : : const ucl_object_t *obj, bool first, bool print_key) { \
490 : : ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
491 : : } \
492 : : static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
493 : : const ucl_object_t *obj, bool print_key) { \
494 : : ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \
495 : : } \
496 : : static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \
497 : : const ucl_object_t *obj, bool print_key) { \
498 : : ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \
499 : : } \
500 : : static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \
501 : : const ucl_object_t *obj) { \
502 : : ucl_emitter_common_end_object (ctx, obj, (compact)); \
503 : : } \
504 : : static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
505 : : const ucl_object_t *obj) { \
506 : : ucl_emitter_common_end_array (ctx, obj, (compact)); \
507 : : }
508 : :
509 : 0 : UCL_EMIT_TYPE_IMPL(json, false)
510 : 2286 : UCL_EMIT_TYPE_IMPL(json_compact, true)
511 : 619 : UCL_EMIT_TYPE_IMPL(config, false)
512 : 4 : UCL_EMIT_TYPE_IMPL(yaml, false)
513 : :
514 : : static void
515 : 0 : ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,
516 : : const ucl_object_t *obj, bool first, bool print_key)
517 : : {
518 : : ucl_object_iter_t it;
519 : : struct ucl_object_userdata *ud;
520 : : const char *ud_out;
521 : : const ucl_object_t *cur, *celt;
522 : :
523 [ # # # # : 0 : switch (obj->type) {
# # # #
# ]
524 : : case UCL_INT:
525 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
526 : 0 : ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj));
527 : 0 : break;
528 : :
529 : : case UCL_FLOAT:
530 : : case UCL_TIME:
531 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
532 : 0 : ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj));
533 : 0 : break;
534 : :
535 : : case UCL_BOOLEAN:
536 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
537 : 0 : ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj));
538 : 0 : break;
539 : :
540 : : case UCL_STRING:
541 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
542 : :
543 [ # # ]: 0 : if (obj->flags & UCL_OBJECT_BINARY) {
544 : 0 : ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
545 : 0 : obj->len);
546 : 0 : }
547 : : else {
548 : 0 : ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
549 : : }
550 : 0 : break;
551 : :
552 : : case UCL_NULL:
553 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
554 : 0 : ucl_emitter_print_null_msgpack (ctx);
555 : 0 : break;
556 : :
557 : : case UCL_OBJECT:
558 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
559 : 0 : ucl_emit_msgpack_start_obj (ctx, obj, print_key);
560 : 0 : it = NULL;
561 : :
562 [ # # ]: 0 : while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
563 [ # # ]: 0 : LL_FOREACH (cur, celt) {
564 : 0 : ucl_emit_msgpack_elt (ctx, celt, false, true);
565 : : /* XXX:
566 : : * in msgpack the length of objects is encoded within a single elt
567 : : * so in case of multi-value keys we are using merely the first
568 : : * element ignoring others
569 : : */
570 : 0 : break;
571 : : }
572 : : }
573 : :
574 : 0 : break;
575 : :
576 : : case UCL_ARRAY:
577 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
578 : 0 : ucl_emit_msgpack_start_array (ctx, obj, print_key);
579 : 0 : it = NULL;
580 : :
581 [ # # ]: 0 : while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
582 : 0 : ucl_emit_msgpack_elt (ctx, cur, false, false);
583 : : }
584 : :
585 : 0 : break;
586 : :
587 : : case UCL_USERDATA:
588 : 0 : ud = (struct ucl_object_userdata *)obj;
589 : 0 : ucl_emitter_print_key_msgpack (print_key, ctx, obj);
590 : :
591 [ # # ]: 0 : if (ud->emitter) {
592 : 0 : ud_out = ud->emitter (obj->value.ud);
593 [ # # ]: 0 : if (ud_out == NULL) {
594 : 0 : ud_out = "null";
595 : 0 : }
596 : 0 : }
597 : 0 : ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
598 : 0 : break;
599 : : }
600 : 0 : }
601 : :
602 : : static void
603 : 0 : ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx,
604 : : const ucl_object_t *obj, bool print_key)
605 : : {
606 : 0 : ucl_emitter_print_object_msgpack (ctx, obj->len);
607 : 0 : }
608 : :
609 : : static void
610 : 0 : ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx,
611 : : const ucl_object_t *obj, bool print_key)
612 : : {
613 : 0 : ucl_emitter_print_array_msgpack (ctx, obj->len);
614 : 0 : }
615 : :
616 : : static void
617 : 0 : ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx,
618 : : const ucl_object_t *obj)
619 : : {
620 : :
621 : 0 : }
622 : :
623 : : static void
624 : 0 : ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx,
625 : : const ucl_object_t *obj)
626 : : {
627 : :
628 : 0 : }
629 : :
630 : : unsigned char *
631 : 90 : ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
632 : : {
633 : 90 : return ucl_object_emit_len (obj, emit_type, NULL);
634 : : }
635 : :
636 : : unsigned char *
637 : 90 : ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
638 : : size_t *outlen)
639 : : {
640 : 90 : unsigned char *res = NULL;
641 : : struct ucl_emitter_functions *func;
642 : : UT_string *s;
643 : :
644 [ + - ]: 90 : if (obj == NULL) {
645 : 0 : return NULL;
646 : : }
647 : :
648 : 90 : func = ucl_object_emit_memory_funcs ((void **)&res);
649 : :
650 [ - + ]: 90 : if (func != NULL) {
651 : 90 : s = func->ud;
652 : 90 : ucl_object_emit_full (obj, emit_type, func, NULL);
653 : :
654 [ + - ]: 90 : if (outlen != NULL) {
655 : 0 : *outlen = s->i;
656 : 0 : }
657 : :
658 : 90 : ucl_object_emit_funcs_free (func);
659 : 90 : }
660 : :
661 : 90 : return res;
662 : 90 : }
663 : :
664 : : bool
665 : 2909 : ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
666 : : struct ucl_emitter_functions *emitter,
667 : : const ucl_object_t *comments)
668 : : {
669 : : const struct ucl_emitter_context *ctx;
670 : : struct ucl_emitter_context my_ctx;
671 : 2909 : bool res = false;
672 : :
673 : 2909 : ctx = ucl_emit_get_standard_context (emit_type);
674 [ + - ]: 2909 : if (ctx != NULL) {
675 : 2909 : memcpy (&my_ctx, ctx, sizeof (my_ctx));
676 : 2909 : my_ctx.func = emitter;
677 : 2909 : my_ctx.indent = 0;
678 : 2909 : my_ctx.top = obj;
679 : 2909 : my_ctx.comments = comments;
680 : :
681 : 2909 : my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
682 : 2909 : res = true;
683 : 2909 : }
684 : :
685 : 2909 : return res;
686 : : }
|