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