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|UCL_CHARACTER_DENIED)) {
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);
132 /* Emit unicode unknown character */
133 func->ucl_emitter_append_len ("\\uFFFD", 5, func->ud);
147 func->ucl_emitter_append_len (c, len, func->ud);
150 func->ucl_emitter_append_character ('"', 1, func->ud);
154 ucl_elt_string_write_multiline (const char *str, size_t size,
155 struct ucl_emitter_context *ctx)
157 const struct ucl_emitter_functions *func = ctx->func;
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);
165 * Generic utstring output
168 ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
173 utstring_append_c (buf, c);
176 utstring_reserve (buf, len + 1);
177 memset (&buf->d[buf->i], c, len);
179 buf->d[buf->i] = '\0';
186 ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
190 utstring_append_len (buf, str, len);
196 ucl_utstring_append_int (int64_t val, void *ud)
200 utstring_printf (buf, "%jd", (intmax_t)val);
205 ucl_utstring_append_double (double val, void *ud)
208 const double delta = 0.0000001;
210 if (val == (double)(int)val) {
211 utstring_printf (buf, "%.1lf", val);
213 else if (fabs (val - (double)(int)val) < delta) {
214 /* Write at maximum precision */
215 utstring_printf (buf, "%.*lg", DBL_DIG, val);
218 utstring_printf (buf, "%lf", val);
225 * Generic file output
228 ucl_file_append_character (unsigned char c, size_t len, void *ud)
240 ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
244 fwrite (str, len, 1, fp);
250 ucl_file_append_int (int64_t val, void *ud)
254 fprintf (fp, "%jd", (intmax_t)val);
260 ucl_file_append_double (double val, void *ud)
263 const double delta = 0.0000001;
265 if (val == (double)(int)val) {
266 fprintf (fp, "%.1lf", val);
268 else if (fabs (val - (double)(int)val) < delta) {
269 /* Write at maximum precision */
270 fprintf (fp, "%.*lg", DBL_DIG, val);
273 fprintf (fp, "%lf", val);
280 * Generic file descriptor writing functions
283 ucl_fd_append_character (unsigned char c, size_t len, void *ud)
289 return write (fd, &c, 1);
296 if (write (fd, &c, 1) == -1) {
302 memset (buf, c, len);
303 if (write (fd, buf, len) == -1) {
315 ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
319 return write (fd, str, len);
323 ucl_fd_append_int (int64_t val, void *ud)
328 snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
329 return write (fd, intbuf, strlen (intbuf));
333 ucl_fd_append_double (double val, void *ud)
336 const double delta = 0.0000001;
339 if (val == (double)(int)val) {
340 snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
342 else if (fabs (val - (double)(int)val) < delta) {
343 /* Write at maximum precision */
344 snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
347 snprintf (nbuf, sizeof (nbuf), "%lf", val);
350 return write (fd, nbuf, strlen (nbuf));
353 struct ucl_emitter_functions*
354 ucl_object_emit_memory_funcs (void **pmem)
356 struct ucl_emitter_functions *f;
359 f = calloc (1, sizeof (*f));
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;
376 struct ucl_emitter_functions*
377 ucl_object_emit_file_funcs (FILE *fp)
379 struct ucl_emitter_functions *f;
381 f = calloc (1, sizeof (*f));
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;
395 struct ucl_emitter_functions*
396 ucl_object_emit_fd_funcs (int fd)
398 struct ucl_emitter_functions *f;
401 f = calloc (1, sizeof (*f));
404 ip = malloc (sizeof (fd));
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;
423 ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
426 if (f->ucl_emitter_free_func != NULL) {
427 f->ucl_emitter_free_func (f->ud);
435 ucl_object_emit_single_json (const ucl_object_t *obj)
437 UT_string *buf = NULL;
438 unsigned char *res = NULL;
449 ucl_utstring_append_len ("object", 6, buf);
452 ucl_utstring_append_len ("array", 5, buf);
455 ucl_utstring_append_int (obj->value.iv, buf);
459 ucl_utstring_append_double (obj->value.dv, buf);
462 ucl_utstring_append_len ("null", 4, buf);
466 ucl_utstring_append_len ("true", 4, buf);
469 ucl_utstring_append_len ("false", 5, buf);
473 ucl_utstring_append_len (obj->value.sv, obj->len, buf);
476 ucl_utstring_append_len ("userdata", 8, buf);
479 res = utstring_body (buf);
486 #define LONG_STRING_LIMIT 80
489 ucl_maybe_long_string (const ucl_object_t *obj)
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) {