13dcf5eb7SBaptiste Daroussin /* Copyright (c) 2014, Vsevolod Stakhov
23dcf5eb7SBaptiste Daroussin  * All rights reserved.
33dcf5eb7SBaptiste Daroussin  *
43dcf5eb7SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
53dcf5eb7SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
63dcf5eb7SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
73dcf5eb7SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
83dcf5eb7SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
93dcf5eb7SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
103dcf5eb7SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
113dcf5eb7SBaptiste Daroussin  *
123dcf5eb7SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
133dcf5eb7SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
143dcf5eb7SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
153dcf5eb7SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
163dcf5eb7SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
173dcf5eb7SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
183dcf5eb7SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
193dcf5eb7SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
203dcf5eb7SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
213dcf5eb7SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
223dcf5eb7SBaptiste Daroussin  */
233dcf5eb7SBaptiste Daroussin 
243dcf5eb7SBaptiste Daroussin #ifdef HAVE_CONFIG_H
253dcf5eb7SBaptiste Daroussin #include "config.h"
263dcf5eb7SBaptiste Daroussin #endif
273dcf5eb7SBaptiste Daroussin 
283dcf5eb7SBaptiste Daroussin #include "ucl.h"
293dcf5eb7SBaptiste Daroussin #include "ucl_internal.h"
303dcf5eb7SBaptiste Daroussin #include "ucl_chartable.h"
313dcf5eb7SBaptiste Daroussin 
323dcf5eb7SBaptiste Daroussin #ifdef HAVE_FLOAT_H
333dcf5eb7SBaptiste Daroussin #include <float.h>
343dcf5eb7SBaptiste Daroussin #endif
353dcf5eb7SBaptiste Daroussin #ifdef HAVE_MATH_H
363dcf5eb7SBaptiste Daroussin #include <math.h>
373dcf5eb7SBaptiste Daroussin #endif
383dcf5eb7SBaptiste Daroussin 
393dcf5eb7SBaptiste Daroussin extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
403dcf5eb7SBaptiste Daroussin 
413dcf5eb7SBaptiste Daroussin static const struct ucl_emitter_context ucl_standard_emitters[] = {
423dcf5eb7SBaptiste Daroussin 	[UCL_EMIT_JSON] = {
433dcf5eb7SBaptiste Daroussin 		.name = "json",
443dcf5eb7SBaptiste Daroussin 		.id = UCL_EMIT_JSON,
453dcf5eb7SBaptiste Daroussin 		.func = NULL,
463dcf5eb7SBaptiste Daroussin 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]
473dcf5eb7SBaptiste Daroussin 	},
483dcf5eb7SBaptiste Daroussin 	[UCL_EMIT_JSON_COMPACT] = {
493dcf5eb7SBaptiste Daroussin 		.name = "json_compact",
503dcf5eb7SBaptiste Daroussin 		.id = UCL_EMIT_JSON_COMPACT,
513dcf5eb7SBaptiste Daroussin 		.func = NULL,
523dcf5eb7SBaptiste Daroussin 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
533dcf5eb7SBaptiste Daroussin 	},
543dcf5eb7SBaptiste Daroussin 	[UCL_EMIT_CONFIG] = {
553dcf5eb7SBaptiste Daroussin 		.name = "config",
563dcf5eb7SBaptiste Daroussin 		.id = UCL_EMIT_CONFIG,
573dcf5eb7SBaptiste Daroussin 		.func = NULL,
583dcf5eb7SBaptiste Daroussin 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
593dcf5eb7SBaptiste Daroussin 	},
603dcf5eb7SBaptiste Daroussin 	[UCL_EMIT_YAML] = {
613dcf5eb7SBaptiste Daroussin 		.name = "yaml",
623dcf5eb7SBaptiste Daroussin 		.id = UCL_EMIT_YAML,
633dcf5eb7SBaptiste Daroussin 		.func = NULL,
643dcf5eb7SBaptiste Daroussin 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
6539ee7a7aSBaptiste Daroussin 	},
6639ee7a7aSBaptiste Daroussin 	[UCL_EMIT_MSGPACK] = {
6739ee7a7aSBaptiste Daroussin 		.name = "msgpack",
6839ee7a7aSBaptiste Daroussin 		.id = UCL_EMIT_MSGPACK,
6939ee7a7aSBaptiste Daroussin 		.func = NULL,
7039ee7a7aSBaptiste Daroussin 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]
713dcf5eb7SBaptiste Daroussin 	}
723dcf5eb7SBaptiste Daroussin };
733dcf5eb7SBaptiste Daroussin 
74*a0409676SBaptiste Daroussin static inline void
_ucl_emitter_free(void * p)75*a0409676SBaptiste Daroussin _ucl_emitter_free(void *p)
76*a0409676SBaptiste Daroussin {
77*a0409676SBaptiste Daroussin 
78*a0409676SBaptiste Daroussin     free(p);
79*a0409676SBaptiste Daroussin }
80*a0409676SBaptiste Daroussin 
813dcf5eb7SBaptiste Daroussin /**
823dcf5eb7SBaptiste Daroussin  * Get standard emitter context for a specified emit_type
833dcf5eb7SBaptiste Daroussin  * @param emit_type type of emitter
843dcf5eb7SBaptiste Daroussin  * @return context or NULL if input is invalid
853dcf5eb7SBaptiste Daroussin  */
863dcf5eb7SBaptiste Daroussin const struct ucl_emitter_context *
ucl_emit_get_standard_context(enum ucl_emitter emit_type)873dcf5eb7SBaptiste Daroussin ucl_emit_get_standard_context (enum ucl_emitter emit_type)
883dcf5eb7SBaptiste Daroussin {
8939ee7a7aSBaptiste Daroussin 	if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
903dcf5eb7SBaptiste Daroussin 		return &ucl_standard_emitters[emit_type];
913dcf5eb7SBaptiste Daroussin 	}
923dcf5eb7SBaptiste Daroussin 
933dcf5eb7SBaptiste Daroussin 	return NULL;
943dcf5eb7SBaptiste Daroussin }
953dcf5eb7SBaptiste Daroussin 
963dcf5eb7SBaptiste Daroussin /**
973dcf5eb7SBaptiste Daroussin  * Serialise string
983dcf5eb7SBaptiste Daroussin  * @param str string to emit
993dcf5eb7SBaptiste Daroussin  * @param buf target buffer
1003dcf5eb7SBaptiste Daroussin  */
1013dcf5eb7SBaptiste Daroussin void
ucl_elt_string_write_json(const char * str,size_t size,struct ucl_emitter_context * ctx)1023dcf5eb7SBaptiste Daroussin ucl_elt_string_write_json (const char *str, size_t size,
1033dcf5eb7SBaptiste Daroussin 		struct ucl_emitter_context *ctx)
1043dcf5eb7SBaptiste Daroussin {
1053dcf5eb7SBaptiste Daroussin 	const char *p = str, *c = str;
1063dcf5eb7SBaptiste Daroussin 	size_t len = 0;
1073dcf5eb7SBaptiste Daroussin 	const struct ucl_emitter_functions *func = ctx->func;
1083dcf5eb7SBaptiste Daroussin 
1093dcf5eb7SBaptiste Daroussin 	func->ucl_emitter_append_character ('"', 1, func->ud);
1103dcf5eb7SBaptiste Daroussin 
1113dcf5eb7SBaptiste Daroussin 	while (size) {
112*a0409676SBaptiste Daroussin 		if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|
113*a0409676SBaptiste Daroussin 				UCL_CHARACTER_DENIED|
114*a0409676SBaptiste Daroussin 				UCL_CHARACTER_WHITESPACE_UNSAFE))) {
1153dcf5eb7SBaptiste Daroussin 			if (len > 0) {
1163dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len (c, len, func->ud);
1173dcf5eb7SBaptiste Daroussin 			}
1183dcf5eb7SBaptiste Daroussin 			switch (*p) {
1193dcf5eb7SBaptiste Daroussin 			case '\n':
1203dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\n", 2, func->ud);
1213dcf5eb7SBaptiste Daroussin 				break;
1223dcf5eb7SBaptiste Daroussin 			case '\r':
1233dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\r", 2, func->ud);
1243dcf5eb7SBaptiste Daroussin 				break;
1253dcf5eb7SBaptiste Daroussin 			case '\b':
1263dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\b", 2, func->ud);
1273dcf5eb7SBaptiste Daroussin 				break;
1283dcf5eb7SBaptiste Daroussin 			case '\t':
1293dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\t", 2, func->ud);
1303dcf5eb7SBaptiste Daroussin 				break;
1313dcf5eb7SBaptiste Daroussin 			case '\f':
1323dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\f", 2, func->ud);
1333dcf5eb7SBaptiste Daroussin 				break;
134*a0409676SBaptiste Daroussin 			case '\v':
135*a0409676SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\u000B", 6, func->ud);
136*a0409676SBaptiste Daroussin 				break;
1373dcf5eb7SBaptiste Daroussin 			case '\\':
1383dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
1393dcf5eb7SBaptiste Daroussin 				break;
140*a0409676SBaptiste Daroussin 			case ' ':
141*a0409676SBaptiste Daroussin 				func->ucl_emitter_append_character (' ', 1, func->ud);
142*a0409676SBaptiste Daroussin 				break;
1433dcf5eb7SBaptiste Daroussin 			case '"':
1443dcf5eb7SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
1453dcf5eb7SBaptiste Daroussin 				break;
14611dd9ed6SBaptiste Daroussin 			default:
14711dd9ed6SBaptiste Daroussin 				/* Emit unicode unknown character */
148*a0409676SBaptiste Daroussin 				func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);
14911dd9ed6SBaptiste Daroussin 				break;
1503dcf5eb7SBaptiste Daroussin 			}
1513dcf5eb7SBaptiste Daroussin 			len = 0;
1523dcf5eb7SBaptiste Daroussin 			c = ++p;
1533dcf5eb7SBaptiste Daroussin 		}
1543dcf5eb7SBaptiste Daroussin 		else {
1553dcf5eb7SBaptiste Daroussin 			p ++;
1563dcf5eb7SBaptiste Daroussin 			len ++;
1573dcf5eb7SBaptiste Daroussin 		}
1583dcf5eb7SBaptiste Daroussin 		size --;
1593dcf5eb7SBaptiste Daroussin 	}
16011dd9ed6SBaptiste Daroussin 
1613dcf5eb7SBaptiste Daroussin 	if (len > 0) {
1623dcf5eb7SBaptiste Daroussin 		func->ucl_emitter_append_len (c, len, func->ud);
1633dcf5eb7SBaptiste Daroussin 	}
16411dd9ed6SBaptiste Daroussin 
1653dcf5eb7SBaptiste Daroussin 	func->ucl_emitter_append_character ('"', 1, func->ud);
1663dcf5eb7SBaptiste Daroussin }
1674bf54857SBaptiste Daroussin 
1684bf54857SBaptiste Daroussin void
ucl_elt_string_write_squoted(const char * str,size_t size,struct ucl_emitter_context * ctx)169*a0409676SBaptiste Daroussin ucl_elt_string_write_squoted (const char *str, size_t size,
170*a0409676SBaptiste Daroussin 		struct ucl_emitter_context *ctx)
171*a0409676SBaptiste Daroussin {
172*a0409676SBaptiste Daroussin 	const char *p = str, *c = str;
173*a0409676SBaptiste Daroussin 	size_t len = 0;
174*a0409676SBaptiste Daroussin 	const struct ucl_emitter_functions *func = ctx->func;
175*a0409676SBaptiste Daroussin 
176*a0409676SBaptiste Daroussin 	func->ucl_emitter_append_character ('\'', 1, func->ud);
177*a0409676SBaptiste Daroussin 
178*a0409676SBaptiste Daroussin 	while (size) {
179*a0409676SBaptiste Daroussin 		if (*p == '\'') {
180*a0409676SBaptiste Daroussin 			if (len > 0) {
181*a0409676SBaptiste Daroussin 				func->ucl_emitter_append_len (c, len, func->ud);
182*a0409676SBaptiste Daroussin 			}
183*a0409676SBaptiste Daroussin 
184*a0409676SBaptiste Daroussin 			len = 0;
185*a0409676SBaptiste Daroussin 			c = ++p;
186*a0409676SBaptiste Daroussin 			func->ucl_emitter_append_len ("\\\'", 2, func->ud);
187*a0409676SBaptiste Daroussin 		}
188*a0409676SBaptiste Daroussin 		else {
189*a0409676SBaptiste Daroussin 			p ++;
190*a0409676SBaptiste Daroussin 			len ++;
191*a0409676SBaptiste Daroussin 		}
192*a0409676SBaptiste Daroussin 		size --;
193*a0409676SBaptiste Daroussin 	}
194*a0409676SBaptiste Daroussin 
195*a0409676SBaptiste Daroussin 	if (len > 0) {
196*a0409676SBaptiste Daroussin 		func->ucl_emitter_append_len (c, len, func->ud);
197*a0409676SBaptiste Daroussin 	}
198*a0409676SBaptiste Daroussin 
199*a0409676SBaptiste Daroussin 	func->ucl_emitter_append_character ('\'', 1, func->ud);
200*a0409676SBaptiste Daroussin }
201*a0409676SBaptiste Daroussin 
202*a0409676SBaptiste Daroussin void
ucl_elt_string_write_multiline(const char * str,size_t size,struct ucl_emitter_context * ctx)2034bf54857SBaptiste Daroussin ucl_elt_string_write_multiline (const char *str, size_t size,
2044bf54857SBaptiste Daroussin 		struct ucl_emitter_context *ctx)
2054bf54857SBaptiste Daroussin {
2064bf54857SBaptiste Daroussin 	const struct ucl_emitter_functions *func = ctx->func;
2074bf54857SBaptiste Daroussin 
2084bf54857SBaptiste Daroussin 	func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);
2094bf54857SBaptiste Daroussin 	func->ucl_emitter_append_len (str, size, func->ud);
2104bf54857SBaptiste Daroussin 	func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);
2113dcf5eb7SBaptiste Daroussin }
2123dcf5eb7SBaptiste Daroussin 
2133dcf5eb7SBaptiste Daroussin /*
2143dcf5eb7SBaptiste Daroussin  * Generic utstring output
2153dcf5eb7SBaptiste Daroussin  */
2163dcf5eb7SBaptiste Daroussin static int
ucl_utstring_append_character(unsigned char c,size_t len,void * ud)2173dcf5eb7SBaptiste Daroussin ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
2183dcf5eb7SBaptiste Daroussin {
2193dcf5eb7SBaptiste Daroussin 	UT_string *buf = ud;
2203dcf5eb7SBaptiste Daroussin 
2213dcf5eb7SBaptiste Daroussin 	if (len == 1) {
2223dcf5eb7SBaptiste Daroussin 		utstring_append_c (buf, c);
2233dcf5eb7SBaptiste Daroussin 	}
2243dcf5eb7SBaptiste Daroussin 	else {
2254bf54857SBaptiste Daroussin 		utstring_reserve (buf, len + 1);
2263dcf5eb7SBaptiste Daroussin 		memset (&buf->d[buf->i], c, len);
2273dcf5eb7SBaptiste Daroussin 		buf->i += len;
2283dcf5eb7SBaptiste Daroussin 		buf->d[buf->i] = '\0';
2293dcf5eb7SBaptiste Daroussin 	}
2303dcf5eb7SBaptiste Daroussin 
2313dcf5eb7SBaptiste Daroussin 	return 0;
2323dcf5eb7SBaptiste Daroussin }
2333dcf5eb7SBaptiste Daroussin 
2343dcf5eb7SBaptiste Daroussin static int
ucl_utstring_append_len(const unsigned char * str,size_t len,void * ud)2353dcf5eb7SBaptiste Daroussin ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
2363dcf5eb7SBaptiste Daroussin {
2373dcf5eb7SBaptiste Daroussin 	UT_string *buf = ud;
2383dcf5eb7SBaptiste Daroussin 
2393dcf5eb7SBaptiste Daroussin 	utstring_append_len (buf, str, len);
2403dcf5eb7SBaptiste Daroussin 
2413dcf5eb7SBaptiste Daroussin 	return 0;
2423dcf5eb7SBaptiste Daroussin }
2433dcf5eb7SBaptiste Daroussin 
2443dcf5eb7SBaptiste Daroussin static int
ucl_utstring_append_int(int64_t val,void * ud)2453dcf5eb7SBaptiste Daroussin ucl_utstring_append_int (int64_t val, void *ud)
2463dcf5eb7SBaptiste Daroussin {
2473dcf5eb7SBaptiste Daroussin 	UT_string *buf = ud;
2483dcf5eb7SBaptiste Daroussin 
2493dcf5eb7SBaptiste Daroussin 	utstring_printf (buf, "%jd", (intmax_t)val);
2503dcf5eb7SBaptiste Daroussin 	return 0;
2513dcf5eb7SBaptiste Daroussin }
2523dcf5eb7SBaptiste Daroussin 
2533dcf5eb7SBaptiste Daroussin static int
ucl_utstring_append_double(double val,void * ud)2543dcf5eb7SBaptiste Daroussin ucl_utstring_append_double (double val, void *ud)
2553dcf5eb7SBaptiste Daroussin {
2563dcf5eb7SBaptiste Daroussin 	UT_string *buf = ud;
2573dcf5eb7SBaptiste Daroussin 	const double delta = 0.0000001;
2583dcf5eb7SBaptiste Daroussin 
2593dcf5eb7SBaptiste Daroussin 	if (val == (double)(int)val) {
2603dcf5eb7SBaptiste Daroussin 		utstring_printf (buf, "%.1lf", val);
2613dcf5eb7SBaptiste Daroussin 	}
2623dcf5eb7SBaptiste Daroussin 	else if (fabs (val - (double)(int)val) < delta) {
2633dcf5eb7SBaptiste Daroussin 		/* Write at maximum precision */
2643dcf5eb7SBaptiste Daroussin 		utstring_printf (buf, "%.*lg", DBL_DIG, val);
2653dcf5eb7SBaptiste Daroussin 	}
2663dcf5eb7SBaptiste Daroussin 	else {
2673dcf5eb7SBaptiste Daroussin 		utstring_printf (buf, "%lf", val);
2683dcf5eb7SBaptiste Daroussin 	}
2693dcf5eb7SBaptiste Daroussin 
2703dcf5eb7SBaptiste Daroussin 	return 0;
2713dcf5eb7SBaptiste Daroussin }
2723dcf5eb7SBaptiste Daroussin 
2733dcf5eb7SBaptiste Daroussin /*
2743dcf5eb7SBaptiste Daroussin  * Generic file output
2753dcf5eb7SBaptiste Daroussin  */
2763dcf5eb7SBaptiste Daroussin static int
ucl_file_append_character(unsigned char c,size_t len,void * ud)2773dcf5eb7SBaptiste Daroussin ucl_file_append_character (unsigned char c, size_t len, void *ud)
2783dcf5eb7SBaptiste Daroussin {
2793dcf5eb7SBaptiste Daroussin 	FILE *fp = ud;
2803dcf5eb7SBaptiste Daroussin 
2813dcf5eb7SBaptiste Daroussin 	while (len --) {
2823dcf5eb7SBaptiste Daroussin 		fputc (c, fp);
2833dcf5eb7SBaptiste Daroussin 	}
2843dcf5eb7SBaptiste Daroussin 
2853dcf5eb7SBaptiste Daroussin 	return 0;
2863dcf5eb7SBaptiste Daroussin }
2873dcf5eb7SBaptiste Daroussin 
2883dcf5eb7SBaptiste Daroussin static int
ucl_file_append_len(const unsigned char * str,size_t len,void * ud)2893dcf5eb7SBaptiste Daroussin ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
2903dcf5eb7SBaptiste Daroussin {
2913dcf5eb7SBaptiste Daroussin 	FILE *fp = ud;
2923dcf5eb7SBaptiste Daroussin 
2933dcf5eb7SBaptiste Daroussin 	fwrite (str, len, 1, fp);
2943dcf5eb7SBaptiste Daroussin 
2953dcf5eb7SBaptiste Daroussin 	return 0;
2963dcf5eb7SBaptiste Daroussin }
2973dcf5eb7SBaptiste Daroussin 
2983dcf5eb7SBaptiste Daroussin static int
ucl_file_append_int(int64_t val,void * ud)2993dcf5eb7SBaptiste Daroussin ucl_file_append_int (int64_t val, void *ud)
3003dcf5eb7SBaptiste Daroussin {
3013dcf5eb7SBaptiste Daroussin 	FILE *fp = ud;
3023dcf5eb7SBaptiste Daroussin 
3033dcf5eb7SBaptiste Daroussin 	fprintf (fp, "%jd", (intmax_t)val);
3043dcf5eb7SBaptiste Daroussin 
3053dcf5eb7SBaptiste Daroussin 	return 0;
3063dcf5eb7SBaptiste Daroussin }
3073dcf5eb7SBaptiste Daroussin 
3083dcf5eb7SBaptiste Daroussin static int
ucl_file_append_double(double val,void * ud)3093dcf5eb7SBaptiste Daroussin ucl_file_append_double (double val, void *ud)
3103dcf5eb7SBaptiste Daroussin {
3113dcf5eb7SBaptiste Daroussin 	FILE *fp = ud;
3123dcf5eb7SBaptiste Daroussin 	const double delta = 0.0000001;
3133dcf5eb7SBaptiste Daroussin 
3143dcf5eb7SBaptiste Daroussin 	if (val == (double)(int)val) {
3153dcf5eb7SBaptiste Daroussin 		fprintf (fp, "%.1lf", val);
3163dcf5eb7SBaptiste Daroussin 	}
3173dcf5eb7SBaptiste Daroussin 	else if (fabs (val - (double)(int)val) < delta) {
3183dcf5eb7SBaptiste Daroussin 		/* Write at maximum precision */
3193dcf5eb7SBaptiste Daroussin 		fprintf (fp, "%.*lg", DBL_DIG, val);
3203dcf5eb7SBaptiste Daroussin 	}
3213dcf5eb7SBaptiste Daroussin 	else {
3223dcf5eb7SBaptiste Daroussin 		fprintf (fp, "%lf", val);
3233dcf5eb7SBaptiste Daroussin 	}
3243dcf5eb7SBaptiste Daroussin 
3253dcf5eb7SBaptiste Daroussin 	return 0;
3263dcf5eb7SBaptiste Daroussin }
3273dcf5eb7SBaptiste Daroussin 
3283dcf5eb7SBaptiste Daroussin /*
3293dcf5eb7SBaptiste Daroussin  * Generic file descriptor writing functions
3303dcf5eb7SBaptiste Daroussin  */
3313dcf5eb7SBaptiste Daroussin static int
ucl_fd_append_character(unsigned char c,size_t len,void * ud)3323dcf5eb7SBaptiste Daroussin ucl_fd_append_character (unsigned char c, size_t len, void *ud)
3333dcf5eb7SBaptiste Daroussin {
3343dcf5eb7SBaptiste Daroussin 	int fd = *(int *)ud;
3353dcf5eb7SBaptiste Daroussin 	unsigned char *buf;
3363dcf5eb7SBaptiste Daroussin 
3373dcf5eb7SBaptiste Daroussin 	if (len == 1) {
3384bf54857SBaptiste Daroussin 		return write (fd, &c, 1);
3393dcf5eb7SBaptiste Daroussin 	}
3403dcf5eb7SBaptiste Daroussin 	else {
3413dcf5eb7SBaptiste Daroussin 		buf = malloc (len);
3423dcf5eb7SBaptiste Daroussin 		if (buf == NULL) {
3433dcf5eb7SBaptiste Daroussin 			/* Fallback */
3443dcf5eb7SBaptiste Daroussin 			while (len --) {
3454bf54857SBaptiste Daroussin 				if (write (fd, &c, 1) == -1) {
3464bf54857SBaptiste Daroussin 					return -1;
3474bf54857SBaptiste Daroussin 				}
3483dcf5eb7SBaptiste Daroussin 			}
3493dcf5eb7SBaptiste Daroussin 		}
3503dcf5eb7SBaptiste Daroussin 		else {
3513dcf5eb7SBaptiste Daroussin 			memset (buf, c, len);
3524bf54857SBaptiste Daroussin 			if (write (fd, buf, len) == -1) {
3538e3b1ab2SBaptiste Daroussin 				free(buf);
3544bf54857SBaptiste Daroussin 				return -1;
3554bf54857SBaptiste Daroussin 			}
3563dcf5eb7SBaptiste Daroussin 			free (buf);
3573dcf5eb7SBaptiste Daroussin 		}
3583dcf5eb7SBaptiste Daroussin 	}
3593dcf5eb7SBaptiste Daroussin 
3603dcf5eb7SBaptiste Daroussin 	return 0;
3613dcf5eb7SBaptiste Daroussin }
3623dcf5eb7SBaptiste Daroussin 
3633dcf5eb7SBaptiste Daroussin static int
ucl_fd_append_len(const unsigned char * str,size_t len,void * ud)3643dcf5eb7SBaptiste Daroussin ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
3653dcf5eb7SBaptiste Daroussin {
3663dcf5eb7SBaptiste Daroussin 	int fd = *(int *)ud;
3673dcf5eb7SBaptiste Daroussin 
3684bf54857SBaptiste Daroussin 	return write (fd, str, len);
3693dcf5eb7SBaptiste Daroussin }
3703dcf5eb7SBaptiste Daroussin 
3713dcf5eb7SBaptiste Daroussin static int
ucl_fd_append_int(int64_t val,void * ud)3723dcf5eb7SBaptiste Daroussin ucl_fd_append_int (int64_t val, void *ud)
3733dcf5eb7SBaptiste Daroussin {
3743dcf5eb7SBaptiste Daroussin 	int fd = *(int *)ud;
3753dcf5eb7SBaptiste Daroussin 	char intbuf[64];
3763dcf5eb7SBaptiste Daroussin 
3773dcf5eb7SBaptiste Daroussin 	snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
3784bf54857SBaptiste Daroussin 	return write (fd, intbuf, strlen (intbuf));
3793dcf5eb7SBaptiste Daroussin }
3803dcf5eb7SBaptiste Daroussin 
3813dcf5eb7SBaptiste Daroussin static int
ucl_fd_append_double(double val,void * ud)3823dcf5eb7SBaptiste Daroussin ucl_fd_append_double (double val, void *ud)
3833dcf5eb7SBaptiste Daroussin {
3843dcf5eb7SBaptiste Daroussin 	int fd = *(int *)ud;
3853dcf5eb7SBaptiste Daroussin 	const double delta = 0.0000001;
3863dcf5eb7SBaptiste Daroussin 	char nbuf[64];
3873dcf5eb7SBaptiste Daroussin 
3883dcf5eb7SBaptiste Daroussin 	if (val == (double)(int)val) {
3893dcf5eb7SBaptiste Daroussin 		snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
3903dcf5eb7SBaptiste Daroussin 	}
3913dcf5eb7SBaptiste Daroussin 	else if (fabs (val - (double)(int)val) < delta) {
3923dcf5eb7SBaptiste Daroussin 		/* Write at maximum precision */
3933dcf5eb7SBaptiste Daroussin 		snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
3943dcf5eb7SBaptiste Daroussin 	}
3953dcf5eb7SBaptiste Daroussin 	else {
3963dcf5eb7SBaptiste Daroussin 		snprintf (nbuf, sizeof (nbuf), "%lf", val);
3973dcf5eb7SBaptiste Daroussin 	}
3983dcf5eb7SBaptiste Daroussin 
3994bf54857SBaptiste Daroussin 	return write (fd, nbuf, strlen (nbuf));
4003dcf5eb7SBaptiste Daroussin }
4013dcf5eb7SBaptiste Daroussin 
4023dcf5eb7SBaptiste Daroussin struct ucl_emitter_functions*
ucl_object_emit_memory_funcs(void ** pmem)4033dcf5eb7SBaptiste Daroussin ucl_object_emit_memory_funcs (void **pmem)
4043dcf5eb7SBaptiste Daroussin {
4053dcf5eb7SBaptiste Daroussin 	struct ucl_emitter_functions *f;
4063dcf5eb7SBaptiste Daroussin 	UT_string *s;
4073dcf5eb7SBaptiste Daroussin 
4083dcf5eb7SBaptiste Daroussin 	f = calloc (1, sizeof (*f));
4093dcf5eb7SBaptiste Daroussin 
4103dcf5eb7SBaptiste Daroussin 	if (f != NULL) {
4113dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_character = ucl_utstring_append_character;
4123dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_double = ucl_utstring_append_double;
4133dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_int = ucl_utstring_append_int;
4143dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_len = ucl_utstring_append_len;
415*a0409676SBaptiste Daroussin 		f->ucl_emitter_free_func = _ucl_emitter_free;
4163dcf5eb7SBaptiste Daroussin 		utstring_new (s);
4173dcf5eb7SBaptiste Daroussin 		f->ud = s;
4183dcf5eb7SBaptiste Daroussin 		*pmem = s->d;
4193dcf5eb7SBaptiste Daroussin 		s->pd = pmem;
4203dcf5eb7SBaptiste Daroussin 	}
4213dcf5eb7SBaptiste Daroussin 
4223dcf5eb7SBaptiste Daroussin 	return f;
4233dcf5eb7SBaptiste Daroussin }
4243dcf5eb7SBaptiste Daroussin 
4253dcf5eb7SBaptiste Daroussin struct ucl_emitter_functions*
ucl_object_emit_file_funcs(FILE * fp)4263dcf5eb7SBaptiste Daroussin ucl_object_emit_file_funcs (FILE *fp)
4273dcf5eb7SBaptiste Daroussin {
4283dcf5eb7SBaptiste Daroussin 	struct ucl_emitter_functions *f;
4293dcf5eb7SBaptiste Daroussin 
4303dcf5eb7SBaptiste Daroussin 	f = calloc (1, sizeof (*f));
4313dcf5eb7SBaptiste Daroussin 
4323dcf5eb7SBaptiste Daroussin 	if (f != NULL) {
4333dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_character = ucl_file_append_character;
4343dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_double = ucl_file_append_double;
4353dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_int = ucl_file_append_int;
4363dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_len = ucl_file_append_len;
4373dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_free_func = NULL;
4383dcf5eb7SBaptiste Daroussin 		f->ud = fp;
4393dcf5eb7SBaptiste Daroussin 	}
4403dcf5eb7SBaptiste Daroussin 
4413dcf5eb7SBaptiste Daroussin 	return f;
4423dcf5eb7SBaptiste Daroussin }
4433dcf5eb7SBaptiste Daroussin 
4443dcf5eb7SBaptiste Daroussin struct ucl_emitter_functions*
ucl_object_emit_fd_funcs(int fd)4453dcf5eb7SBaptiste Daroussin ucl_object_emit_fd_funcs (int fd)
4463dcf5eb7SBaptiste Daroussin {
4473dcf5eb7SBaptiste Daroussin 	struct ucl_emitter_functions *f;
4483dcf5eb7SBaptiste Daroussin 	int *ip;
4493dcf5eb7SBaptiste Daroussin 
4503dcf5eb7SBaptiste Daroussin 	f = calloc (1, sizeof (*f));
4513dcf5eb7SBaptiste Daroussin 
4523dcf5eb7SBaptiste Daroussin 	if (f != NULL) {
4533dcf5eb7SBaptiste Daroussin 		ip = malloc (sizeof (fd));
4543dcf5eb7SBaptiste Daroussin 		if (ip == NULL) {
4553dcf5eb7SBaptiste Daroussin 			free (f);
4563dcf5eb7SBaptiste Daroussin 			return NULL;
4573dcf5eb7SBaptiste Daroussin 		}
4583dcf5eb7SBaptiste Daroussin 
4593dcf5eb7SBaptiste Daroussin 		memcpy (ip, &fd, sizeof (fd));
4603dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_character = ucl_fd_append_character;
4613dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_double = ucl_fd_append_double;
4623dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_int = ucl_fd_append_int;
4633dcf5eb7SBaptiste Daroussin 		f->ucl_emitter_append_len = ucl_fd_append_len;
464*a0409676SBaptiste Daroussin 		f->ucl_emitter_free_func = _ucl_emitter_free;
4653dcf5eb7SBaptiste Daroussin 		f->ud = ip;
4663dcf5eb7SBaptiste Daroussin 	}
4673dcf5eb7SBaptiste Daroussin 
4683dcf5eb7SBaptiste Daroussin 	return f;
4693dcf5eb7SBaptiste Daroussin }
4703dcf5eb7SBaptiste Daroussin 
4713dcf5eb7SBaptiste Daroussin void
ucl_object_emit_funcs_free(struct ucl_emitter_functions * f)4723dcf5eb7SBaptiste Daroussin ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
4733dcf5eb7SBaptiste Daroussin {
4743dcf5eb7SBaptiste Daroussin 	if (f != NULL) {
4753dcf5eb7SBaptiste Daroussin 		if (f->ucl_emitter_free_func != NULL) {
4763dcf5eb7SBaptiste Daroussin 			f->ucl_emitter_free_func (f->ud);
4773dcf5eb7SBaptiste Daroussin 		}
4783dcf5eb7SBaptiste Daroussin 		free (f);
4793dcf5eb7SBaptiste Daroussin 	}
4803dcf5eb7SBaptiste Daroussin }
4813dcf5eb7SBaptiste Daroussin 
4823dcf5eb7SBaptiste Daroussin 
4833dcf5eb7SBaptiste Daroussin unsigned char *
ucl_object_emit_single_json(const ucl_object_t * obj)4843dcf5eb7SBaptiste Daroussin ucl_object_emit_single_json (const ucl_object_t *obj)
4853dcf5eb7SBaptiste Daroussin {
4863dcf5eb7SBaptiste Daroussin 	UT_string *buf = NULL;
4873dcf5eb7SBaptiste Daroussin 	unsigned char *res = NULL;
4883dcf5eb7SBaptiste Daroussin 
4893dcf5eb7SBaptiste Daroussin 	if (obj == NULL) {
4903dcf5eb7SBaptiste Daroussin 		return NULL;
4913dcf5eb7SBaptiste Daroussin 	}
4923dcf5eb7SBaptiste Daroussin 
4933dcf5eb7SBaptiste Daroussin 	utstring_new (buf);
4943dcf5eb7SBaptiste Daroussin 
4953dcf5eb7SBaptiste Daroussin 	if (buf != NULL) {
4963dcf5eb7SBaptiste Daroussin 		switch (obj->type) {
4973dcf5eb7SBaptiste Daroussin 		case UCL_OBJECT:
4983dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_len ("object", 6, buf);
4993dcf5eb7SBaptiste Daroussin 			break;
5003dcf5eb7SBaptiste Daroussin 		case UCL_ARRAY:
5013dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_len ("array", 5, buf);
5023dcf5eb7SBaptiste Daroussin 			break;
5033dcf5eb7SBaptiste Daroussin 		case UCL_INT:
5043dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_int (obj->value.iv, buf);
5053dcf5eb7SBaptiste Daroussin 			break;
5063dcf5eb7SBaptiste Daroussin 		case UCL_FLOAT:
5073dcf5eb7SBaptiste Daroussin 		case UCL_TIME:
5083dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_double (obj->value.dv, buf);
5093dcf5eb7SBaptiste Daroussin 			break;
5103dcf5eb7SBaptiste Daroussin 		case UCL_NULL:
5113dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_len ("null", 4, buf);
5123dcf5eb7SBaptiste Daroussin 			break;
5133dcf5eb7SBaptiste Daroussin 		case UCL_BOOLEAN:
5143dcf5eb7SBaptiste Daroussin 			if (obj->value.iv) {
5153dcf5eb7SBaptiste Daroussin 				ucl_utstring_append_len ("true", 4, buf);
5163dcf5eb7SBaptiste Daroussin 			}
5173dcf5eb7SBaptiste Daroussin 			else {
5183dcf5eb7SBaptiste Daroussin 				ucl_utstring_append_len ("false", 5, buf);
5193dcf5eb7SBaptiste Daroussin 			}
5203dcf5eb7SBaptiste Daroussin 			break;
5213dcf5eb7SBaptiste Daroussin 		case UCL_STRING:
5223dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_len (obj->value.sv, obj->len, buf);
5233dcf5eb7SBaptiste Daroussin 			break;
5243dcf5eb7SBaptiste Daroussin 		case UCL_USERDATA:
5253dcf5eb7SBaptiste Daroussin 			ucl_utstring_append_len ("userdata", 8, buf);
5263dcf5eb7SBaptiste Daroussin 			break;
5273dcf5eb7SBaptiste Daroussin 		}
5283dcf5eb7SBaptiste Daroussin 		res = utstring_body (buf);
5293dcf5eb7SBaptiste Daroussin 		free (buf);
5303dcf5eb7SBaptiste Daroussin 	}
5313dcf5eb7SBaptiste Daroussin 
5323dcf5eb7SBaptiste Daroussin 	return res;
5333dcf5eb7SBaptiste Daroussin }
5344bf54857SBaptiste Daroussin 
5354bf54857SBaptiste Daroussin #define LONG_STRING_LIMIT 80
5364bf54857SBaptiste Daroussin 
5374bf54857SBaptiste Daroussin bool
ucl_maybe_long_string(const ucl_object_t * obj)5384bf54857SBaptiste Daroussin ucl_maybe_long_string (const ucl_object_t *obj)
5394bf54857SBaptiste Daroussin {
5404bf54857SBaptiste Daroussin 	if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
5414bf54857SBaptiste Daroussin 		/* String is long enough, so search for newline characters in it */
5424bf54857SBaptiste Daroussin 		if (memchr (obj->value.sv, '\n', obj->len) != NULL) {
5434bf54857SBaptiste Daroussin 			return true;
5444bf54857SBaptiste Daroussin 		}
5454bf54857SBaptiste Daroussin 	}
5464bf54857SBaptiste Daroussin 
5474bf54857SBaptiste Daroussin 	return false;
5484bf54857SBaptiste Daroussin }
549