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