1 /* Copyright (c) 2014, Vsevolod Stakhov
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.
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.
29 #include "ucl_internal.h"
30 #include "ucl_chartable.h"
39 extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
41 static const struct ucl_emitter_context ucl_standard_emitters[] = {
46 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]
48 [UCL_EMIT_JSON_COMPACT] = {
49 .name = "json_compact",
50 .id = UCL_EMIT_JSON_COMPACT,
52 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
56 .id = UCL_EMIT_CONFIG,
58 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
64 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
66 [UCL_EMIT_MSGPACK] = {
68 .id = UCL_EMIT_MSGPACK,
70 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]
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
79 const struct ucl_emitter_context *
80 ucl_emit_get_standard_context (enum ucl_emitter emit_type)
82 if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
83 return &ucl_standard_emitters[emit_type];
91 * @param str string to emit
92 * @param buf target buffer
95 ucl_elt_string_write_json (const char *str, size_t size,
96 struct ucl_emitter_context *ctx)
98 const char *p = str, *c = str;
100 const struct ucl_emitter_functions *func = ctx->func;
102 func->ucl_emitter_append_character ('"', 1, func->ud);
105 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
107 func->ucl_emitter_append_len (c, len, func->ud);
111 func->ucl_emitter_append_len ("\\n", 2, func->ud);
114 func->ucl_emitter_append_len ("\\r", 2, func->ud);
117 func->ucl_emitter_append_len ("\\b", 2, func->ud);
120 func->ucl_emitter_append_len ("\\t", 2, func->ud);
123 func->ucl_emitter_append_len ("\\f", 2, func->ud);
126 func->ucl_emitter_append_len ("\\\\", 2, func->ud);
129 func->ucl_emitter_append_len ("\\\"", 2, func->ud);
142 func->ucl_emitter_append_len (c, len, func->ud);
144 func->ucl_emitter_append_character ('"', 1, func->ud);
148 ucl_elt_string_write_multiline (const char *str, size_t size,
149 struct ucl_emitter_context *ctx)
151 const struct ucl_emitter_functions *func = ctx->func;
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);
159 * Generic utstring output
162 ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
167 utstring_append_c (buf, c);
170 utstring_reserve (buf, len + 1);
171 memset (&buf->d[buf->i], c, len);
173 buf->d[buf->i] = '\0';
180 ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
184 utstring_append_len (buf, str, len);
190 ucl_utstring_append_int (int64_t val, void *ud)
194 utstring_printf (buf, "%jd", (intmax_t)val);
199 ucl_utstring_append_double (double val, void *ud)
202 const double delta = 0.0000001;
204 if (val == (double)(int)val) {
205 utstring_printf (buf, "%.1lf", val);
207 else if (fabs (val - (double)(int)val) < delta) {
208 /* Write at maximum precision */
209 utstring_printf (buf, "%.*lg", DBL_DIG, val);
212 utstring_printf (buf, "%lf", val);
219 * Generic file output
222 ucl_file_append_character (unsigned char c, size_t len, void *ud)
234 ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
238 fwrite (str, len, 1, fp);
244 ucl_file_append_int (int64_t val, void *ud)
248 fprintf (fp, "%jd", (intmax_t)val);
254 ucl_file_append_double (double val, void *ud)
257 const double delta = 0.0000001;
259 if (val == (double)(int)val) {
260 fprintf (fp, "%.1lf", val);
262 else if (fabs (val - (double)(int)val) < delta) {
263 /* Write at maximum precision */
264 fprintf (fp, "%.*lg", DBL_DIG, val);
267 fprintf (fp, "%lf", val);
274 * Generic file descriptor writing functions
277 ucl_fd_append_character (unsigned char c, size_t len, void *ud)
283 return write (fd, &c, 1);
290 if (write (fd, &c, 1) == -1) {
296 memset (buf, c, len);
297 if (write (fd, buf, len) == -1) {
309 ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
313 return write (fd, str, len);
317 ucl_fd_append_int (int64_t val, void *ud)
322 snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
323 return write (fd, intbuf, strlen (intbuf));
327 ucl_fd_append_double (double val, void *ud)
330 const double delta = 0.0000001;
333 if (val == (double)(int)val) {
334 snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
336 else if (fabs (val - (double)(int)val) < delta) {
337 /* Write at maximum precision */
338 snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
341 snprintf (nbuf, sizeof (nbuf), "%lf", val);
344 return write (fd, nbuf, strlen (nbuf));
347 struct ucl_emitter_functions*
348 ucl_object_emit_memory_funcs (void **pmem)
350 struct ucl_emitter_functions *f;
353 f = calloc (1, sizeof (*f));
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;
370 struct ucl_emitter_functions*
371 ucl_object_emit_file_funcs (FILE *fp)
373 struct ucl_emitter_functions *f;
375 f = calloc (1, sizeof (*f));
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;
389 struct ucl_emitter_functions*
390 ucl_object_emit_fd_funcs (int fd)
392 struct ucl_emitter_functions *f;
395 f = calloc (1, sizeof (*f));
398 ip = malloc (sizeof (fd));
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;
417 ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
420 if (f->ucl_emitter_free_func != NULL) {
421 f->ucl_emitter_free_func (f->ud);
429 ucl_object_emit_single_json (const ucl_object_t *obj)
431 UT_string *buf = NULL;
432 unsigned char *res = NULL;
443 ucl_utstring_append_len ("object", 6, buf);
446 ucl_utstring_append_len ("array", 5, buf);
449 ucl_utstring_append_int (obj->value.iv, buf);
453 ucl_utstring_append_double (obj->value.dv, buf);
456 ucl_utstring_append_len ("null", 4, buf);
460 ucl_utstring_append_len ("true", 4, buf);
463 ucl_utstring_append_len ("false", 5, buf);
467 ucl_utstring_append_len (obj->value.sv, obj->len, buf);
470 ucl_utstring_append_len ("userdata", 8, buf);
473 res = utstring_body (buf);
480 #define LONG_STRING_LIMIT 80
483 ucl_maybe_long_string (const ucl_object_t *obj)
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) {