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.
- checksums.yaml +4 -4
- data/LICENSE-DEPENDENCIES.md +161 -0
- data/README.md +104 -15
- data/ext/extconf.rb +42 -40
- data/ext/libucl/COPYING +23 -0
- data/ext/libucl/include/ucl.h +1689 -0
- data/ext/libucl/klib/khash.h +627 -0
- data/ext/libucl/klib/kvec.h +161 -0
- data/ext/libucl/src/mum.h +440 -0
- data/ext/libucl/src/tree.h +209 -0
- data/ext/libucl/src/ucl_chartable.h +267 -0
- data/ext/libucl/src/ucl_emitter.c +721 -0
- data/ext/libucl/src/ucl_emitter_streamline.c +178 -0
- data/ext/libucl/src/ucl_emitter_utils.c +521 -0
- data/ext/libucl/src/ucl_hash.c +642 -0
- data/ext/libucl/src/ucl_hash.h +115 -0
- data/ext/libucl/src/ucl_internal.h +668 -0
- data/ext/libucl/src/ucl_msgpack.c +1574 -0
- data/ext/libucl/src/ucl_parser.c +3247 -0
- data/ext/libucl/src/ucl_schema.c +1102 -0
- data/ext/libucl/src/ucl_sexp.c +229 -0
- data/ext/libucl/src/ucl_util.c +4004 -0
- data/ext/libucl/uthash/uthash.h +720 -0
- data/ext/libucl/uthash/utlist.h +1076 -0
- data/ext/libucl/uthash/utstring.h +412 -0
- data/ext/ucl.c +308 -89
- data/test/test_ucl.rb +129 -0
- data/ucl.gemspec +20 -7
- metadata +25 -17
|
@@ -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
|
+
}
|