]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/src/ucl_emitter_utils.c
Import OpenCSD -- an ARM CoreSight(tm) Trace Decode Library.
[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|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
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
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
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
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
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
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
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
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
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
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
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
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
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*
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*
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*
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
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 *
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
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 }