ucl 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,721 @@
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
+ #define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \
85
+ ((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
+ {
97
+ if (!compact && tabs > 0) {
98
+ func->ucl_emitter_append_character(' ', tabs * 4, func->ud);
99
+ }
100
+ }
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
+ {
111
+ const struct ucl_emitter_functions *func = ctx->func;
112
+
113
+ if (!print_key) {
114
+ return;
115
+ }
116
+
117
+ if (ctx->id == UCL_EMIT_CONFIG) {
118
+ if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
119
+ ucl_elt_string_write_json(obj->key, obj->keylen, ctx);
120
+ }
121
+ else {
122
+ func->ucl_emitter_append_len(obj->key, obj->keylen, func->ud);
123
+ }
124
+
125
+ if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
126
+ func->ucl_emitter_append_len(" = ", 3, func->ud);
127
+ }
128
+ else {
129
+ func->ucl_emitter_append_character(' ', 1, func->ud);
130
+ }
131
+ }
132
+ else if (ctx->id == UCL_EMIT_YAML) {
133
+ if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
134
+ ucl_elt_string_write_json(obj->key, obj->keylen, ctx);
135
+ }
136
+ else if (obj->keylen > 0) {
137
+ func->ucl_emitter_append_len(obj->key, obj->keylen, func->ud);
138
+ }
139
+ else {
140
+ func->ucl_emitter_append_len("null", 4, func->ud);
141
+ }
142
+
143
+ func->ucl_emitter_append_len(": ", 2, func->ud);
144
+ }
145
+ else {
146
+ if (obj->keylen > 0) {
147
+ ucl_elt_string_write_json(obj->key, obj->keylen, ctx);
148
+ }
149
+ else {
150
+ func->ucl_emitter_append_len("null", 4, func->ud);
151
+ }
152
+
153
+ if (compact) {
154
+ func->ucl_emitter_append_character(':', 1, func->ud);
155
+ }
156
+ else {
157
+ func->ucl_emitter_append_len(": ", 2, func->ud);
158
+ }
159
+ }
160
+ }
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
+ {
166
+ const struct ucl_emitter_functions *func = ctx->func;
167
+
168
+ if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) {
169
+ if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) {
170
+ if (!is_array) {
171
+ /* Objects are split by ';' */
172
+ func->ucl_emitter_append_len(";\n", 2, func->ud);
173
+ }
174
+ else {
175
+ /* Use commas for arrays */
176
+ func->ucl_emitter_append_len(",\n", 2, func->ud);
177
+ }
178
+ }
179
+ else {
180
+ func->ucl_emitter_append_character('\n', 1, func->ud);
181
+ }
182
+ }
183
+ }
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
+ {
194
+ const struct ucl_emitter_functions *func = ctx->func;
195
+
196
+ if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
197
+ ctx->indent--;
198
+ if (compact) {
199
+ func->ucl_emitter_append_character('}', 1, func->ud);
200
+ }
201
+ else {
202
+ if (ctx->id != UCL_EMIT_CONFIG) {
203
+ /* newline is already added for this format */
204
+ func->ucl_emitter_append_character('\n', 1, func->ud);
205
+ }
206
+ ucl_add_tabs(func, ctx->indent, compact);
207
+ func->ucl_emitter_append_character('}', 1, func->ud);
208
+ }
209
+ }
210
+
211
+ ucl_emitter_finish_object(ctx, obj, compact, false);
212
+ }
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
+ {
223
+ const struct ucl_emitter_functions *func = ctx->func;
224
+
225
+ ctx->indent--;
226
+ if (compact) {
227
+ func->ucl_emitter_append_character(']', 1, func->ud);
228
+ }
229
+ else {
230
+ if (ctx->id != UCL_EMIT_CONFIG) {
231
+ /* newline is already added for this format */
232
+ func->ucl_emitter_append_character('\n', 1, func->ud);
233
+ }
234
+ ucl_add_tabs(func, ctx->indent, compact);
235
+ func->ucl_emitter_append_character(']', 1, func->ud);
236
+ }
237
+
238
+ ucl_emitter_finish_object(ctx, obj, compact, true);
239
+ }
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
+ {
251
+ const ucl_object_t *cur;
252
+ ucl_object_iter_t iter = NULL;
253
+ const struct ucl_emitter_functions *func = ctx->func;
254
+ bool first_key = true;
255
+
256
+ if (ctx->id != UCL_EMIT_CONFIG && !first) {
257
+ if (compact) {
258
+ func->ucl_emitter_append_character(',', 1, func->ud);
259
+ }
260
+ else {
261
+ if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
262
+ func->ucl_emitter_append_len("\n", 1, func->ud);
263
+ }
264
+ else {
265
+ func->ucl_emitter_append_len(",\n", 2, func->ud);
266
+ }
267
+ }
268
+ ucl_add_tabs(func, ctx->indent, compact);
269
+ }
270
+
271
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
272
+
273
+ if (compact) {
274
+ func->ucl_emitter_append_character('[', 1, func->ud);
275
+ }
276
+ else {
277
+ func->ucl_emitter_append_len("[\n", 2, func->ud);
278
+ }
279
+
280
+ ctx->indent++;
281
+
282
+ if (obj->type == UCL_ARRAY) {
283
+ /* explicit array */
284
+ while ((cur = ucl_object_iterate(obj, &iter, true)) != NULL) {
285
+ ucl_emitter_common_elt(ctx, cur, first_key, false, compact);
286
+ first_key = false;
287
+ }
288
+ }
289
+ else {
290
+ /* implicit array */
291
+ cur = obj;
292
+ while (cur) {
293
+ ucl_emitter_common_elt(ctx, cur, first_key, false, compact);
294
+ first_key = false;
295
+ cur = cur->next;
296
+ }
297
+ }
298
+ }
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
+ {
310
+ ucl_hash_iter_t it = NULL;
311
+ const ucl_object_t *cur, *elt;
312
+ const struct ucl_emitter_functions *func = ctx->func;
313
+ bool first_key = true;
314
+
315
+ if (ctx->id != UCL_EMIT_CONFIG && !first) {
316
+ if (compact) {
317
+ func->ucl_emitter_append_character(',', 1, func->ud);
318
+ }
319
+ else {
320
+ if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
321
+ func->ucl_emitter_append_len("\n", 1, func->ud);
322
+ }
323
+ else {
324
+ func->ucl_emitter_append_len(",\n", 2, func->ud);
325
+ }
326
+ }
327
+ ucl_add_tabs(func, ctx->indent, compact);
328
+ }
329
+
330
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
331
+ /*
332
+ * Print <ident_level>{
333
+ * <ident_level + 1><object content>
334
+ */
335
+ if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
336
+ if (compact) {
337
+ func->ucl_emitter_append_character('{', 1, func->ud);
338
+ }
339
+ else {
340
+ func->ucl_emitter_append_len("{\n", 2, func->ud);
341
+ }
342
+ ctx->indent++;
343
+ }
344
+
345
+ while ((cur = ucl_hash_iterate(obj->value.ov, &it))) {
346
+
347
+ if (ctx->id == UCL_EMIT_CONFIG) {
348
+ LL_FOREACH(cur, elt)
349
+ {
350
+ ucl_emitter_common_elt(ctx, elt, first_key, true, compact);
351
+ }
352
+ }
353
+ else {
354
+ /* Expand implicit arrays */
355
+ if (cur->next != NULL) {
356
+ if (!first_key) {
357
+ if (compact) {
358
+ func->ucl_emitter_append_character(',', 1, func->ud);
359
+ }
360
+ else {
361
+ func->ucl_emitter_append_len(",\n", 2, func->ud);
362
+ }
363
+ }
364
+ ucl_add_tabs(func, ctx->indent, compact);
365
+ ucl_emitter_common_start_array(ctx, cur, true, true, compact);
366
+ ucl_emitter_common_end_array(ctx, cur, compact);
367
+ }
368
+ else {
369
+ ucl_emitter_common_elt(ctx, cur, first_key, true, compact);
370
+ }
371
+ }
372
+
373
+ first_key = false;
374
+ }
375
+ }
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
+ {
389
+ const struct ucl_emitter_functions *func = ctx->func;
390
+ bool flag;
391
+ struct ucl_object_userdata *ud;
392
+ const ucl_object_t *comment = NULL, *cur_comment;
393
+ const char *ud_out = "";
394
+
395
+ if (ctx->id != UCL_EMIT_CONFIG && !first) {
396
+ if (compact) {
397
+ func->ucl_emitter_append_character(',', 1, func->ud);
398
+ }
399
+ else {
400
+ if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
401
+ func->ucl_emitter_append_len("\n", 1, func->ud);
402
+ }
403
+ else {
404
+ func->ucl_emitter_append_len(",\n", 2, func->ud);
405
+ }
406
+ }
407
+ }
408
+
409
+ ucl_add_tabs(func, ctx->indent, compact);
410
+
411
+ if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
412
+ comment = ucl_object_lookup_len(ctx->comments, (const char *) &obj,
413
+ sizeof(void *));
414
+
415
+ if (comment) {
416
+ if (!(comment->flags & UCL_OBJECT_INHERITED)) {
417
+ DL_FOREACH(comment, cur_comment)
418
+ {
419
+ func->ucl_emitter_append_len(cur_comment->value.sv,
420
+ cur_comment->len,
421
+ func->ud);
422
+ func->ucl_emitter_append_character('\n', 1, func->ud);
423
+ ucl_add_tabs(func, ctx->indent, compact);
424
+ }
425
+
426
+ comment = NULL;
427
+ }
428
+ }
429
+ }
430
+
431
+ switch (obj->type) {
432
+ case UCL_INT:
433
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
434
+ func->ucl_emitter_append_int(ucl_object_toint(obj), func->ud);
435
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
436
+ break;
437
+ case UCL_FLOAT:
438
+ case UCL_TIME:
439
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
440
+ func->ucl_emitter_append_double(ucl_object_todouble(obj), func->ud);
441
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
442
+ break;
443
+ case UCL_BOOLEAN:
444
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
445
+ flag = ucl_object_toboolean(obj);
446
+ if (flag) {
447
+ func->ucl_emitter_append_len("true", 4, func->ud);
448
+ }
449
+ else {
450
+ func->ucl_emitter_append_len("false", 5, func->ud);
451
+ }
452
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
453
+ break;
454
+ case UCL_STRING:
455
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
456
+ if (ctx->id == UCL_EMIT_CONFIG) {
457
+ if (ucl_maybe_long_string(obj)) {
458
+ ucl_elt_string_write_multiline(obj->value.sv, obj->len, ctx);
459
+ }
460
+ else {
461
+ if (obj->flags & UCL_OBJECT_SQUOTED) {
462
+ ucl_elt_string_write_squoted(obj->value.sv, obj->len, ctx);
463
+ }
464
+ else {
465
+ ucl_elt_string_write_json(obj->value.sv, obj->len, ctx);
466
+ }
467
+ }
468
+ }
469
+ else {
470
+ ucl_elt_string_write_json(obj->value.sv, obj->len, ctx);
471
+ }
472
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
473
+ break;
474
+ case UCL_NULL:
475
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
476
+ func->ucl_emitter_append_len("null", 4, func->ud);
477
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
478
+ break;
479
+ case UCL_OBJECT:
480
+ ucl_emitter_common_start_object(ctx, obj, true, print_key, compact);
481
+ ucl_emitter_common_end_object(ctx, obj, compact);
482
+ break;
483
+ case UCL_ARRAY:
484
+ ucl_emitter_common_start_array(ctx, obj, true, print_key, compact);
485
+ ucl_emitter_common_end_array(ctx, obj, compact);
486
+ break;
487
+ case UCL_USERDATA:
488
+ ud = (struct ucl_object_userdata *) obj;
489
+ ucl_emitter_print_key(print_key, ctx, obj, compact);
490
+ if (ud->emitter) {
491
+ ud_out = ud->emitter(obj->value.ud);
492
+ if (ud_out == NULL) {
493
+ ud_out = "null";
494
+ }
495
+ }
496
+ ucl_elt_string_write_json(ud_out, strlen(ud_out), ctx);
497
+ ucl_emitter_finish_object(ctx, obj, compact, !print_key);
498
+ break;
499
+ }
500
+
501
+ if (comment) {
502
+ DL_FOREACH(comment, cur_comment)
503
+ {
504
+ func->ucl_emitter_append_len(cur_comment->value.sv,
505
+ cur_comment->len,
506
+ func->ud);
507
+ func->ucl_emitter_append_character('\n', 1, func->ud);
508
+
509
+ if (cur_comment->next) {
510
+ ucl_add_tabs(func, ctx->indent, compact);
511
+ }
512
+ }
513
+ }
514
+ }
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
+ { \
523
+ ucl_emitter_common_elt(ctx, obj, first, print_key, (compact)); \
524
+ } \
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
+ { \
528
+ ucl_emitter_common_start_object(ctx, obj, first, print_key, (compact)); \
529
+ } \
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
+ { \
533
+ ucl_emitter_common_start_array(ctx, obj, first, print_key, (compact)); \
534
+ } \
535
+ static void ucl_emit_##type##_end_object(struct ucl_emitter_context *ctx, \
536
+ const ucl_object_t *obj) \
537
+ { \
538
+ ucl_emitter_common_end_object(ctx, obj, (compact)); \
539
+ } \
540
+ static void ucl_emit_##type##_end_array(struct ucl_emitter_context *ctx, \
541
+ const ucl_object_t *obj) \
542
+ { \
543
+ ucl_emitter_common_end_array(ctx, obj, (compact)); \
544
+ }
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
+ {
555
+ ucl_object_iter_t it;
556
+ struct ucl_object_userdata *ud;
557
+ const char *ud_out;
558
+ const ucl_object_t *cur, *celt;
559
+
560
+ switch (obj->type) {
561
+ case UCL_INT:
562
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
563
+ ucl_emitter_print_int_msgpack(ctx, ucl_object_toint(obj));
564
+ break;
565
+
566
+ case UCL_FLOAT:
567
+ case UCL_TIME:
568
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
569
+ ucl_emitter_print_double_msgpack(ctx, ucl_object_todouble(obj));
570
+ break;
571
+
572
+ case UCL_BOOLEAN:
573
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
574
+ ucl_emitter_print_bool_msgpack(ctx, ucl_object_toboolean(obj));
575
+ break;
576
+
577
+ case UCL_STRING:
578
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
579
+
580
+ if (obj->flags & UCL_OBJECT_BINARY) {
581
+ ucl_emitter_print_binary_string_msgpack(ctx, obj->value.sv,
582
+ obj->len);
583
+ }
584
+ else {
585
+ ucl_emitter_print_string_msgpack(ctx, obj->value.sv, obj->len);
586
+ }
587
+ break;
588
+
589
+ case UCL_NULL:
590
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
591
+ ucl_emitter_print_null_msgpack(ctx);
592
+ break;
593
+
594
+ case UCL_OBJECT:
595
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
596
+ ucl_emit_msgpack_start_obj(ctx, obj, false, print_key);
597
+ it = NULL;
598
+
599
+ while ((cur = ucl_object_iterate(obj, &it, true)) != NULL) {
600
+ LL_FOREACH(cur, celt)
601
+ {
602
+ 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
+ break;
609
+ }
610
+ }
611
+
612
+ break;
613
+
614
+ case UCL_ARRAY:
615
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
616
+ ucl_emit_msgpack_start_array(ctx, obj, false, print_key);
617
+ it = NULL;
618
+
619
+ while ((cur = ucl_object_iterate(obj, &it, true)) != NULL) {
620
+ ucl_emit_msgpack_elt(ctx, cur, false, false);
621
+ }
622
+
623
+ break;
624
+
625
+ case UCL_USERDATA:
626
+ ud = (struct ucl_object_userdata *) obj;
627
+ ucl_emitter_print_key_msgpack(print_key, ctx, obj);
628
+
629
+ if (ud->emitter) {
630
+ ud_out = ud->emitter(obj->value.ud);
631
+ if (ud_out == NULL) {
632
+ ud_out = "null";
633
+ }
634
+ }
635
+ ucl_emitter_print_string_msgpack(ctx, obj->value.sv, obj->len);
636
+ break;
637
+ }
638
+ }
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
+ {
644
+ ucl_emitter_print_object_msgpack(ctx, obj->len);
645
+ }
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
+ {
651
+ ucl_emitter_print_array_msgpack(ctx, obj->len);
652
+ }
653
+
654
+ static void
655
+ ucl_emit_msgpack_end_object(struct ucl_emitter_context *ctx,
656
+ const ucl_object_t *obj)
657
+ {
658
+ }
659
+
660
+ static void
661
+ ucl_emit_msgpack_end_array(struct ucl_emitter_context *ctx,
662
+ const ucl_object_t *obj)
663
+ {
664
+ }
665
+
666
+ unsigned char *
667
+ ucl_object_emit(const ucl_object_t *obj, enum ucl_emitter emit_type)
668
+ {
669
+ return ucl_object_emit_len(obj, emit_type, NULL);
670
+ }
671
+
672
+ unsigned char *
673
+ ucl_object_emit_len(const ucl_object_t *obj, enum ucl_emitter emit_type,
674
+ size_t *outlen)
675
+ {
676
+ unsigned char *res = NULL;
677
+ struct ucl_emitter_functions *func;
678
+ UT_string *s;
679
+
680
+ if (obj == NULL) {
681
+ return NULL;
682
+ }
683
+
684
+ func = ucl_object_emit_memory_funcs((void **) &res);
685
+
686
+ if (func != NULL) {
687
+ s = func->ud;
688
+ ucl_object_emit_full(obj, emit_type, func, NULL);
689
+
690
+ if (outlen != NULL) {
691
+ *outlen = s->i;
692
+ }
693
+
694
+ ucl_object_emit_funcs_free(func);
695
+ }
696
+
697
+ return res;
698
+ }
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
+ {
704
+ const struct ucl_emitter_context *ctx;
705
+ struct ucl_emitter_context my_ctx;
706
+ bool res = false;
707
+
708
+ ctx = ucl_emit_get_standard_context(emit_type);
709
+ if (ctx != NULL) {
710
+ memcpy(&my_ctx, ctx, sizeof(my_ctx));
711
+ my_ctx.func = emitter;
712
+ my_ctx.indent = 0;
713
+ my_ctx.top = obj;
714
+ my_ctx.comments = comments;
715
+
716
+ my_ctx.ops->ucl_emitter_write_elt(&my_ctx, obj, true, false);
717
+ res = true;
718
+ }
719
+
720
+ return res;
721
+ }