1/* Copyright (c) 2013, 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#include <float.h>
25#include <math.h>
26#include "ucl.h"
27#include "ucl_internal.h"
28#include "ucl_chartable.h"
29
30/**
31 * @file rcl_emitter.c
32 * Serialise UCL object to various of output formats
33 */
34
35
36static void ucl_obj_write_json (ucl_object_t *obj,
37		struct ucl_emitter_functions *func,
38		unsigned int tabs,
39		bool start_tabs,
40		bool compact);
41static void ucl_elt_write_json (ucl_object_t *obj,
42		struct ucl_emitter_functions *func,
43		unsigned int tabs,
44		bool start_tabs,
45		bool compact);
46static void ucl_elt_write_config (ucl_object_t *obj,
47		struct ucl_emitter_functions *func,
48		unsigned int tabs,
49		bool start_tabs,
50		bool is_top,
51		bool expand_array);
52static void ucl_elt_write_yaml (ucl_object_t *obj,
53		struct ucl_emitter_functions *func,
54		unsigned int tabs,
55		bool start_tabs,
56		bool compact,
57		bool expand_array);
58static void ucl_elt_array_write_yaml (ucl_object_t *obj,
59		struct ucl_emitter_functions *func,
60		unsigned int tabs,
61		bool start_tabs,
62		bool is_top);
63
64/**
65 * Add tabulation to the output buffer
66 * @param buf target buffer
67 * @param tabs number of tabs to add
68 */
69static inline void
70ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact)
71{
72	if (!compact) {
73		func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
74	}
75}
76
77/**
78 * Serialise string
79 * @param str string to emit
80 * @param buf target buffer
81 */
82static void
83ucl_elt_string_write_json (const char *str, size_t size,
84		struct ucl_emitter_functions *func)
85{
86	const char *p = str, *c = str;
87	size_t len = 0;
88
89	func->ucl_emitter_append_character ('"', 1, func->ud);
90	while (size) {
91		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
92			if (len > 0) {
93				func->ucl_emitter_append_len (c, len, func->ud);
94			}
95			switch (*p) {
96			case '\n':
97				func->ucl_emitter_append_len ("\\n", 2, func->ud);
98				break;
99			case '\r':
100				func->ucl_emitter_append_len ("\\r", 2, func->ud);
101				break;
102			case '\b':
103				func->ucl_emitter_append_len ("\\b", 2, func->ud);
104				break;
105			case '\t':
106				func->ucl_emitter_append_len ("\\t", 2, func->ud);
107				break;
108			case '\f':
109				func->ucl_emitter_append_len ("\\f", 2, func->ud);
110				break;
111			case '\\':
112				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
113				break;
114			case '"':
115				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
116				break;
117			}
118			len = 0;
119			c = ++p;
120		}
121		else {
122			p ++;
123			len ++;
124		}
125		size --;
126	}
127	if (len > 0) {
128		func->ucl_emitter_append_len (c, len, func->ud);
129	}
130	func->ucl_emitter_append_character ('"', 1, func->ud);
131}
132
133/**
134 * Write a single object to the buffer
135 * @param obj object to write
136 * @param buf target buffer
137 */
138static void
139ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
140		unsigned int tabs, bool start_tabs, bool compact)
141{
142	ucl_object_t *cur;
143	ucl_hash_iter_t it = NULL;
144
145	if (start_tabs) {
146		ucl_add_tabs (func, tabs, compact);
147	}
148	if (compact) {
149		func->ucl_emitter_append_character ('{', 1, func->ud);
150	}
151	else {
152		func->ucl_emitter_append_len ("{\n", 2, func->ud);
153	}
154	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
155		ucl_add_tabs (func, tabs + 1, compact);
156		if (cur->keylen > 0) {
157			ucl_elt_string_write_json (cur->key, cur->keylen, func);
158		}
159		else {
160			func->ucl_emitter_append_len ("null", 4, func->ud);
161		}
162		if (compact) {
163			func->ucl_emitter_append_character (':', 1, func->ud);
164		}
165		else {
166			func->ucl_emitter_append_len (": ", 2, func->ud);
167		}
168		ucl_obj_write_json (cur, func, tabs + 1, false, compact);
169		if (ucl_hash_iter_has_next (it)) {
170			if (compact) {
171				func->ucl_emitter_append_character (',', 1, func->ud);
172			}
173			else {
174				func->ucl_emitter_append_len (",\n", 2, func->ud);
175			}
176		}
177		else if (!compact) {
178			func->ucl_emitter_append_character ('\n', 1, func->ud);
179		}
180	}
181	ucl_add_tabs (func, tabs, compact);
182	func->ucl_emitter_append_character ('}', 1, func->ud);
183}
184
185/**
186 * Write a single array to the buffer
187 * @param obj array to write
188 * @param buf target buffer
189 */
190static void
191ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
192		unsigned int tabs, bool start_tabs, bool compact)
193{
194	ucl_object_t *cur = obj;
195
196	if (start_tabs) {
197		ucl_add_tabs (func, tabs, compact);
198	}
199	if (compact) {
200		func->ucl_emitter_append_character ('[', 1, func->ud);
201	}
202	else {
203		func->ucl_emitter_append_len ("[\n", 2, func->ud);
204	}
205	while (cur) {
206		ucl_elt_write_json (cur, func, tabs + 1, true, compact);
207		if (cur->next != NULL) {
208			if (compact) {
209				func->ucl_emitter_append_character (',', 1, func->ud);
210			}
211			else {
212				func->ucl_emitter_append_len (",\n", 2, func->ud);
213			}
214		}
215		else if (!compact) {
216			func->ucl_emitter_append_character ('\n', 1, func->ud);
217		}
218		cur = cur->next;
219	}
220	ucl_add_tabs (func, tabs, compact);
221	func->ucl_emitter_append_character (']', 1, func->ud);
222}
223
224/**
225 * Emit a single element
226 * @param obj object
227 * @param buf buffer
228 */
229static void
230ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
231		unsigned int tabs, bool start_tabs, bool compact)
232{
233	bool flag;
234
235	switch (obj->type) {
236	case UCL_INT:
237		if (start_tabs) {
238			ucl_add_tabs (func, tabs, compact);
239		}
240		func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
241		break;
242	case UCL_FLOAT:
243	case UCL_TIME:
244		if (start_tabs) {
245			ucl_add_tabs (func, tabs, compact);
246		}
247		func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
248		break;
249	case UCL_BOOLEAN:
250		if (start_tabs) {
251			ucl_add_tabs (func, tabs, compact);
252		}
253		flag = ucl_object_toboolean (obj);
254		if (flag) {
255			func->ucl_emitter_append_len ("true", 4, func->ud);
256		}
257		else {
258			func->ucl_emitter_append_len ("false", 5, func->ud);
259		}
260		break;
261	case UCL_STRING:
262		if (start_tabs) {
263			ucl_add_tabs (func, tabs, compact);
264		}
265		ucl_elt_string_write_json (obj->value.sv, obj->len, func);
266		break;
267	case UCL_NULL:
268		if (start_tabs) {
269			ucl_add_tabs (func, tabs, compact);
270		}
271		func->ucl_emitter_append_len ("null", 4, func->ud);
272		break;
273	case UCL_OBJECT:
274		ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact);
275		break;
276	case UCL_ARRAY:
277		ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact);
278		break;
279	case UCL_USERDATA:
280		break;
281	}
282}
283
284/**
285 * Write a single object to the buffer
286 * @param obj object
287 * @param buf target buffer
288 */
289static void
290ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
291		unsigned int tabs, bool start_tabs, bool compact)
292{
293	ucl_object_t *cur;
294	bool is_array = (obj->next != NULL);
295
296	if (is_array) {
297		/* This is an array actually */
298		if (start_tabs) {
299			ucl_add_tabs (func, tabs, compact);
300		}
301
302		if (compact) {
303			func->ucl_emitter_append_character ('[', 1, func->ud);
304		}
305		else {
306			func->ucl_emitter_append_len ("[\n", 2, func->ud);
307		}
308		cur = obj;
309		while (cur != NULL) {
310			ucl_elt_write_json (cur, func, tabs + 1, true, compact);
311			if (cur->next) {
312				func->ucl_emitter_append_character (',', 1, func->ud);
313			}
314			if (!compact) {
315				func->ucl_emitter_append_character ('\n', 1, func->ud);
316			}
317			cur = cur->next;
318		}
319		ucl_add_tabs (func, tabs, compact);
320		func->ucl_emitter_append_character (']', 1, func->ud);
321	}
322	else {
323		ucl_elt_write_json (obj, func, tabs, start_tabs, compact);
324	}
325
326}
327
328/**
329 * Emit an object to json
330 * @param obj object
331 * @return json output (should be freed after using)
332 */
333static void
334ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func)
335{
336	ucl_obj_write_json (obj, func, 0, false, compact);
337}
338
339/**
340 * Write a single object to the buffer
341 * @param obj object to write
342 * @param buf target buffer
343 */
344static void
345ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
346		unsigned int tabs, bool start_tabs, bool is_top)
347{
348	ucl_object_t *cur, *cur_obj;
349	ucl_hash_iter_t it = NULL;
350
351	if (start_tabs) {
352		ucl_add_tabs (func, tabs, is_top);
353	}
354	if (!is_top) {
355		func->ucl_emitter_append_len ("{\n", 2, func->ud);
356	}
357
358	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
359		LL_FOREACH (cur, cur_obj) {
360			ucl_add_tabs (func, tabs + 1, is_top);
361			if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
362				ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func);
363			}
364			else {
365				func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud);
366			}
367			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
368				func->ucl_emitter_append_len (" = ", 3, func->ud);
369			}
370			else {
371				func->ucl_emitter_append_character (' ', 1, func->ud);
372			}
373			ucl_elt_write_config (cur_obj, func,
374					is_top ? tabs : tabs + 1,
375					false, false, false);
376			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
377				func->ucl_emitter_append_len (";\n", 2, func->ud);
378			}
379			else {
380				func->ucl_emitter_append_character ('\n', 1, func->ud);
381			}
382		}
383	}
384
385	ucl_add_tabs (func, tabs, is_top);
386	if (!is_top) {
387		func->ucl_emitter_append_character ('}', 1, func->ud);
388	}
389}
390
391/**
392 * Write a single array to the buffer
393 * @param obj array to write
394 * @param buf target buffer
395 */
396static void
397ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
398		unsigned int tabs, bool start_tabs, bool is_top)
399{
400	ucl_object_t *cur = obj;
401
402	if (start_tabs) {
403		ucl_add_tabs (func, tabs, false);
404	}
405
406	func->ucl_emitter_append_len ("[\n", 2, func->ud);
407	while (cur) {
408		ucl_elt_write_config (cur, func, tabs + 1, true, false, false);
409		func->ucl_emitter_append_len (",\n", 2, func->ud);
410		cur = cur->next;
411	}
412	ucl_add_tabs (func, tabs, false);
413	func->ucl_emitter_append_character (']', 1, func->ud);
414}
415
416/**
417 * Emit a single element
418 * @param obj object
419 * @param buf buffer
420 */
421static void
422ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
423		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
424{
425	bool flag;
426
427	if (expand_array && obj->next != NULL) {
428		ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top);
429	}
430	else {
431		switch (obj->type) {
432		case UCL_INT:
433			if (start_tabs) {
434				ucl_add_tabs (func, tabs, false);
435			}
436			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
437			break;
438		case UCL_FLOAT:
439		case UCL_TIME:
440			if (start_tabs) {
441				ucl_add_tabs (func, tabs, false);
442			}
443			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
444			break;
445		case UCL_BOOLEAN:
446			if (start_tabs) {
447				ucl_add_tabs (func, tabs, false);
448			}
449			flag = ucl_object_toboolean (obj);
450			if (flag) {
451				func->ucl_emitter_append_len ("true", 4, func->ud);
452			}
453			else {
454				func->ucl_emitter_append_len ("false", 5, func->ud);
455			}
456			break;
457		case UCL_STRING:
458			if (start_tabs) {
459				ucl_add_tabs (func, tabs, false);
460			}
461			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
462			break;
463		case UCL_NULL:
464			if (start_tabs) {
465				ucl_add_tabs (func, tabs, false);
466			}
467			func->ucl_emitter_append_len ("null", 4, func->ud);
468			break;
469		case UCL_OBJECT:
470			ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top);
471			break;
472		case UCL_ARRAY:
473			ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top);
474			break;
475		case UCL_USERDATA:
476			break;
477		}
478	}
479}
480
481/**
482 * Emit an object to rcl
483 * @param obj object
484 * @return rcl output (should be freed after using)
485 */
486static void
487ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func)
488{
489	ucl_elt_write_config (obj, func, 0, false, true, true);
490}
491
492
493static void
494ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
495		unsigned int tabs, bool start_tabs)
496{
497	bool is_array = (obj->next != NULL);
498
499	if (is_array) {
500		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false);
501	}
502	else {
503		ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true);
504	}
505}
506
507/**
508 * Write a single object to the buffer
509 * @param obj object to write
510 * @param buf target buffer
511 */
512static void
513ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
514		unsigned int tabs, bool start_tabs, bool is_top)
515{
516	ucl_object_t *cur;
517	ucl_hash_iter_t it = NULL;
518
519	if (start_tabs) {
520		ucl_add_tabs (func, tabs, is_top);
521	}
522	if (!is_top) {
523		func->ucl_emitter_append_len ("{\n", 2, func->ud);
524	}
525
526	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
527		ucl_add_tabs (func, tabs + 1, is_top);
528		if (cur->keylen > 0) {
529			ucl_elt_string_write_json (cur->key, cur->keylen, func);
530		}
531		else {
532			func->ucl_emitter_append_len ("null", 4, func->ud);
533		}
534		func->ucl_emitter_append_len (": ", 2, func->ud);
535		ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false);
536		if (ucl_hash_iter_has_next(it)) {
537			if (!is_top) {
538				func->ucl_emitter_append_len (",\n", 2, func->ud);
539			}
540			else {
541				func->ucl_emitter_append_character ('\n', 1, func->ud);
542			}
543		}
544		else {
545			func->ucl_emitter_append_character ('\n', 1, func->ud);
546		}
547	}
548
549	ucl_add_tabs (func, tabs, is_top);
550	if (!is_top) {
551		func->ucl_emitter_append_character ('}', 1, func->ud);
552	}
553}
554
555/**
556 * Write a single array to the buffer
557 * @param obj array to write
558 * @param buf target buffer
559 */
560static void
561ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
562		unsigned int tabs, bool start_tabs, bool is_top)
563{
564	ucl_object_t *cur = obj;
565
566	if (start_tabs) {
567		ucl_add_tabs (func, tabs, false);
568	}
569
570	func->ucl_emitter_append_len ("[\n", 2, func->ud);
571	while (cur) {
572		ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false);
573		func->ucl_emitter_append_len (",\n", 2, func->ud);
574		cur = cur->next;
575	}
576	ucl_add_tabs (func, tabs, false);
577	func->ucl_emitter_append_character (']', 1, func->ud);
578}
579
580/**
581 * Emit a single element
582 * @param obj object
583 * @param buf buffer
584 */
585static void
586ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
587		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
588{
589	bool flag;
590
591	if (expand_array && obj->next != NULL ) {
592		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top);
593	}
594	else {
595		switch (obj->type) {
596		case UCL_INT:
597			if (start_tabs) {
598				ucl_add_tabs (func, tabs, false);
599			}
600			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
601			break;
602		case UCL_FLOAT:
603		case UCL_TIME:
604			if (start_tabs) {
605				ucl_add_tabs (func, tabs, false);
606			}
607			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
608			break;
609		case UCL_BOOLEAN:
610			if (start_tabs) {
611				ucl_add_tabs (func, tabs, false);
612			}
613			flag = ucl_object_toboolean (obj);
614			if (flag) {
615				func->ucl_emitter_append_len ("true", 4, func->ud);
616			}
617			else {
618				func->ucl_emitter_append_len ("false", 5, func->ud);
619			}
620			break;
621		case UCL_STRING:
622			if (start_tabs) {
623				ucl_add_tabs (func, tabs, false);
624			}
625			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
626			break;
627		case UCL_NULL:
628			if (start_tabs) {
629				ucl_add_tabs (func, tabs, false);
630			}
631			func->ucl_emitter_append_len ("null", 4, func->ud);
632			break;
633		case UCL_OBJECT:
634			ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top);
635			break;
636		case UCL_ARRAY:
637			ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top);
638			break;
639		case UCL_USERDATA:
640			break;
641		}
642	}
643}
644
645/**
646 * Emit an object to rcl
647 * @param obj object
648 * @return rcl output (should be freed after using)
649 */
650static void
651ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func)
652{
653	ucl_elt_write_yaml (obj, func, 0, false, true, true);
654}
655
656/*
657 * Generic utstring output
658 */
659static int
660ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
661{
662	UT_string *buf = ud;
663
664	if (len == 1) {
665		utstring_append_c (buf, c);
666	}
667	else {
668		utstring_reserve (buf, len);
669		memset (&buf->d[buf->i], c, len);
670		buf->i += len;
671		buf->d[buf->i] = '\0';
672	}
673
674	return 0;
675}
676
677static int
678ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
679{
680	UT_string *buf = ud;
681
682	utstring_append_len (buf, str, len);
683
684	return 0;
685}
686
687static int
688ucl_utstring_append_int (int64_t val, void *ud)
689{
690	UT_string *buf = ud;
691
692	utstring_printf (buf, "%jd", (intmax_t)val);
693	return 0;
694}
695
696static int
697ucl_utstring_append_double (double val, void *ud)
698{
699	UT_string *buf = ud;
700	const double delta = 0.0000001;
701
702	if (val == (double)(int)val) {
703		utstring_printf (buf, "%.1lf", val);
704	}
705	else if (fabs (val - (double)(int)val) < delta) {
706		/* Write at maximum precision */
707		utstring_printf (buf, "%.*lg", DBL_DIG, val);
708	}
709	else {
710		utstring_printf (buf, "%lf", val);
711	}
712
713	return 0;
714}
715
716
717unsigned char *
718ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
719{
720	UT_string *buf = NULL;
721	unsigned char *res = NULL;
722	struct ucl_emitter_functions func = {
723		.ucl_emitter_append_character = ucl_utstring_append_character,
724		.ucl_emitter_append_len = ucl_utstring_append_len,
725		.ucl_emitter_append_int = ucl_utstring_append_int,
726		.ucl_emitter_append_double = ucl_utstring_append_double
727	};
728
729	if (obj == NULL) {
730		return NULL;
731	}
732
733	utstring_new (buf);
734	func.ud = buf;
735
736	if (buf != NULL) {
737		if (emit_type == UCL_EMIT_JSON) {
738			ucl_object_emit_json (obj, false, &func);
739		}
740		else if (emit_type == UCL_EMIT_JSON_COMPACT) {
741			ucl_object_emit_json (obj, true, &func);
742		}
743		else if (emit_type == UCL_EMIT_YAML) {
744			ucl_object_emit_yaml (obj, &func);
745		}
746		else {
747			ucl_object_emit_config (obj, &func);
748		}
749
750		res = utstring_body (buf);
751		free (buf);
752	}
753
754	return res;
755}
756
757bool
758ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
759		struct ucl_emitter_functions *emitter)
760{
761	if (emit_type == UCL_EMIT_JSON) {
762		ucl_object_emit_json (obj, false, emitter);
763	}
764	else if (emit_type == UCL_EMIT_JSON_COMPACT) {
765		ucl_object_emit_json (obj, true, emitter);
766	}
767	else if (emit_type == UCL_EMIT_YAML) {
768		ucl_object_emit_yaml (obj, emitter);
769	}
770	else {
771		ucl_object_emit_config (obj, emitter);
772	}
773
774	/* XXX: need some error checks here */
775	return true;
776}
777
778
779unsigned char *
780ucl_object_emit_single_json (ucl_object_t *obj)
781{
782	UT_string *buf = NULL;
783	unsigned char *res = NULL;
784
785	if (obj == NULL) {
786		return NULL;
787	}
788
789	utstring_new (buf);
790
791	if (buf != NULL) {
792		switch (obj->type) {
793		case UCL_OBJECT:
794			ucl_utstring_append_len ("object", 6, buf);
795			break;
796		case UCL_ARRAY:
797			ucl_utstring_append_len ("array", 5, buf);
798			break;
799		case UCL_INT:
800			ucl_utstring_append_int (obj->value.iv, buf);
801			break;
802		case UCL_FLOAT:
803		case UCL_TIME:
804			ucl_utstring_append_double (obj->value.dv, buf);
805			break;
806		case UCL_NULL:
807			ucl_utstring_append_len ("null", 4, buf);
808			break;
809		case UCL_BOOLEAN:
810			if (obj->value.iv) {
811				ucl_utstring_append_len ("true", 4, buf);
812			}
813			else {
814				ucl_utstring_append_len ("false", 5, buf);
815			}
816			break;
817		case UCL_STRING:
818			ucl_utstring_append_len (obj->value.sv, obj->len, buf);
819			break;
820		case UCL_USERDATA:
821			ucl_utstring_append_len ("userdata", 8, buf);
822			break;
823		}
824		res = utstring_body (buf);
825		free (buf);
826	}
827
828	return res;
829}
830