xref: /freebsd/contrib/libucl/src/ucl_emitter_utils.c (revision 193d9e768ba63fcfb187cfd17f461f7d41345048)
1 /* Copyright (c) 2014, 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 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "ucl.h"
29 #include "ucl_internal.h"
30 #include "ucl_chartable.h"
31 
32 #ifdef HAVE_FLOAT_H
33 #include <float.h>
34 #endif
35 #ifdef HAVE_MATH_H
36 #include <math.h>
37 #endif
38 
39 extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
40 
41 static const struct ucl_emitter_context ucl_standard_emitters[] = {
42 	[UCL_EMIT_JSON] = {
43 		.name = "json",
44 		.id = UCL_EMIT_JSON,
45 		.func = NULL,
46 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]
47 	},
48 	[UCL_EMIT_JSON_COMPACT] = {
49 		.name = "json_compact",
50 		.id = UCL_EMIT_JSON_COMPACT,
51 		.func = NULL,
52 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
53 	},
54 	[UCL_EMIT_CONFIG] = {
55 		.name = "config",
56 		.id = UCL_EMIT_CONFIG,
57 		.func = NULL,
58 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
59 	},
60 	[UCL_EMIT_YAML] = {
61 		.name = "yaml",
62 		.id = UCL_EMIT_YAML,
63 		.func = NULL,
64 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
65 	},
66 	[UCL_EMIT_MSGPACK] = {
67 		.name = "msgpack",
68 		.id = UCL_EMIT_MSGPACK,
69 		.func = NULL,
70 		.ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]
71 	}
72 };
73 
74 /**
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
78  */
79 const struct ucl_emitter_context *
80 ucl_emit_get_standard_context (enum ucl_emitter emit_type)
81 {
82 	if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
83 		return &ucl_standard_emitters[emit_type];
84 	}
85 
86 	return NULL;
87 }
88 
89 /**
90  * Serialise string
91  * @param str string to emit
92  * @param buf target buffer
93  */
94 void
95 ucl_elt_string_write_json (const char *str, size_t size,
96 		struct ucl_emitter_context *ctx)
97 {
98 	const char *p = str, *c = str;
99 	size_t len = 0;
100 	const struct ucl_emitter_functions *func = ctx->func;
101 
102 	func->ucl_emitter_append_character ('"', 1, func->ud);
103 
104 	while (size) {
105 		if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_DENIED)) {
106 			if (len > 0) {
107 				func->ucl_emitter_append_len (c, len, func->ud);
108 			}
109 			switch (*p) {
110 			case '\n':
111 				func->ucl_emitter_append_len ("\\n", 2, func->ud);
112 				break;
113 			case '\r':
114 				func->ucl_emitter_append_len ("\\r", 2, func->ud);
115 				break;
116 			case '\b':
117 				func->ucl_emitter_append_len ("\\b", 2, func->ud);
118 				break;
119 			case '\t':
120 				func->ucl_emitter_append_len ("\\t", 2, func->ud);
121 				break;
122 			case '\f':
123 				func->ucl_emitter_append_len ("\\f", 2, func->ud);
124 				break;
125 			case '\\':
126 				func->ucl_emitter_append_len ("\\\\", 2, func->ud);
127 				break;
128 			case '"':
129 				func->ucl_emitter_append_len ("\\\"", 2, func->ud);
130 				break;
131 			default:
132 				/* Emit unicode unknown character */
133 				func->ucl_emitter_append_len ("\\uFFFD", 5, func->ud);
134 				break;
135 			}
136 			len = 0;
137 			c = ++p;
138 		}
139 		else {
140 			p ++;
141 			len ++;
142 		}
143 		size --;
144 	}
145 
146 	if (len > 0) {
147 		func->ucl_emitter_append_len (c, len, func->ud);
148 	}
149 
150 	func->ucl_emitter_append_character ('"', 1, func->ud);
151 }
152 
153 void
154 ucl_elt_string_write_multiline (const char *str, size_t size,
155 		struct ucl_emitter_context *ctx)
156 {
157 	const struct ucl_emitter_functions *func = ctx->func;
158 
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);
162 }
163 
164 /*
165  * Generic utstring output
166  */
167 static int
168 ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
169 {
170 	UT_string *buf = ud;
171 
172 	if (len == 1) {
173 		utstring_append_c (buf, c);
174 	}
175 	else {
176 		utstring_reserve (buf, len + 1);
177 		memset (&buf->d[buf->i], c, len);
178 		buf->i += len;
179 		buf->d[buf->i] = '\0';
180 	}
181 
182 	return 0;
183 }
184 
185 static int
186 ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
187 {
188 	UT_string *buf = ud;
189 
190 	utstring_append_len (buf, str, len);
191 
192 	return 0;
193 }
194 
195 static int
196 ucl_utstring_append_int (int64_t val, void *ud)
197 {
198 	UT_string *buf = ud;
199 
200 	utstring_printf (buf, "%jd", (intmax_t)val);
201 	return 0;
202 }
203 
204 static int
205 ucl_utstring_append_double (double val, void *ud)
206 {
207 	UT_string *buf = ud;
208 	const double delta = 0.0000001;
209 
210 	if (val == (double)(int)val) {
211 		utstring_printf (buf, "%.1lf", val);
212 	}
213 	else if (fabs (val - (double)(int)val) < delta) {
214 		/* Write at maximum precision */
215 		utstring_printf (buf, "%.*lg", DBL_DIG, val);
216 	}
217 	else {
218 		utstring_printf (buf, "%lf", val);
219 	}
220 
221 	return 0;
222 }
223 
224 /*
225  * Generic file output
226  */
227 static int
228 ucl_file_append_character (unsigned char c, size_t len, void *ud)
229 {
230 	FILE *fp = ud;
231 
232 	while (len --) {
233 		fputc (c, fp);
234 	}
235 
236 	return 0;
237 }
238 
239 static int
240 ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
241 {
242 	FILE *fp = ud;
243 
244 	fwrite (str, len, 1, fp);
245 
246 	return 0;
247 }
248 
249 static int
250 ucl_file_append_int (int64_t val, void *ud)
251 {
252 	FILE *fp = ud;
253 
254 	fprintf (fp, "%jd", (intmax_t)val);
255 
256 	return 0;
257 }
258 
259 static int
260 ucl_file_append_double (double val, void *ud)
261 {
262 	FILE *fp = ud;
263 	const double delta = 0.0000001;
264 
265 	if (val == (double)(int)val) {
266 		fprintf (fp, "%.1lf", val);
267 	}
268 	else if (fabs (val - (double)(int)val) < delta) {
269 		/* Write at maximum precision */
270 		fprintf (fp, "%.*lg", DBL_DIG, val);
271 	}
272 	else {
273 		fprintf (fp, "%lf", val);
274 	}
275 
276 	return 0;
277 }
278 
279 /*
280  * Generic file descriptor writing functions
281  */
282 static int
283 ucl_fd_append_character (unsigned char c, size_t len, void *ud)
284 {
285 	int fd = *(int *)ud;
286 	unsigned char *buf;
287 
288 	if (len == 1) {
289 		return write (fd, &c, 1);
290 	}
291 	else {
292 		buf = malloc (len);
293 		if (buf == NULL) {
294 			/* Fallback */
295 			while (len --) {
296 				if (write (fd, &c, 1) == -1) {
297 					return -1;
298 				}
299 			}
300 		}
301 		else {
302 			memset (buf, c, len);
303 			if (write (fd, buf, len) == -1) {
304 				free(buf);
305 				return -1;
306 			}
307 			free (buf);
308 		}
309 	}
310 
311 	return 0;
312 }
313 
314 static int
315 ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
316 {
317 	int fd = *(int *)ud;
318 
319 	return write (fd, str, len);
320 }
321 
322 static int
323 ucl_fd_append_int (int64_t val, void *ud)
324 {
325 	int fd = *(int *)ud;
326 	char intbuf[64];
327 
328 	snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
329 	return write (fd, intbuf, strlen (intbuf));
330 }
331 
332 static int
333 ucl_fd_append_double (double val, void *ud)
334 {
335 	int fd = *(int *)ud;
336 	const double delta = 0.0000001;
337 	char nbuf[64];
338 
339 	if (val == (double)(int)val) {
340 		snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
341 	}
342 	else if (fabs (val - (double)(int)val) < delta) {
343 		/* Write at maximum precision */
344 		snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
345 	}
346 	else {
347 		snprintf (nbuf, sizeof (nbuf), "%lf", val);
348 	}
349 
350 	return write (fd, nbuf, strlen (nbuf));
351 }
352 
353 struct ucl_emitter_functions*
354 ucl_object_emit_memory_funcs (void **pmem)
355 {
356 	struct ucl_emitter_functions *f;
357 	UT_string *s;
358 
359 	f = calloc (1, sizeof (*f));
360 
361 	if (f != NULL) {
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;
367 		utstring_new (s);
368 		f->ud = s;
369 		*pmem = s->d;
370 		s->pd = pmem;
371 	}
372 
373 	return f;
374 }
375 
376 struct ucl_emitter_functions*
377 ucl_object_emit_file_funcs (FILE *fp)
378 {
379 	struct ucl_emitter_functions *f;
380 
381 	f = calloc (1, sizeof (*f));
382 
383 	if (f != NULL) {
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;
389 		f->ud = fp;
390 	}
391 
392 	return f;
393 }
394 
395 struct ucl_emitter_functions*
396 ucl_object_emit_fd_funcs (int fd)
397 {
398 	struct ucl_emitter_functions *f;
399 	int *ip;
400 
401 	f = calloc (1, sizeof (*f));
402 
403 	if (f != NULL) {
404 		ip = malloc (sizeof (fd));
405 		if (ip == NULL) {
406 			free (f);
407 			return NULL;
408 		}
409 
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;
416 		f->ud = ip;
417 	}
418 
419 	return f;
420 }
421 
422 void
423 ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
424 {
425 	if (f != NULL) {
426 		if (f->ucl_emitter_free_func != NULL) {
427 			f->ucl_emitter_free_func (f->ud);
428 		}
429 		free (f);
430 	}
431 }
432 
433 
434 unsigned char *
435 ucl_object_emit_single_json (const ucl_object_t *obj)
436 {
437 	UT_string *buf = NULL;
438 	unsigned char *res = NULL;
439 
440 	if (obj == NULL) {
441 		return NULL;
442 	}
443 
444 	utstring_new (buf);
445 
446 	if (buf != NULL) {
447 		switch (obj->type) {
448 		case UCL_OBJECT:
449 			ucl_utstring_append_len ("object", 6, buf);
450 			break;
451 		case UCL_ARRAY:
452 			ucl_utstring_append_len ("array", 5, buf);
453 			break;
454 		case UCL_INT:
455 			ucl_utstring_append_int (obj->value.iv, buf);
456 			break;
457 		case UCL_FLOAT:
458 		case UCL_TIME:
459 			ucl_utstring_append_double (obj->value.dv, buf);
460 			break;
461 		case UCL_NULL:
462 			ucl_utstring_append_len ("null", 4, buf);
463 			break;
464 		case UCL_BOOLEAN:
465 			if (obj->value.iv) {
466 				ucl_utstring_append_len ("true", 4, buf);
467 			}
468 			else {
469 				ucl_utstring_append_len ("false", 5, buf);
470 			}
471 			break;
472 		case UCL_STRING:
473 			ucl_utstring_append_len (obj->value.sv, obj->len, buf);
474 			break;
475 		case UCL_USERDATA:
476 			ucl_utstring_append_len ("userdata", 8, buf);
477 			break;
478 		}
479 		res = utstring_body (buf);
480 		free (buf);
481 	}
482 
483 	return res;
484 }
485 
486 #define LONG_STRING_LIMIT 80
487 
488 bool
489 ucl_maybe_long_string (const ucl_object_t *obj)
490 {
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) {
494 			return true;
495 		}
496 	}
497 
498 	return false;
499 }
500