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