1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov
2262395Sbapt * All rights reserved.
3262395Sbapt *
4262395Sbapt * Redistribution and use in source and binary forms, with or without
5262395Sbapt * modification, are permitted provided that the following conditions are met:
6262395Sbapt *       * Redistributions of source code must retain the above copyright
7262395Sbapt *         notice, this list of conditions and the following disclaimer.
8262395Sbapt *       * Redistributions in binary form must reproduce the above copyright
9262395Sbapt *         notice, this list of conditions and the following disclaimer in the
10262395Sbapt *         documentation and/or other materials provided with the distribution.
11262395Sbapt *
12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22262395Sbapt */
23262395Sbapt
24262395Sbapt#include <float.h>
25262395Sbapt#include <math.h>
26262395Sbapt#include "ucl.h"
27262395Sbapt#include "ucl_internal.h"
28262395Sbapt#include "ucl_chartable.h"
29262395Sbapt
30262395Sbapt/**
31262395Sbapt * @file rcl_emitter.c
32262395Sbapt * Serialise UCL object to various of output formats
33262395Sbapt */
34262395Sbapt
35262395Sbapt
36262395Sbaptstatic void ucl_obj_write_json (ucl_object_t *obj,
37262395Sbapt		struct ucl_emitter_functions *func,
38262395Sbapt		unsigned int tabs,
39262395Sbapt		bool start_tabs,
40262395Sbapt		bool compact);
41262395Sbaptstatic void ucl_elt_write_json (ucl_object_t *obj,
42262395Sbapt		struct ucl_emitter_functions *func,
43262395Sbapt		unsigned int tabs,
44262395Sbapt		bool start_tabs,
45262395Sbapt		bool compact);
46262395Sbaptstatic void ucl_elt_write_config (ucl_object_t *obj,
47262395Sbapt		struct ucl_emitter_functions *func,
48262395Sbapt		unsigned int tabs,
49262395Sbapt		bool start_tabs,
50262395Sbapt		bool is_top,
51262395Sbapt		bool expand_array);
52262395Sbaptstatic void ucl_elt_write_yaml (ucl_object_t *obj,
53262395Sbapt		struct ucl_emitter_functions *func,
54262395Sbapt		unsigned int tabs,
55262395Sbapt		bool start_tabs,
56262395Sbapt		bool compact,
57262395Sbapt		bool expand_array);
58262395Sbaptstatic void ucl_elt_array_write_yaml (ucl_object_t *obj,
59262395Sbapt		struct ucl_emitter_functions *func,
60262395Sbapt		unsigned int tabs,
61262395Sbapt		bool start_tabs,
62262395Sbapt		bool is_top);
63262395Sbapt
64262395Sbapt/**
65262395Sbapt * Add tabulation to the output buffer
66262395Sbapt * @param buf target buffer
67262395Sbapt * @param tabs number of tabs to add
68262395Sbapt */
69262395Sbaptstatic inline void
70262395Sbaptucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact)
71262395Sbapt{
72262395Sbapt	if (!compact) {
73262395Sbapt		func->ucl_emitter_append_character (' ', tabs * 4, func->ud);
74262395Sbapt	}
75262395Sbapt}
76262395Sbapt
77262395Sbapt/**
78262395Sbapt * Serialise string
79262395Sbapt * @param str string to emit
80262395Sbapt * @param buf target buffer
81262395Sbapt */
82262395Sbaptstatic void
83262395Sbaptucl_elt_string_write_json (const char *str, size_t size,
84262395Sbapt		struct ucl_emitter_functions *func)
85262395Sbapt{
86262395Sbapt	const char *p = str, *c = str;
87262395Sbapt	size_t len = 0;
88262395Sbapt
89262395Sbapt	func->ucl_emitter_append_character ('"', 1, func->ud);
90262395Sbapt	while (size) {
91262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
92262395Sbapt			if (len > 0) {
93262395Sbapt				func->ucl_emitter_append_len (c, len, func->ud);
94262395Sbapt			}
95262395Sbapt			switch (*p) {
96262395Sbapt			case '\n':
97262395Sbapt				func->ucl_emitter_append_len ("\\n", 2, func->ud);
98262395Sbapt				break;
99262395Sbapt			case '\r':
100262395Sbapt				func->ucl_emitter_append_len ("\\r", 2, func->ud);
101262395Sbapt				break;
102262395Sbapt			case '\b':
103262395Sbapt				func->ucl_emitter_append_len ("\\b", 2, func->ud);
104262395Sbapt				break;
105262395Sbapt			case '\t':
106262395Sbapt				func->ucl_emitter_append_len ("\\t", 2, func->ud);
107262395Sbapt				break;
108262395Sbapt			case '\f':
109262395Sbapt				func->ucl_emitter_append_len ("\\f", 2, func->ud);
110262395Sbapt				break;
111262395Sbapt			case '\\':
112262395Sbapt				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
113262395Sbapt				break;
114262395Sbapt			case '"':
115262395Sbapt				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
116262395Sbapt				break;
117262395Sbapt			}
118262395Sbapt			len = 0;
119262395Sbapt			c = ++p;
120262395Sbapt		}
121262395Sbapt		else {
122262395Sbapt			p ++;
123262395Sbapt			len ++;
124262395Sbapt		}
125262395Sbapt		size --;
126262395Sbapt	}
127262395Sbapt	if (len > 0) {
128262395Sbapt		func->ucl_emitter_append_len (c, len, func->ud);
129262395Sbapt	}
130262395Sbapt	func->ucl_emitter_append_character ('"', 1, func->ud);
131262395Sbapt}
132262395Sbapt
133262395Sbapt/**
134262395Sbapt * Write a single object to the buffer
135262395Sbapt * @param obj object to write
136262395Sbapt * @param buf target buffer
137262395Sbapt */
138262395Sbaptstatic void
139262395Sbaptucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
140262395Sbapt		unsigned int tabs, bool start_tabs, bool compact)
141262395Sbapt{
142262395Sbapt	ucl_object_t *cur;
143262395Sbapt	ucl_hash_iter_t it = NULL;
144262395Sbapt
145262395Sbapt	if (start_tabs) {
146262395Sbapt		ucl_add_tabs (func, tabs, compact);
147262395Sbapt	}
148262395Sbapt	if (compact) {
149262395Sbapt		func->ucl_emitter_append_character ('{', 1, func->ud);
150262395Sbapt	}
151262395Sbapt	else {
152262395Sbapt		func->ucl_emitter_append_len ("{\n", 2, func->ud);
153262395Sbapt	}
154262395Sbapt	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
155262395Sbapt		ucl_add_tabs (func, tabs + 1, compact);
156262395Sbapt		if (cur->keylen > 0) {
157262395Sbapt			ucl_elt_string_write_json (cur->key, cur->keylen, func);
158262395Sbapt		}
159262395Sbapt		else {
160262395Sbapt			func->ucl_emitter_append_len ("null", 4, func->ud);
161262395Sbapt		}
162262395Sbapt		if (compact) {
163262395Sbapt			func->ucl_emitter_append_character (':', 1, func->ud);
164262395Sbapt		}
165262395Sbapt		else {
166262395Sbapt			func->ucl_emitter_append_len (": ", 2, func->ud);
167262395Sbapt		}
168262395Sbapt		ucl_obj_write_json (cur, func, tabs + 1, false, compact);
169262395Sbapt		if (ucl_hash_iter_has_next (it)) {
170262395Sbapt			if (compact) {
171262395Sbapt				func->ucl_emitter_append_character (',', 1, func->ud);
172262395Sbapt			}
173262395Sbapt			else {
174262395Sbapt				func->ucl_emitter_append_len (",\n", 2, func->ud);
175262395Sbapt			}
176262395Sbapt		}
177262395Sbapt		else if (!compact) {
178262395Sbapt			func->ucl_emitter_append_character ('\n', 1, func->ud);
179262395Sbapt		}
180262395Sbapt	}
181262395Sbapt	ucl_add_tabs (func, tabs, compact);
182262395Sbapt	func->ucl_emitter_append_character ('}', 1, func->ud);
183262395Sbapt}
184262395Sbapt
185262395Sbapt/**
186262395Sbapt * Write a single array to the buffer
187262395Sbapt * @param obj array to write
188262395Sbapt * @param buf target buffer
189262395Sbapt */
190262395Sbaptstatic void
191262395Sbaptucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
192262395Sbapt		unsigned int tabs, bool start_tabs, bool compact)
193262395Sbapt{
194262395Sbapt	ucl_object_t *cur = obj;
195262395Sbapt
196262395Sbapt	if (start_tabs) {
197262395Sbapt		ucl_add_tabs (func, tabs, compact);
198262395Sbapt	}
199262395Sbapt	if (compact) {
200262395Sbapt		func->ucl_emitter_append_character ('[', 1, func->ud);
201262395Sbapt	}
202262395Sbapt	else {
203262395Sbapt		func->ucl_emitter_append_len ("[\n", 2, func->ud);
204262395Sbapt	}
205262395Sbapt	while (cur) {
206262395Sbapt		ucl_elt_write_json (cur, func, tabs + 1, true, compact);
207262395Sbapt		if (cur->next != NULL) {
208262395Sbapt			if (compact) {
209262395Sbapt				func->ucl_emitter_append_character (',', 1, func->ud);
210262395Sbapt			}
211262395Sbapt			else {
212262395Sbapt				func->ucl_emitter_append_len (",\n", 2, func->ud);
213262395Sbapt			}
214262395Sbapt		}
215262395Sbapt		else if (!compact) {
216262395Sbapt			func->ucl_emitter_append_character ('\n', 1, func->ud);
217262395Sbapt		}
218262395Sbapt		cur = cur->next;
219262395Sbapt	}
220262395Sbapt	ucl_add_tabs (func, tabs, compact);
221262395Sbapt	func->ucl_emitter_append_character (']', 1, func->ud);
222262395Sbapt}
223262395Sbapt
224262395Sbapt/**
225262395Sbapt * Emit a single element
226262395Sbapt * @param obj object
227262395Sbapt * @param buf buffer
228262395Sbapt */
229262395Sbaptstatic void
230262395Sbaptucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
231262395Sbapt		unsigned int tabs, bool start_tabs, bool compact)
232262395Sbapt{
233262395Sbapt	bool flag;
234262395Sbapt
235262395Sbapt	switch (obj->type) {
236262395Sbapt	case UCL_INT:
237262395Sbapt		if (start_tabs) {
238262395Sbapt			ucl_add_tabs (func, tabs, compact);
239262395Sbapt		}
240262395Sbapt		func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
241262395Sbapt		break;
242262395Sbapt	case UCL_FLOAT:
243262395Sbapt	case UCL_TIME:
244262395Sbapt		if (start_tabs) {
245262395Sbapt			ucl_add_tabs (func, tabs, compact);
246262395Sbapt		}
247262395Sbapt		func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
248262395Sbapt		break;
249262395Sbapt	case UCL_BOOLEAN:
250262395Sbapt		if (start_tabs) {
251262395Sbapt			ucl_add_tabs (func, tabs, compact);
252262395Sbapt		}
253262395Sbapt		flag = ucl_object_toboolean (obj);
254262395Sbapt		if (flag) {
255262395Sbapt			func->ucl_emitter_append_len ("true", 4, func->ud);
256262395Sbapt		}
257262395Sbapt		else {
258262395Sbapt			func->ucl_emitter_append_len ("false", 5, func->ud);
259262395Sbapt		}
260262395Sbapt		break;
261262395Sbapt	case UCL_STRING:
262262395Sbapt		if (start_tabs) {
263262395Sbapt			ucl_add_tabs (func, tabs, compact);
264262395Sbapt		}
265262395Sbapt		ucl_elt_string_write_json (obj->value.sv, obj->len, func);
266262395Sbapt		break;
267262395Sbapt	case UCL_NULL:
268262395Sbapt		if (start_tabs) {
269262395Sbapt			ucl_add_tabs (func, tabs, compact);
270262395Sbapt		}
271262395Sbapt		func->ucl_emitter_append_len ("null", 4, func->ud);
272262395Sbapt		break;
273262395Sbapt	case UCL_OBJECT:
274262395Sbapt		ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact);
275262395Sbapt		break;
276262395Sbapt	case UCL_ARRAY:
277262395Sbapt		ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact);
278262395Sbapt		break;
279262395Sbapt	case UCL_USERDATA:
280262395Sbapt		break;
281262395Sbapt	}
282262395Sbapt}
283262395Sbapt
284262395Sbapt/**
285262395Sbapt * Write a single object to the buffer
286262395Sbapt * @param obj object
287262395Sbapt * @param buf target buffer
288262395Sbapt */
289262395Sbaptstatic void
290262395Sbaptucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
291262395Sbapt		unsigned int tabs, bool start_tabs, bool compact)
292262395Sbapt{
293262395Sbapt	ucl_object_t *cur;
294262395Sbapt	bool is_array = (obj->next != NULL);
295262395Sbapt
296262395Sbapt	if (is_array) {
297262395Sbapt		/* This is an array actually */
298262395Sbapt		if (start_tabs) {
299262395Sbapt			ucl_add_tabs (func, tabs, compact);
300262395Sbapt		}
301262395Sbapt
302262395Sbapt		if (compact) {
303262395Sbapt			func->ucl_emitter_append_character ('[', 1, func->ud);
304262395Sbapt		}
305262395Sbapt		else {
306262395Sbapt			func->ucl_emitter_append_len ("[\n", 2, func->ud);
307262395Sbapt		}
308262395Sbapt		cur = obj;
309262395Sbapt		while (cur != NULL) {
310262395Sbapt			ucl_elt_write_json (cur, func, tabs + 1, true, compact);
311262395Sbapt			if (cur->next) {
312262395Sbapt				func->ucl_emitter_append_character (',', 1, func->ud);
313262395Sbapt			}
314262395Sbapt			if (!compact) {
315262395Sbapt				func->ucl_emitter_append_character ('\n', 1, func->ud);
316262395Sbapt			}
317262395Sbapt			cur = cur->next;
318262395Sbapt		}
319262395Sbapt		ucl_add_tabs (func, tabs, compact);
320262395Sbapt		func->ucl_emitter_append_character (']', 1, func->ud);
321262395Sbapt	}
322262395Sbapt	else {
323262395Sbapt		ucl_elt_write_json (obj, func, tabs, start_tabs, compact);
324262395Sbapt	}
325262395Sbapt
326262395Sbapt}
327262395Sbapt
328262395Sbapt/**
329262395Sbapt * Emit an object to json
330262395Sbapt * @param obj object
331262395Sbapt * @return json output (should be freed after using)
332262395Sbapt */
333262395Sbaptstatic void
334262395Sbaptucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func)
335262395Sbapt{
336262395Sbapt	ucl_obj_write_json (obj, func, 0, false, compact);
337262395Sbapt}
338262395Sbapt
339262395Sbapt/**
340262395Sbapt * Write a single object to the buffer
341262395Sbapt * @param obj object to write
342262395Sbapt * @param buf target buffer
343262395Sbapt */
344262395Sbaptstatic void
345262395Sbaptucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
346262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top)
347262395Sbapt{
348262395Sbapt	ucl_object_t *cur, *cur_obj;
349262395Sbapt	ucl_hash_iter_t it = NULL;
350262395Sbapt
351262395Sbapt	if (start_tabs) {
352262395Sbapt		ucl_add_tabs (func, tabs, is_top);
353262395Sbapt	}
354262395Sbapt	if (!is_top) {
355262395Sbapt		func->ucl_emitter_append_len ("{\n", 2, func->ud);
356262395Sbapt	}
357262395Sbapt
358262395Sbapt	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
359262395Sbapt		LL_FOREACH (cur, cur_obj) {
360262395Sbapt			ucl_add_tabs (func, tabs + 1, is_top);
361262395Sbapt			if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) {
362262395Sbapt				ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func);
363262395Sbapt			}
364262395Sbapt			else {
365262395Sbapt				func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud);
366262395Sbapt			}
367262395Sbapt			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
368262395Sbapt				func->ucl_emitter_append_len (" = ", 3, func->ud);
369262395Sbapt			}
370262395Sbapt			else {
371262395Sbapt				func->ucl_emitter_append_character (' ', 1, func->ud);
372262395Sbapt			}
373262395Sbapt			ucl_elt_write_config (cur_obj, func,
374262395Sbapt					is_top ? tabs : tabs + 1,
375262395Sbapt					false, false, false);
376262395Sbapt			if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) {
377262395Sbapt				func->ucl_emitter_append_len (";\n", 2, func->ud);
378262395Sbapt			}
379262395Sbapt			else {
380262395Sbapt				func->ucl_emitter_append_character ('\n', 1, func->ud);
381262395Sbapt			}
382262395Sbapt		}
383262395Sbapt	}
384262395Sbapt
385262395Sbapt	ucl_add_tabs (func, tabs, is_top);
386262395Sbapt	if (!is_top) {
387262395Sbapt		func->ucl_emitter_append_character ('}', 1, func->ud);
388262395Sbapt	}
389262395Sbapt}
390262395Sbapt
391262395Sbapt/**
392262395Sbapt * Write a single array to the buffer
393262395Sbapt * @param obj array to write
394262395Sbapt * @param buf target buffer
395262395Sbapt */
396262395Sbaptstatic void
397262395Sbaptucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
398262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top)
399262395Sbapt{
400262395Sbapt	ucl_object_t *cur = obj;
401262395Sbapt
402262395Sbapt	if (start_tabs) {
403262395Sbapt		ucl_add_tabs (func, tabs, false);
404262395Sbapt	}
405262395Sbapt
406262395Sbapt	func->ucl_emitter_append_len ("[\n", 2, func->ud);
407262395Sbapt	while (cur) {
408262395Sbapt		ucl_elt_write_config (cur, func, tabs + 1, true, false, false);
409262395Sbapt		func->ucl_emitter_append_len (",\n", 2, func->ud);
410262395Sbapt		cur = cur->next;
411262395Sbapt	}
412262395Sbapt	ucl_add_tabs (func, tabs, false);
413262395Sbapt	func->ucl_emitter_append_character (']', 1, func->ud);
414262395Sbapt}
415262395Sbapt
416262395Sbapt/**
417262395Sbapt * Emit a single element
418262395Sbapt * @param obj object
419262395Sbapt * @param buf buffer
420262395Sbapt */
421262395Sbaptstatic void
422262395Sbaptucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
423262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
424262395Sbapt{
425262395Sbapt	bool flag;
426262395Sbapt
427262395Sbapt	if (expand_array && obj->next != NULL) {
428262395Sbapt		ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top);
429262395Sbapt	}
430262395Sbapt	else {
431262395Sbapt		switch (obj->type) {
432262395Sbapt		case UCL_INT:
433262395Sbapt			if (start_tabs) {
434262395Sbapt				ucl_add_tabs (func, tabs, false);
435262395Sbapt			}
436262395Sbapt			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
437262395Sbapt			break;
438262395Sbapt		case UCL_FLOAT:
439262395Sbapt		case UCL_TIME:
440262395Sbapt			if (start_tabs) {
441262395Sbapt				ucl_add_tabs (func, tabs, false);
442262395Sbapt			}
443262395Sbapt			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
444262395Sbapt			break;
445262395Sbapt		case UCL_BOOLEAN:
446262395Sbapt			if (start_tabs) {
447262395Sbapt				ucl_add_tabs (func, tabs, false);
448262395Sbapt			}
449262395Sbapt			flag = ucl_object_toboolean (obj);
450262395Sbapt			if (flag) {
451262395Sbapt				func->ucl_emitter_append_len ("true", 4, func->ud);
452262395Sbapt			}
453262395Sbapt			else {
454262395Sbapt				func->ucl_emitter_append_len ("false", 5, func->ud);
455262395Sbapt			}
456262395Sbapt			break;
457262395Sbapt		case UCL_STRING:
458262395Sbapt			if (start_tabs) {
459262395Sbapt				ucl_add_tabs (func, tabs, false);
460262395Sbapt			}
461262395Sbapt			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
462262395Sbapt			break;
463262395Sbapt		case UCL_NULL:
464262395Sbapt			if (start_tabs) {
465262395Sbapt				ucl_add_tabs (func, tabs, false);
466262395Sbapt			}
467262395Sbapt			func->ucl_emitter_append_len ("null", 4, func->ud);
468262395Sbapt			break;
469262395Sbapt		case UCL_OBJECT:
470262395Sbapt			ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top);
471262395Sbapt			break;
472262395Sbapt		case UCL_ARRAY:
473262395Sbapt			ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top);
474262395Sbapt			break;
475262395Sbapt		case UCL_USERDATA:
476262395Sbapt			break;
477262395Sbapt		}
478262395Sbapt	}
479262395Sbapt}
480262395Sbapt
481262395Sbapt/**
482262395Sbapt * Emit an object to rcl
483262395Sbapt * @param obj object
484262395Sbapt * @return rcl output (should be freed after using)
485262395Sbapt */
486262395Sbaptstatic void
487262395Sbaptucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func)
488262395Sbapt{
489262395Sbapt	ucl_elt_write_config (obj, func, 0, false, true, true);
490262395Sbapt}
491262395Sbapt
492262395Sbapt
493262395Sbaptstatic void
494262395Sbaptucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
495262395Sbapt		unsigned int tabs, bool start_tabs)
496262395Sbapt{
497262395Sbapt	bool is_array = (obj->next != NULL);
498262395Sbapt
499262395Sbapt	if (is_array) {
500262395Sbapt		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false);
501262395Sbapt	}
502262395Sbapt	else {
503262395Sbapt		ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true);
504262395Sbapt	}
505262395Sbapt}
506262395Sbapt
507262395Sbapt/**
508262395Sbapt * Write a single object to the buffer
509262395Sbapt * @param obj object to write
510262395Sbapt * @param buf target buffer
511262395Sbapt */
512262395Sbaptstatic void
513262395Sbaptucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
514262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top)
515262395Sbapt{
516262395Sbapt	ucl_object_t *cur;
517262395Sbapt	ucl_hash_iter_t it = NULL;
518262395Sbapt
519262395Sbapt	if (start_tabs) {
520262395Sbapt		ucl_add_tabs (func, tabs, is_top);
521262395Sbapt	}
522262395Sbapt	if (!is_top) {
523262395Sbapt		func->ucl_emitter_append_len ("{\n", 2, func->ud);
524262395Sbapt	}
525262395Sbapt
526262395Sbapt	while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
527262395Sbapt		ucl_add_tabs (func, tabs + 1, is_top);
528262395Sbapt		if (cur->keylen > 0) {
529262395Sbapt			ucl_elt_string_write_json (cur->key, cur->keylen, func);
530262395Sbapt		}
531262395Sbapt		else {
532262395Sbapt			func->ucl_emitter_append_len ("null", 4, func->ud);
533262395Sbapt		}
534262395Sbapt		func->ucl_emitter_append_len (": ", 2, func->ud);
535262395Sbapt		ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false);
536262395Sbapt		if (ucl_hash_iter_has_next(it)) {
537262395Sbapt			if (!is_top) {
538262395Sbapt				func->ucl_emitter_append_len (",\n", 2, func->ud);
539262395Sbapt			}
540262395Sbapt			else {
541262395Sbapt				func->ucl_emitter_append_character ('\n', 1, func->ud);
542262395Sbapt			}
543262395Sbapt		}
544262395Sbapt		else {
545262395Sbapt			func->ucl_emitter_append_character ('\n', 1, func->ud);
546262395Sbapt		}
547262395Sbapt	}
548262395Sbapt
549262395Sbapt	ucl_add_tabs (func, tabs, is_top);
550262395Sbapt	if (!is_top) {
551262395Sbapt		func->ucl_emitter_append_character ('}', 1, func->ud);
552262395Sbapt	}
553262395Sbapt}
554262395Sbapt
555262395Sbapt/**
556262395Sbapt * Write a single array to the buffer
557262395Sbapt * @param obj array to write
558262395Sbapt * @param buf target buffer
559262395Sbapt */
560262395Sbaptstatic void
561262395Sbaptucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
562262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top)
563262395Sbapt{
564262395Sbapt	ucl_object_t *cur = obj;
565262395Sbapt
566262395Sbapt	if (start_tabs) {
567262395Sbapt		ucl_add_tabs (func, tabs, false);
568262395Sbapt	}
569262395Sbapt
570262395Sbapt	func->ucl_emitter_append_len ("[\n", 2, func->ud);
571262395Sbapt	while (cur) {
572262395Sbapt		ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false);
573262395Sbapt		func->ucl_emitter_append_len (",\n", 2, func->ud);
574262395Sbapt		cur = cur->next;
575262395Sbapt	}
576262395Sbapt	ucl_add_tabs (func, tabs, false);
577262395Sbapt	func->ucl_emitter_append_character (']', 1, func->ud);
578262395Sbapt}
579262395Sbapt
580262395Sbapt/**
581262395Sbapt * Emit a single element
582262395Sbapt * @param obj object
583262395Sbapt * @param buf buffer
584262395Sbapt */
585262395Sbaptstatic void
586262395Sbaptucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
587262395Sbapt		unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
588262395Sbapt{
589262395Sbapt	bool flag;
590262395Sbapt
591262395Sbapt	if (expand_array && obj->next != NULL ) {
592262395Sbapt		ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top);
593262395Sbapt	}
594262395Sbapt	else {
595262395Sbapt		switch (obj->type) {
596262395Sbapt		case UCL_INT:
597262395Sbapt			if (start_tabs) {
598262395Sbapt				ucl_add_tabs (func, tabs, false);
599262395Sbapt			}
600262395Sbapt			func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud);
601262395Sbapt			break;
602262395Sbapt		case UCL_FLOAT:
603262395Sbapt		case UCL_TIME:
604262395Sbapt			if (start_tabs) {
605262395Sbapt				ucl_add_tabs (func, tabs, false);
606262395Sbapt			}
607262395Sbapt			func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud);
608262395Sbapt			break;
609262395Sbapt		case UCL_BOOLEAN:
610262395Sbapt			if (start_tabs) {
611262395Sbapt				ucl_add_tabs (func, tabs, false);
612262395Sbapt			}
613262395Sbapt			flag = ucl_object_toboolean (obj);
614262395Sbapt			if (flag) {
615262395Sbapt				func->ucl_emitter_append_len ("true", 4, func->ud);
616262395Sbapt			}
617262395Sbapt			else {
618262395Sbapt				func->ucl_emitter_append_len ("false", 5, func->ud);
619262395Sbapt			}
620262395Sbapt			break;
621262395Sbapt		case UCL_STRING:
622262395Sbapt			if (start_tabs) {
623262395Sbapt				ucl_add_tabs (func, tabs, false);
624262395Sbapt			}
625262395Sbapt			ucl_elt_string_write_json (obj->value.sv, obj->len, func);
626262395Sbapt			break;
627262395Sbapt		case UCL_NULL:
628262395Sbapt			if (start_tabs) {
629262395Sbapt				ucl_add_tabs (func, tabs, false);
630262395Sbapt			}
631262395Sbapt			func->ucl_emitter_append_len ("null", 4, func->ud);
632262395Sbapt			break;
633262395Sbapt		case UCL_OBJECT:
634262395Sbapt			ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top);
635262395Sbapt			break;
636262395Sbapt		case UCL_ARRAY:
637262395Sbapt			ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top);
638262395Sbapt			break;
639262395Sbapt		case UCL_USERDATA:
640262395Sbapt			break;
641262395Sbapt		}
642262395Sbapt	}
643262395Sbapt}
644262395Sbapt
645262395Sbapt/**
646262395Sbapt * Emit an object to rcl
647262395Sbapt * @param obj object
648262395Sbapt * @return rcl output (should be freed after using)
649262395Sbapt */
650262395Sbaptstatic void
651262395Sbaptucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func)
652262395Sbapt{
653262395Sbapt	ucl_elt_write_yaml (obj, func, 0, false, true, true);
654262395Sbapt}
655262395Sbapt
656262395Sbapt/*
657262395Sbapt * Generic utstring output
658262395Sbapt */
659262395Sbaptstatic int
660262395Sbaptucl_utstring_append_character (unsigned char c, size_t len, void *ud)
661262395Sbapt{
662262395Sbapt	UT_string *buf = ud;
663262395Sbapt
664262395Sbapt	if (len == 1) {
665262395Sbapt		utstring_append_c (buf, c);
666262395Sbapt	}
667262395Sbapt	else {
668262395Sbapt		utstring_reserve (buf, len);
669262395Sbapt		memset (&buf->d[buf->i], c, len);
670262395Sbapt		buf->i += len;
671262395Sbapt		buf->d[buf->i] = '\0';
672262395Sbapt	}
673262395Sbapt
674262395Sbapt	return 0;
675262395Sbapt}
676262395Sbapt
677262395Sbaptstatic int
678262395Sbaptucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
679262395Sbapt{
680262395Sbapt	UT_string *buf = ud;
681262395Sbapt
682262395Sbapt	utstring_append_len (buf, str, len);
683262395Sbapt
684262395Sbapt	return 0;
685262395Sbapt}
686262395Sbapt
687262395Sbaptstatic int
688262395Sbaptucl_utstring_append_int (int64_t val, void *ud)
689262395Sbapt{
690262395Sbapt	UT_string *buf = ud;
691262395Sbapt
692262395Sbapt	utstring_printf (buf, "%jd", (intmax_t)val);
693262395Sbapt	return 0;
694262395Sbapt}
695262395Sbapt
696262395Sbaptstatic int
697262395Sbaptucl_utstring_append_double (double val, void *ud)
698262395Sbapt{
699262395Sbapt	UT_string *buf = ud;
700262395Sbapt	const double delta = 0.0000001;
701262395Sbapt
702262395Sbapt	if (val == (double)(int)val) {
703262395Sbapt		utstring_printf (buf, "%.1lf", val);
704262395Sbapt	}
705262395Sbapt	else if (fabs (val - (double)(int)val) < delta) {
706262395Sbapt		/* Write at maximum precision */
707262395Sbapt		utstring_printf (buf, "%.*lg", DBL_DIG, val);
708262395Sbapt	}
709262395Sbapt	else {
710262395Sbapt		utstring_printf (buf, "%lf", val);
711262395Sbapt	}
712262395Sbapt
713262395Sbapt	return 0;
714262395Sbapt}
715262395Sbapt
716262395Sbapt
717262395Sbaptunsigned char *
718262395Sbaptucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
719262395Sbapt{
720262395Sbapt	UT_string *buf = NULL;
721262395Sbapt	unsigned char *res = NULL;
722262395Sbapt	struct ucl_emitter_functions func = {
723262395Sbapt		.ucl_emitter_append_character = ucl_utstring_append_character,
724262395Sbapt		.ucl_emitter_append_len = ucl_utstring_append_len,
725262395Sbapt		.ucl_emitter_append_int = ucl_utstring_append_int,
726262395Sbapt		.ucl_emitter_append_double = ucl_utstring_append_double
727262395Sbapt	};
728262395Sbapt
729262395Sbapt	if (obj == NULL) {
730262395Sbapt		return NULL;
731262395Sbapt	}
732262395Sbapt
733262395Sbapt	utstring_new (buf);
734262395Sbapt	func.ud = buf;
735262395Sbapt
736262395Sbapt	if (buf != NULL) {
737262395Sbapt		if (emit_type == UCL_EMIT_JSON) {
738262395Sbapt			ucl_object_emit_json (obj, false, &func);
739262395Sbapt		}
740262395Sbapt		else if (emit_type == UCL_EMIT_JSON_COMPACT) {
741262395Sbapt			ucl_object_emit_json (obj, true, &func);
742262395Sbapt		}
743262395Sbapt		else if (emit_type == UCL_EMIT_YAML) {
744262395Sbapt			ucl_object_emit_yaml (obj, &func);
745262395Sbapt		}
746262395Sbapt		else {
747262395Sbapt			ucl_object_emit_config (obj, &func);
748262395Sbapt		}
749262395Sbapt
750262395Sbapt		res = utstring_body (buf);
751262395Sbapt		free (buf);
752262395Sbapt	}
753262395Sbapt
754262395Sbapt	return res;
755262395Sbapt}
756262395Sbapt
757262395Sbaptbool
758262395Sbaptucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
759262395Sbapt		struct ucl_emitter_functions *emitter)
760262395Sbapt{
761262395Sbapt	if (emit_type == UCL_EMIT_JSON) {
762262395Sbapt		ucl_object_emit_json (obj, false, emitter);
763262395Sbapt	}
764262395Sbapt	else if (emit_type == UCL_EMIT_JSON_COMPACT) {
765262395Sbapt		ucl_object_emit_json (obj, true, emitter);
766262395Sbapt	}
767262395Sbapt	else if (emit_type == UCL_EMIT_YAML) {
768262395Sbapt		ucl_object_emit_yaml (obj, emitter);
769262395Sbapt	}
770262395Sbapt	else {
771262395Sbapt		ucl_object_emit_config (obj, emitter);
772262395Sbapt	}
773262395Sbapt
774262395Sbapt	/* XXX: need some error checks here */
775262395Sbapt	return true;
776262395Sbapt}
777262395Sbapt
778262395Sbapt
779262395Sbaptunsigned char *
780262395Sbaptucl_object_emit_single_json (ucl_object_t *obj)
781262395Sbapt{
782262395Sbapt	UT_string *buf = NULL;
783262395Sbapt	unsigned char *res = NULL;
784262395Sbapt
785262395Sbapt	if (obj == NULL) {
786262395Sbapt		return NULL;
787262395Sbapt	}
788262395Sbapt
789262395Sbapt	utstring_new (buf);
790262395Sbapt
791262395Sbapt	if (buf != NULL) {
792262395Sbapt		switch (obj->type) {
793262395Sbapt		case UCL_OBJECT:
794262395Sbapt			ucl_utstring_append_len ("object", 6, buf);
795262395Sbapt			break;
796262395Sbapt		case UCL_ARRAY:
797262395Sbapt			ucl_utstring_append_len ("array", 5, buf);
798262395Sbapt			break;
799262395Sbapt		case UCL_INT:
800262395Sbapt			ucl_utstring_append_int (obj->value.iv, buf);
801262395Sbapt			break;
802262395Sbapt		case UCL_FLOAT:
803262395Sbapt		case UCL_TIME:
804262395Sbapt			ucl_utstring_append_double (obj->value.dv, buf);
805262395Sbapt			break;
806262395Sbapt		case UCL_NULL:
807262395Sbapt			ucl_utstring_append_len ("null", 4, buf);
808262395Sbapt			break;
809262395Sbapt		case UCL_BOOLEAN:
810262395Sbapt			if (obj->value.iv) {
811262395Sbapt				ucl_utstring_append_len ("true", 4, buf);
812262395Sbapt			}
813262395Sbapt			else {
814262395Sbapt				ucl_utstring_append_len ("false", 5, buf);
815262395Sbapt			}
816262395Sbapt			break;
817262395Sbapt		case UCL_STRING:
818262395Sbapt			ucl_utstring_append_len (obj->value.sv, obj->len, buf);
819262395Sbapt			break;
820262395Sbapt		case UCL_USERDATA:
821262395Sbapt			ucl_utstring_append_len ("userdata", 8, buf);
822262395Sbapt			break;
823262395Sbapt		}
824262395Sbapt		res = utstring_body (buf);
825262395Sbapt		free (buf);
826262395Sbapt	}
827262395Sbapt
828262395Sbapt	return res;
829262395Sbapt}
830