Coverage Report

Created: 2024-07-23 06:12

/src/rtpproxy/external/libucl/src/ucl_emitter.c
Line
Count
Source (jump to first uncovered line)
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
0
#define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \
87
0
    ((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
0
{
99
0
  if (!compact && tabs > 0) {
100
0
    func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
101
0
  }
102
0
}
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
0
{
113
0
  const struct ucl_emitter_functions *func = ctx->func;
114
115
0
  if (!print_key) {
116
0
    return;
117
0
  }
118
119
0
  if (ctx->id == UCL_EMIT_CONFIG) {
120
0
    if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
121
0
      ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
122
0
    }
123
0
    else {
124
0
      func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
125
0
    }
126
127
0
    if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
128
0
      func->ucl_emitter_append_len (" = ", 3, func->ud);
129
0
    }
130
0
    else {
131
0
      func->ucl_emitter_append_character (' ', 1, func->ud);
132
0
    }
133
0
  }
134
0
  else if (ctx->id == UCL_EMIT_YAML) {
135
0
    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
0
    else if (obj->keylen > 0) {
139
0
      func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
140
0
    }
141
0
    else {
142
0
      func->ucl_emitter_append_len ("null", 4, func->ud);
143
0
    }
144
145
0
    func->ucl_emitter_append_len (": ", 2, func->ud);
146
0
  }
147
0
  else {
148
0
    if (obj->keylen > 0) {
149
0
      ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
150
0
    }
151
0
    else {
152
0
      func->ucl_emitter_append_len ("null", 4, func->ud);
153
0
    }
154
155
0
    if (compact) {
156
0
      func->ucl_emitter_append_character (':', 1, func->ud);
157
0
    }
158
0
    else {
159
0
      func->ucl_emitter_append_len (": ", 2, func->ud);
160
0
    }
161
0
  }
162
0
}
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
0
{
168
0
  const struct ucl_emitter_functions *func = ctx->func;
169
170
0
  if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
171
0
    if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
172
0
      if (!is_array) {
173
        /* Objects are split by ';' */
174
0
        func->ucl_emitter_append_len (";\n", 2, func->ud);
175
0
      }
176
0
      else {
177
        /* Use commas for arrays */
178
0
        func->ucl_emitter_append_len (",\n", 2, func->ud);
179
0
      }
180
0
    }
181
0
    else {
182
0
      func->ucl_emitter_append_character ('\n', 1, func->ud);
183
0
    }
184
0
  }
185
0
}
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
0
{
196
0
  const struct ucl_emitter_functions *func = ctx->func;
197
198
0
  if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
199
0
    ctx->indent --;
200
0
    if (compact) {
201
0
      func->ucl_emitter_append_character ('}', 1, func->ud);
202
0
    }
203
0
    else {
204
0
      if (ctx->id != UCL_EMIT_CONFIG) {
205
        /* newline is already added for this format */
206
0
        func->ucl_emitter_append_character ('\n', 1, func->ud);
207
0
      }
208
0
      ucl_add_tabs (func, ctx->indent, compact);
209
0
      func->ucl_emitter_append_character ('}', 1, func->ud);
210
0
    }
211
0
  }
212
213
0
  ucl_emitter_finish_object (ctx, obj, compact, false);
214
0
}
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
0
{
225
0
  const struct ucl_emitter_functions *func = ctx->func;
226
227
0
  ctx->indent --;
228
0
  if (compact) {
229
0
    func->ucl_emitter_append_character (']', 1, func->ud);
230
0
  }
231
0
  else {
232
0
    if (ctx->id != UCL_EMIT_CONFIG) {
233
      /* newline is already added for this format */
234
0
      func->ucl_emitter_append_character ('\n', 1, func->ud);
235
0
    }
236
0
    ucl_add_tabs (func, ctx->indent, compact);
237
0
    func->ucl_emitter_append_character (']', 1, func->ud);
238
0
  }
239
240
0
  ucl_emitter_finish_object (ctx, obj, compact, true);
241
0
}
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
0
{
253
0
  const ucl_object_t *cur;
254
0
  ucl_object_iter_t iter = NULL;
255
0
  const struct ucl_emitter_functions *func = ctx->func;
256
0
  bool first = true;
257
258
0
  ucl_emitter_print_key (print_key, ctx, obj, compact);
259
260
0
  if (compact) {
261
0
    func->ucl_emitter_append_character ('[', 1, func->ud);
262
0
  }
263
0
  else {
264
0
    func->ucl_emitter_append_len ("[\n", 2, func->ud);
265
0
  }
266
267
0
  ctx->indent ++;
268
269
0
  if (obj->type == UCL_ARRAY) {
270
    /* explicit array */
271
0
    while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) {
272
0
      ucl_emitter_common_elt (ctx, cur, first, false, compact);
273
0
      first = false;
274
0
    }
275
0
  }
276
0
  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
0
    }
284
0
  }
