Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/libucl/src/ucl_emitter_utils.c
2066 views
1
/* Copyright (c) 2014, 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
32
#ifdef HAVE_FLOAT_H
33
#include <float.h>
34
#endif
35
#ifdef HAVE_MATH_H
36
#include <math.h>
37
#endif
38
39
extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
40
41
static const struct ucl_emitter_context ucl_standard_emitters[] = {
42
[UCL_EMIT_JSON] = {
43
.name = "json",
44
.id = UCL_EMIT_JSON,
45
.func = NULL,
46
.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]
47
},
48
[UCL_EMIT_JSON_COMPACT] = {
49
.name = "json_compact",
50
.id = UCL_EMIT_JSON_COMPACT,
51
.func = NULL,
52
.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
53
},
54
[UCL_EMIT_CONFIG] = {
55
.name = "config",
56
.id = UCL_EMIT_CONFIG,
57
.func = NULL,
58
.ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
59
},
60
[UCL_EMIT_YAML] = {
61
.name = "yaml",
62
.id = UCL_EMIT_YAML,
63
.func = NULL,
64
.ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
65
},
66
[UCL_EMIT_MSGPACK] = {
67
.name = "msgpack",
68
.id = UCL_EMIT_MSGPACK,
69
.func = NULL,
70
.ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]
71
}
72
};
73
74
static inline void
75
_ucl_emitter_free(void *p)
76
{
77
78
free(p);
79
}
80
81
/**
82
* Get standard emitter context for a specified emit_type
83
* @param emit_type type of emitter
84
* @return context or NULL if input is invalid
85
*/
86
const struct ucl_emitter_context *
87
ucl_emit_get_standard_context (enum ucl_emitter emit_type)
88
{
89
if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
90
return &ucl_standard_emitters[emit_type];
91
}
92
93
return NULL;
94
}
95
96
/**
97
* Serialise string
98
* @param str string to emit
99
* @param buf target buffer
100
*/
101
void
102
ucl_elt_string_write_json (const char *str, size_t size,
103
struct ucl_emitter_context *ctx)
104
{
105
const char *p = str, *c = str;
106
size_t len = 0;
107
const struct ucl_emitter_functions *func = ctx->func;
108
109
func->ucl_emitter_append_character ('"', 1, func->ud);
110
111
while (size) {
112
if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|
113
UCL_CHARACTER_DENIED|
114
UCL_CHARACTER_WHITESPACE_UNSAFE))) {
115
if (len > 0) {
116
func->ucl_emitter_append_len (c, len, func->ud);
117
}
118
switch (*p) {
119
case '\n':
120
func->ucl_emitter_append_len ("\\n", 2, func->ud);
121
break;
122
case '\r':
123
func->ucl_emitter_append_len ("\\r", 2, func->ud);
124
break;
125
case '\b':
126
func->ucl_emitter_append_len ("\\b", 2, func->ud);
127
break;
128
case '\t':
129
func->ucl_emitter_append_len ("\\t", 2, func->ud);
130
break;
131
case '\f':
132
func->ucl_emitter_append_len ("\\f", 2, func->ud);
133
break;
134
case '\v':
135
func->ucl_emitter_append_len ("\\u000B", 6, func->ud);
136
break;
137
case '\\':
138
func->ucl_emitter_append_len ("\\\\", 2, func->ud);
139
break;
140
case ' ':
141
func->ucl_emitter_append_character (' ', 1, func->ud);
142
break;
143
case '"':
144
func->ucl_emitter_append_len ("\\\"", 2, func->ud);
145
break;
146
default:
147
/* Emit unicode unknown character */
148
func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);
149
break;
150
}
151
len = 0;
152
c = ++p;
153
}
154
else {
155
p ++;
156
len ++;
157
}
158
size --;
159
}
160
161
if (len > 0) {
162
func->ucl_emitter_append_len (c, len, func->ud);
163
}
164
165
func->ucl_emitter_append_character ('"', 1, func->ud);
166
}
167
168
void
169
ucl_elt_string_write_squoted (const char *str, size_t size,
170
struct ucl_emitter_context *ctx)
171
{
172
const char *p = str, *c = str;
173
size_t len = 0;
174
const struct ucl_emitter_functions *func = ctx->func;
175
176
func->ucl_emitter_append_character ('\'', 1, func->ud);
177
178
while (size) {
179
if (*p == '\'') {
180
if (len > 0) {
181
func->ucl_emitter_append_len (c, len, func->ud);
182
}
183
184
len = 0;
185
c = ++p;
186
func->ucl_emitter_append_len ("\\\'", 2, func->ud);
187
}
188
else {
189
p ++;
190
len ++;
191
}
192
size --;
193
}
194
195
if (len > 0) {
196
func->ucl_emitter_append_len (c, len, func->ud);
197
}
198
199
func->ucl_emitter_append_character ('\'', 1, func->ud);
200
}
201
202
void
203
ucl_elt_string_write_multiline (const char *str, size_t size,
204
struct ucl_emitter_context *ctx)
205
{
206
const struct ucl_emitter_functions *func = ctx->func;
207
208
func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);
209
func->ucl_emitter_append_len (str, size, func->ud);
210
func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);
211
}
212
213
/*
214
* Generic utstring output
215
*/
216
static int
217
ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
218
{
219
UT_string *buf = ud;
220
221
if (len == 1) {
222
utstring_append_c (buf, c);
223
}
224
else {
225
utstring_reserve (buf, len + 1);
226
memset (&buf->d[buf->i], c, len);
227
buf->i += len;
228
buf->d[buf->i] = '\0';
229
}
230
231
return 0;
232
}
233
234
static int
235
ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
236
{
237
UT_string *buf = ud;
238
239
utstring_append_len (buf, str, len);
240
241
return 0;
242
}
243
244
static int
245
ucl_utstring_append_int (int64_t val, void *ud)
246
{
247
UT_string *buf = ud;
248
249
utstring_printf (buf, "%jd", (intmax_t)val);
250
return 0;
251
}
252
253
static int
254
ucl_utstring_append_double (double val, void *ud)
255
{
256
UT_string *buf = ud;
257
const double delta = 0.0000001;
258
259
if (val == (double)(int)val) {
260
utstring_printf (buf, "%.1lf", val);
261
}
262
else if (fabs (val - (double)(int)val) < delta) {
263
/* Write at maximum precision */
264
utstring_printf (buf, "%.*lg", DBL_DIG, val);
265
}
266
else {
267
utstring_printf (buf, "%lf", val);
268
}
269
270
return 0;
271
}
272
273
/*
274
* Generic file output
275
*/
276
static int
277
ucl_file_append_character (unsigned char c, size_t len, void *ud)
278
{
279
FILE *fp = ud;
280
281
while (len --) {
282
fputc (c, fp);
283
}
284
285
return 0;
286
}
287
288
static int
289
ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
290
{
291
FILE *fp = ud;
292
293
fwrite (str, len, 1, fp);
294
295
return 0;
296
}
297
298
static int
299
ucl_file_append_int (int64_t val, void *ud)
300
{
301
FILE *fp = ud;
302
303
fprintf (fp, "%jd", (intmax_t)val);
304
305
return 0;
306
}
307
308
static int
309
ucl_file_append_double (double val, void *ud)
310
{
311
FILE *fp = ud;
312
const double delta = 0.0000001;
313
314
if (val == (double)(int)val) {
315
fprintf (fp, "%.1lf", val);
316
}
317
else if (fabs (val - (double)(int)val) < delta) {
318
/* Write at maximum precision */
319
fprintf (fp, "%.*lg", DBL_DIG, val);
320
}
321
else {
322
fprintf (fp, "%lf", val);
323
}
324
325
return 0;
326
}
327
328
/*
329
* Generic file descriptor writing functions
330
*/
331
static int
332
ucl_fd_append_character (unsigned char c, size_t len, void *ud)
333
{
334
int fd = *(int *)ud;
335
unsigned char *buf;
336
337
if (len == 1) {
338
return write (fd, &c, 1);
339
}
340
else {
341
buf = malloc (len);
342
if (buf == NULL) {
343
/* Fallback */
344
while (len --) {
345
if (write (fd, &c, 1) == -1) {
346
return -1;
347
}
348
}
349
}
350
else {
351
memset (buf, c, len);
352
if (write (fd, buf, len) == -1) {
353
free(buf);
354
return -1;
355
}
356
free (buf);
357
}
358
}
359
360
return 0;
361
}
362
363
static int
364
ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
365
{
366
int fd = *(int *)ud;
367
368
return write (fd, str, len);
369
}
370
371
static int
372
ucl_fd_append_int (int64_t val, void *ud)
373
{
374
int fd = *(int *)ud;
375
char intbuf[64];
376
377
snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
378
return write (fd, intbuf, strlen (intbuf));
379
}
380
381
static int
382
ucl_fd_append_double (double val, void *ud)
383
{
384
int fd = *(int *)ud;
385
const double delta = 0.0000001;
386
char nbuf[64];
387
388
if (val == (double)(int)val) {
389
snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
390
}
391
else if (fabs (val - (double)(int)val) < delta) {
392
/* Write at maximum precision */
393
snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
394
}
395
else {
396
snprintf (nbuf, sizeof (nbuf), "%lf", val);
397
}
398
399
return write (fd, nbuf, strlen (nbuf));
400
}
401
402
struct ucl_emitter_functions*
403
ucl_object_emit_memory_funcs (void **pmem)
404
{
405
struct ucl_emitter_functions *f;
406
UT_string *s;
407
408
f = calloc (1, sizeof (*f));
409
410
if (f != NULL) {
411
f->ucl_emitter_append_character = ucl_utstring_append_character;
412
f->ucl_emitter_append_double = ucl_utstring_append_double;
413
f->ucl_emitter_append_int = ucl_utstring_append_int;
414
f->ucl_emitter_append_len = ucl_utstring_append_len;
415
f->ucl_emitter_free_func = _ucl_emitter_free;
416
utstring_new (s);
417
f->ud = s;
418
*pmem = s->d;
419
s->pd = pmem;
420
}
421
422
return f;
423
}
424
425
struct ucl_emitter_functions*
426
ucl_object_emit_file_funcs (FILE *fp)
427
{
428
struct ucl_emitter_functions *f;
429
430
f = calloc (1, sizeof (*f));
431
432
if (f != NULL) {
433
f->ucl_emitter_append_character = ucl_file_append_character;
434
f->ucl_emitter_append_double = ucl_file_append_double;
435
f->ucl_emitter_append_int = ucl_file_append_int;
436
f->ucl_emitter_append_len = ucl_file_append_len;
437
f->ucl_emitter_free_func = NULL;
438
f->ud = fp;
439
}
440
441
return f;
442
}
443
444
struct ucl_emitter_functions*
445
ucl_object_emit_fd_funcs (int fd)
446
{
447
struct ucl_emitter_functions *f;
448
int *ip;
449
450
f = calloc (1, sizeof (*f));
451
452
if (f != NULL) {
453
ip = malloc (sizeof (fd));
454
if (ip == NULL) {
455
free (f);
456
return NULL;
457
}
458
459
memcpy (ip, &fd, sizeof (fd));
460
f->ucl_emitter_append_character = ucl_fd_append_character;
461
f->ucl_emitter_append_double = ucl_fd_append_double;
462
f->ucl_emitter_append_int = ucl_fd_append_int;
463
f->ucl_emitter_append_len = ucl_fd_append_len;
464
f->ucl_emitter_free_func = _ucl_emitter_free;
465
f->ud = ip;
466
}
467
468
return f;
469
}
470
471
void
472
ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
473
{
474
if (f != NULL) {
475
if (f->ucl_emitter_free_func != NULL) {
476
f->ucl_emitter_free_func (f->ud);
477
}
478
free (f);
479
}
480
}
481
482
483
unsigned char *
484
ucl_object_emit_single_json (const ucl_object_t *obj)
485
{
486
UT_string *buf = NULL;
487
unsigned char *res = NULL;
488
489
if (obj == NULL) {
490
return NULL;
491
}
492
493
utstring_new (buf);
494
495
if (buf != NULL) {
496
switch (obj->type) {
497
case UCL_OBJECT:
498
ucl_utstring_append_len ("object", 6, buf);
499
break;
500
case UCL_ARRAY:
501
ucl_utstring_append_len ("array", 5, buf);
502
break;
503
case UCL_INT:
504
ucl_utstring_append_int (obj->value.iv, buf);
505
break;
506
case UCL_FLOAT:
507
case UCL_TIME:
508
ucl_utstring_append_double (obj->value.dv, buf);
509
break;
510
case UCL_NULL:
511
ucl_utstring_append_len ("null", 4, buf);
512
break;
513
case UCL_BOOLEAN:
514
if (obj->value.iv) {
515
ucl_utstring_append_len ("true", 4, buf);
516
}
517
else {
518
ucl_utstring_append_len ("false", 5, buf);
519
}
520
break;
521
case UCL_STRING:
522
ucl_utstring_append_len (obj->value.sv, obj->len, buf);
523
break;
524
case UCL_USERDATA:
525
ucl_utstring_append_len ("userdata", 8, buf);
526
break;
527
}
528
res = utstring_body (buf);
529
free (buf);
530
}
531
532
return res;
533
}
534
535
#define LONG_STRING_LIMIT 80
536
537
bool
538
ucl_maybe_long_string (const ucl_object_t *obj)
539
{
540
if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
541
/* String is long enough, so search for newline characters in it */
542
if (memchr (obj->value.sv, '\n', obj->len) != NULL) {
543
return true;
544
}
545
}
546
547
return false;
548
}
549
550