Coverage Report

Created: 2026-09-13 06:44

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