285
286
287
0
}
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
0
{
299
0
  ucl_hash_iter_t it = NULL;
300
0
  const ucl_object_t *cur, *elt;
301
0
  const struct ucl_emitter_functions *func = ctx->func;
302
0
  bool first = true;
303
304
0
  ucl_emitter_print_key (print_key, ctx, obj, compact);
305
  /*
306
   * Print <ident_level>{
307
   * <ident_level + 1><object content>
308
   */
309
0
  if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
310
0
    if (compact) {
311
0
      func->ucl_emitter_append_character ('{', 1, func->ud);
312
0
    }
313
0
    else {
314
0
      func->ucl_emitter_append_len ("{\n", 2, func->ud);
315
0
    }
316
0
    ctx->indent ++;
317
0
  }
318
319
0
  while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
320
321
0
    if (ctx->id == UCL_EMIT_CONFIG) {
322
0
      LL_FOREACH (cur, elt) {
323
0
        ucl_emitter_common_elt (ctx, elt, first, true, compact);
324
0
      }
325
0
    }
326
0
    else {
327
      /* Expand implicit arrays */
328
0
      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
0
          else {
334
0
            func->ucl_emitter_append_len (",\n", 2, func->ud);
335
0
          }
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
0
      else {
342
0
        ucl_emitter_common_elt (ctx, cur, first, true, compact);
343
0
      }
344
0
    }
345
346
0
    first = false;
347
0
  }
348
0
}
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
0
{
362
0
  const struct ucl_emitter_functions *func = ctx->func;
363
0
  bool flag;
364
0
  struct ucl_object_userdata *ud;
365
0
  const ucl_object_t *comment = NULL, *cur_comment;
366
0
  const char *ud_out = "";
367
368
0
  if (ctx->id != UCL_EMIT_CONFIG && !first) {
369
0
    if (compact) {
370
0
      func->ucl_emitter_append_character (',', 1, func->ud);
371
0
    }
372
0
    else {
373
0
      if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
374
0
        func->ucl_emitter_append_len ("\n", 1, func->ud);
375
0
      } else {
376
0
        func->ucl_emitter_append_len (",\n", 2, func->ud);
377
0
      }
378
0
    }
379
0
  }
380
381
0
  ucl_add_tabs (func, ctx->indent, compact);
382
383
0
  if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
384
0
    comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj,
385
0
        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
0
  switch (obj->type) {
403
0
  case UCL_INT:
404
0
    ucl_emitter_print_key (print_key, ctx, obj, compact);
405
0
    func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
406
0
    ucl_emitter_finish_object (ctx, obj, compact, !print_key);
407
0
    break;
408
0
  case UCL_FLOAT:
409
0
  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
0
  case UCL_BOOLEAN:
415
0
    ucl_emitter_print_key (print_key, ctx, obj, compact);
416
0
    flag = ucl_object_toboolean (obj);
417
0
    if (flag) {
418
0
      func->ucl_emitter_append_len ("true", 4, func->ud);
419
0
    }
420
0
    else {
421
0
      func->ucl_emitter_append_len ("false", 5, func->ud);
422
0
    }
423
0
    ucl_emitter_finish_object (ctx, obj, compact, !print_key);
424
0
    break;
425
0
  case UCL_STRING:
426
0
    ucl_emitter_print_key (print_key, ctx, obj, compact);
427
0
    if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
428
0
      ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
429
0
    }
430
0
    else {
431
0
      ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
432
0
    }
433
0
    ucl_emitter_finish_object (ctx, obj, compact, !print_key);
434
0
    break;
435
0
  case UCL_NULL:
436
0
    ucl_emitter_print_key (print_key, ctx, obj, compact);
437
0
    func->ucl_emitter_append_len ("null", 4, func->ud);
438
0
    ucl_emitter_finish_object (ctx, obj, compact, !print_key);
439
0
    break;
440
0
  case UCL_OBJECT:
441
0
    ucl_emitter_common_start_object (ctx, obj, print_key, compact);
442
0
    ucl_emitter_common_end_object (ctx, obj, compact);
443
0
    break;
444
0
  case UCL_ARRAY:
445
0
    ucl_emitter_common_start_array (ctx, obj, print_key, compact);
446
0
    ucl_emitter_common_end_array (ctx, obj, compact);
447
0
    break;
448
0
  case UCL_USERDATA:
449
0
    ud = (struct ucl_object_userdata *)obj;
450
0
    ucl_emitter_print_key (print_key, ctx, obj, compact);
451
0
    if (ud->emitter) {
452
0
      ud_out = ud->emitter (obj->value.ud);
453
0
      if (ud_out == NULL) {
454
0
        ud_out = "null";
455
0
      }
456
0
    }
457
0
    ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
458
0
    ucl_emitter_finish_object (ctx, obj, compact, !print_key);
459
0
    break;
460
0
  }
461
462
0
  if (comment) {
463
0
    DL_FOREACH (comment, cur_comment) {
464
0
      func->ucl_emitter_append_len (cur_comment->value.sv,
465
0
          cur_comment->len,
466
0
          func->ud);
467
0
      func->ucl_emitter_append_character ('\n', 1, func->ud);
468
469
0
      if (cur_comment->next) {
470
0
        ucl_add_tabs (func, ctx->indent, compact);
471
0
      }
472
0
    }
473
0
  }
