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