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