474
0
}
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
0
    const ucl_object_t *obj, bool first, bool print_key) { \
482
0
    ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \
483
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
484
  static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \
485
0
    const ucl_object_t *obj, bool print_key) { \
486
0
    ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \
487
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
488
  static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx,  \
489
0
    const ucl_object_t *obj, bool print_key) { \
490
0
    ucl_emitter_common_start_array (ctx, obj, print_key, (compact));  \
491
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
492
  static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx,  \
493
0
    const ucl_object_t *obj) { \
494
0
    ucl_emitter_common_end_object (ctx, obj, (compact));  \
495
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
496
  static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \
497
0
    const ucl_object_t *obj) { \
498
0
    ucl_emitter_common_end_array (ctx, obj, (compact)); \
499
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
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
0
{
510
0
  ucl_object_iter_t it;
511
0
  struct ucl_object_userdata *ud;
512
0
  const char *ud_out;
513
0
  const ucl_object_t *cur, *celt;
514
515
0
  switch (obj->type) {
516
0
  case UCL_INT:
517
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
518
0
    ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj));
519
0
    break;
520
521
0
  case UCL_FLOAT:
522
0
  case UCL_TIME:
523
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
524
0
    ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj));
525
0
    break;
526
527
0
  case UCL_BOOLEAN:
528
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
529
0
    ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj));
530
0
    break;
531
532
0
  case UCL_STRING:
533
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
534
535
0
    if (obj->flags & UCL_OBJECT_BINARY) {
536
0
      ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv,
537
0
          obj->len);
538
0
    }
539
0
    else {
540
0
      ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
541
0
    }
542
0
    break;
543
544
0
  case UCL_NULL:
545
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
546
0
    ucl_emitter_print_null_msgpack (ctx);
547
0
    break;
548
549
0
  case UCL_OBJECT:
550
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
551
0
    ucl_emit_msgpack_start_obj (ctx, obj, print_key);
552
0
    it = NULL;
553
554
0
    while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
555
0
      LL_FOREACH (cur, celt) {
556
0
        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
0
        break;
563
0
      }
564
0
    }
565
566
0
    break;
567
568
0
  case UCL_ARRAY:
569
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
570
0
    ucl_emit_msgpack_start_array (ctx, obj, print_key);
571
0
    it = NULL;
572
573
0
    while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
574
0
      ucl_emit_msgpack_elt (ctx, cur, false, false);
575
0
    }
576
577
0
    break;
578
579
0
  case UCL_USERDATA:
580
0
    ud = (struct ucl_object_userdata *)obj;
581
0
    ucl_emitter_print_key_msgpack (print_key, ctx, obj);
582
583
0
    if (ud->emitter) {
584
0
      ud_out = ud->emitter (obj->value.ud);
585
0
      if (ud_out == NULL) {
586
0
        ud_out = "null";
587
0
      }
588
0
    }
589
0
    ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len);
590
0
    break;
591
0
  }
592
0
}
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
0
{
598
0
  ucl_emitter_print_object_msgpack (ctx, obj->len);
599
0
}
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
0
{
605
0
  ucl_emitter_print_array_msgpack (ctx, obj->len);
606
0
}
607
608
static void
609
ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx,
610
    const ucl_object_t *obj)
611
0
{
612
613
0
}
614
615
static void
616
ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx,
617
    const ucl_object_t *obj)
618
0
{
619
620
0
}
621
622
unsigned char *
623
ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
624
0
{
625
0
  return ucl_object_emit_len (obj, emit_type, NULL);
626
0
}
627
628
unsigned char *
629
ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
630
    size_t *outlen)
631
0
{
632
0
  unsigned char *res = NULL;
633
0
  struct ucl_emitter_functions *func;
634
0
  UT_string *s;
635
636
0
  if (obj == NULL) {
637
0
    return NULL;
638
0
  }
639
640
0
  func = ucl_object_emit_memory_funcs ((void **)&res);
641
642
0
  if (func != NULL) {
643
0
    s = func->ud;
644
0
    ucl_object_emit_full (obj, emit_type, func, NULL);
645
646
0
    if (outlen != NULL) {
647
0
      *outlen = s->i;
648
0
    }
649
650
0
    ucl_object_emit_funcs_free (func);
651
0
  }
652
653
0
  return res;
654
0
}
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
0
{
661
0
  const struct ucl_emitter_context *ctx;
662
0
  struct ucl_emitter_context my_ctx;
663
0
  bool res = false;
664
665
0
  ctx = ucl_emit_get_standard_context (emit_type);
666
0
  if (ctx != NULL) {
667
0
    memcpy (&my_ctx, ctx, sizeof (my_ctx));
668
0
    my_ctx.func = emitter;
669
0
    my_ctx.indent = 0;
670
0
    my_ctx.top = obj;
671
0
    my_ctx.comments = comments;
672
673
0
    my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
674
0
    res = true;
675
0
  }
676
677
0
  return res;
678
0
}