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
_ucl_emitter_free(void * p)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 *
ucl_emit_get_standard_context(enum ucl_emitter emit_type)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
ucl_elt_string_write_json(const char * str,size_t size,struct ucl_emitter_context * ctx)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
ucl_elt_string_write_squoted(const char * str,size_t size,struct ucl_emitter_context * ctx)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
ucl_elt_string_write_multiline(const char * str,size_t size,struct ucl_emitter_context * ctx)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
ucl_utstring_append_character(unsigned char c,size_t len,void * ud)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
ucl_utstring_append_len(const unsigned char * str,size_t len,void * ud)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
ucl_utstring_append_int(int64_t val,void * ud)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
ucl_utstring_append_double(double val,void * ud)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
ucl_file_append_character(unsigned char c,size_t len,void * ud)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
ucl_file_append_len(const unsigned char * str,size_t len,void * ud)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
ucl_file_append_int(int64_t val,void * ud)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
ucl_file_append_double(double val,void * ud)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
ucl_fd_append_character(unsigned char c,size_t len,void * ud)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
ucl_fd_append_len(const unsigned char * str,size_t len,void * ud)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
ucl_fd_append_int(int64_t val,void * ud)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
ucl_fd_append_double(double val,void * ud)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*
ucl_object_emit_memory_funcs(void ** pmem)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*
ucl_object_emit_file_funcs(FILE * fp)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*
ucl_object_emit_fd_funcs(int fd)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
ucl_object_emit_funcs_free(struct ucl_emitter_functions * f)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 *
ucl_object_emit_single_json(const ucl_object_t * obj)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
ucl_maybe_long_string(const ucl_object_t * obj)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