1/*	$NetBSD: data.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2
3/*
4 * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 *   Internet Systems Consortium, Inc.
19 *   PO Box 360
20 *   Newmarket, NH 03857 USA
21 *   <info@isc.org>
22 *   http://www.isc.org/
23 */
24
25#include <sys/cdefs.h>
26__RCSID("$NetBSD: data.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
27
28#include "data.h"
29
30#include <sys/types.h>
31#include <arpa/inet.h>
32#include <assert.h>
33#include <stdlib.h>
34#include <string.h>
35
36struct string *
37allocString(void)
38{
39	struct string *result;
40
41	result = (struct string *)malloc(sizeof(struct string));
42	assert(result != NULL);
43	memset(result, 0, sizeof(struct string));
44
45	return result;
46}
47
48struct string *
49makeString(int l, const char *s)
50{
51	struct string *result;
52
53	result = allocString();
54	if (l < 0)
55		result->length = strlen(s);
56	else
57		result->length = (size_t)l;
58	if (result->length > 0) {
59		result->content = (char *)malloc(result->length + 1);
60		assert(result->content != NULL);
61		memcpy(result->content, s, result->length);
62		result->content[result->length] = 0;
63	}
64
65	return result;
66}
67
68struct string *
69makeStringExt(int l, const char *s, char fmt)
70{
71	switch (fmt) {
72	case 'Z':
73		/* zero-length */
74		return allocString();
75
76	case 'l': {
77		/* 32-bit signed integer */
78		int32_t x;
79		char buf[40];
80
81		assert(s != NULL);
82		assert(l > 3);
83
84		memcpy(&x, s, 4);
85		x = (int32_t)ntohl((uint32_t)x);
86		snprintf(buf, sizeof(buf), "%lld", (long long)x);
87		return makeString(-1, buf);
88	}
89
90	case 'L': {
91		/* 32-bit unsigned integer */
92		uint32_t x;
93		char buf[40];
94
95		assert(s != NULL);
96		assert(l > 3);
97
98		memcpy(&x, s, 4);
99		x = ntohl(x);
100		snprintf(buf, sizeof(buf), "%llu", (unsigned long long)x);
101		return makeString(-1, buf);
102	}
103
104	case 's': {
105		/* 16-bit signed integer */
106		int16_t x;
107		char buf[20];
108
109		assert(s != NULL);
110		assert(l > 1);
111
112		memcpy(&x, s, 2);
113		x = (int16_t)ntohs((uint16_t)x);
114		snprintf(buf, sizeof(buf), "%hd", x);
115		return makeString(-1, buf);
116	}
117
118	case 'S': {
119		/* 16-bit unsigned integer */
120		uint16_t x;
121		char buf[20];
122
123		assert(s != NULL);
124		assert(l > 1);
125
126		memcpy(&x, s, 2);
127		x = ntohs(x);
128		snprintf(buf, sizeof(buf), "%hu", x);
129		return makeString(-1, buf);
130	}
131
132	case 'b': {
133		/* 8-bit signed integer */
134		int8_t x;
135		char buf[10];
136
137		assert(s != NULL);
138		assert(l > 0);
139
140		memcpy(&x, s, 1);
141		snprintf(buf, sizeof(buf), "%hhd", x);
142		return makeString(-1, buf);
143	}
144
145	case 'B': {
146		/* 8-bit unsigned integer */
147		uint8_t x;
148		char buf[10];
149
150		assert(s != NULL);
151		assert(l > 0);
152
153		memcpy(&x, s, 1);
154		snprintf(buf, sizeof(buf), "%hhu", x);
155		return makeString(-1, buf);
156	}
157
158	case 'f': {
159		/* flag (true or false) */
160		uint8_t f;
161
162		assert(s != NULL);
163		assert(l > 0);
164
165		f = *s;
166		return makeString(-1, f ? "true" : "false");
167	}
168
169	case 'X': {
170		/* binary data */
171		struct string *result;
172		size_t i;
173		char buf[4];
174
175		assert((l == 0) || (s != NULL));
176
177		result = allocString();
178		for (i = 0; i < l; i++) {
179			snprintf(buf, sizeof(buf), "%02hhx", (uint8_t)s[i]);
180			appendString(result, buf);
181		}
182		return result;
183	}
184
185	case 'H': {
186		/* binary data with colons */
187		struct string *result;
188		size_t i;
189		isc_boolean_t first = ISC_TRUE;
190		char buf[4];
191
192		assert((l == 0) || (s != NULL));
193
194		result = allocString();
195		for (i = 0; i < l; i++) {
196			if (!first)
197				appendString(result, ":");
198			first = ISC_FALSE;
199			snprintf(buf, sizeof(buf), "%02hhx", (uint8_t)s[i]);
200			appendString(result, buf);
201		}
202		return result;
203	}
204
205	case 'I': {
206		/* IPv4 address to text */
207		char buf[40 /* INET_ADDRSTRLEN == 26 */];
208
209		assert(l > 3);
210		assert(inet_ntop(AF_INET, s, buf, sizeof(buf)) != NULL);
211		return makeString(-1, buf);
212	}
213
214	case 'i': {
215		/* IPv4 address to hexa */
216		uint8_t a[4];
217		char buf[10];
218
219		assert(inet_pton(AF_INET, s, a) == 1);
220		snprintf(buf, sizeof(buf), "%02hhx%02hhx%02hhx%02hhx",
221			 a[0], a[1], a[2], a[3]);
222		return makeString(-1, buf);
223	}
224
225	case '6': {
226		/* IPv6 address */
227		char buf[80 /* INET6_ADDRSTRLEN == 46 */];
228
229		assert(l > 15);
230		assert(inet_ntop(AF_INET6, s, buf, sizeof(buf)) != NULL);
231		return makeString(-1, buf);
232	}
233
234	case 'd': {
235		/* FQDN to DNS wire format */
236		struct string *result;
237		const char *p;
238		const char *dot;
239		char ll;
240
241		assert(s[l] == '0');
242
243		result = allocString();
244		p = s;
245		while ((dot = strchr(p, '.')) != NULL) {
246			int len;
247
248			len = dot - p - 1;
249			if ((len & 0xc0) != 0)
250				return NULL;
251			if (dot - s >= l)
252				return NULL;
253			ll = len & 0x3f;
254			concatString(result, makeString(1, &ll));
255			concatString(result, makeString(len, p));
256			p = dot + 1;
257			if (p - s == l)
258				break;
259		}
260		if (dot == NULL) {
261			ll = 0;
262			concatString(result, makeString(1, &ll));
263		}
264		return result;
265	}
266
267	default:
268		assert(0);
269	}
270}
271
272struct string *
273makeStringArray(int l, const char *s, char fmt)
274{
275	struct string *result;
276	size_t step;
277	isc_boolean_t first = ISC_TRUE;
278
279	switch (fmt) {
280	case '6':
281		step = 16;
282		break;
283	case 'l':
284	case 'L':
285	case 'I':
286		step = 4;
287		break;
288	case 's':
289	case 'S':
290		step = 2;
291		break;
292	case 'b':
293	case 'B':
294	case 'f':
295		step = 1;
296		break;
297	default:
298		assert(0);
299	}
300
301	assert((l % step) == 0);
302
303	result = allocString();
304	while (l > 0) {
305		if (!first)
306			appendString(result, ",");
307		first = ISC_FALSE;
308		concatString(result, makeStringExt(l, s, fmt));
309		s += step;
310		l -= step;
311	}
312	return result;
313}
314
315void
316appendString(struct string *s, const char *a)
317{
318	size_t n;
319
320	assert(s != NULL);
321
322	if (a == NULL)
323		return;
324	n = strlen(a);
325	if (n == 0)
326		return;
327	s->content = (char *)realloc(s->content, s->length + n + 1);
328	assert(s->content != NULL);
329	memcpy(s->content + s->length, a, n);
330	s->length += n;
331	s->content[s->length] = 0;
332}
333
334void
335concatString(struct string *s, const struct string *a)
336{
337	assert(s != NULL);
338	assert(a != NULL);
339
340	s->content = (char *)realloc(s->content, s->length + a->length + 1);
341	assert(s->content != NULL);
342	memcpy(s->content + s->length, a->content, a->length);
343	s->length += a->length;
344	s->content[s->length] = 0;
345}
346
347isc_boolean_t
348eqString(const struct string *s, const struct string *o)
349{
350	assert(s != NULL);
351	assert(o != NULL);
352
353	if (s->length != o->length)
354		return ISC_FALSE;
355	if (s->length == 0)
356		return ISC_TRUE;
357	return ISC_TF(memcmp(s->content, o->content, s->length) == 0);
358}
359
360struct string *
361quote(struct string *s)
362{
363	struct string *result;
364
365	result = makeString(-1, "'");
366	concatString(result, s);
367	appendString(result, "'");
368	return result;
369}
370
371struct comment *
372createComment(const char *line)
373{
374	struct comment *comment;
375
376	assert(line != NULL);
377
378	comment = (struct comment *)malloc(sizeof(struct comment));
379	assert(comment != NULL);
380	memset(comment, 0, sizeof(struct comment));
381
382	comment->line = strdup(line);
383
384	return comment;
385}
386
387int64_t
388intValue(const struct element *e)
389{
390	assert(e != NULL);
391	assert(e->type == ELEMENT_INTEGER);
392	return e->value.int_value;
393}
394
395double
396doubleValue(const struct element *e)
397{
398	assert(e != NULL);
399	assert(e->type == ELEMENT_REAL);
400	return e->value.double_value;
401}
402
403isc_boolean_t
404boolValue(const struct element *e)
405{
406	assert(e != NULL);
407	assert(e->type == ELEMENT_BOOLEAN);
408	/* could check if 0 or 1 */
409	return e->value.bool_value;
410}
411
412struct string *
413stringValue(struct element *e)
414{
415	assert(e != NULL);
416	assert(e->type == ELEMENT_STRING);
417	return &e->value.string_value;
418}
419
420struct list *
421listValue(struct element *e)
422{
423	assert(e != NULL);
424	assert(e->type == ELEMENT_LIST);
425	return &e->value.list_value;
426}
427
428struct map *
429mapValue(struct element *e)
430{
431	assert(e != NULL);
432	assert(e->type == ELEMENT_MAP);
433	return &e->value.map_value;
434}
435
436struct element *
437create(void)
438{
439	struct element *elem;
440
441	elem = (struct element *)malloc(sizeof(struct element));
442	assert(elem != NULL);
443	memset(elem, 0, sizeof(struct element));
444	TAILQ_INIT(&elem->comments);
445
446	return elem;
447}
448
449struct element *
450createInt(int64_t i)
451{
452	struct element *elem;
453
454	elem = create();
455	elem->type = ELEMENT_INTEGER;
456	elem->value.int_value = i;
457
458	return elem;
459}
460
461struct element *
462createDouble(double d)
463{
464	struct element *elem;
465
466	elem = create();
467	elem->type = ELEMENT_REAL;
468	elem->value.double_value = d;
469
470	return elem;
471}
472
473struct element *
474createBool(isc_boolean_t b)
475{
476	struct element *elem;
477
478	elem = create();
479	elem->type = ELEMENT_BOOLEAN;
480	elem->value.bool_value = b;
481
482	return elem;
483}
484
485struct element *
486createNull(void)
487{
488	struct element *elem;
489
490	elem = create();
491	elem->type = ELEMENT_NULL;
492
493	return elem;
494}
495
496struct element *
497createString(const struct string *s)
498{
499	struct element *elem;
500
501	elem = create();
502	elem->type = ELEMENT_STRING;
503	elem->value.string_value = *s;
504
505	return elem;
506}
507
508struct element *
509createList(void)
510{
511	struct element *elem;
512
513	elem = create();
514	elem->type = ELEMENT_LIST;
515	TAILQ_INIT(&elem->value.list_value);
516
517	return elem;
518}
519
520struct element *
521createMap(void)
522{
523	struct element *elem;
524
525	elem = create();
526	elem->type = ELEMENT_MAP;
527	TAILQ_INIT(&elem->value.map_value);
528
529	return elem;
530}
531
532static void
533reset(struct element *e)
534{
535	e->type = 0;
536	e->kind = 0;
537	assert(e->key == NULL);
538	memset(&e->value, 0, sizeof(e->value));
539}
540
541void
542resetInt(struct element *e, int64_t i)
543{
544	assert(e != NULL);
545
546	reset(e);
547	e->type = ELEMENT_INTEGER;
548	e->value.int_value = i;
549}
550
551void
552resetDouble(struct element *e, double d)
553{
554	assert(e != NULL);
555
556	reset(e);
557	e->type = ELEMENT_REAL;
558	e->value.double_value = d;
559}
560
561void
562resetBool(struct element *e, isc_boolean_t b)
563{
564	assert(e != NULL);
565
566	reset(e);
567	e->type = ELEMENT_BOOLEAN;
568	e->value.bool_value = b;
569}
570
571void resetNull(struct element *e)
572{
573	assert(e != NULL);
574
575	reset(e);
576	e->type = ELEMENT_NULL;
577}
578
579void
580resetString(struct element *e, const struct string *s)
581{
582	assert(e != NULL);
583
584	reset(e);
585	e->type = ELEMENT_STRING;
586	e->value.string_value = *s;
587}
588
589void
590resetList(struct element *e)
591{
592	assert(e != NULL);
593
594	reset(e);
595	e->type = ELEMENT_LIST;
596	TAILQ_INIT(&e->value.list_value);
597}
598
599void
600resetMap(struct element *e)
601{
602	assert(e != NULL);
603
604	reset(e);
605	e->type = ELEMENT_MAP;
606	TAILQ_INIT(&e->value.map_value);
607}
608
609void
610resetBy(struct element *e, struct element *o)
611{
612	assert(e != NULL);
613	assert(o != NULL);
614
615	reset(e);
616	e->type = o->type;
617	e->kind = o->kind;
618	e->skip = o->skip;
619	e->key = o->key;
620	o->key = NULL;
621	TAILQ_CONCAT(&e->comments, &o->comments);
622
623	switch (e->type) {
624	case ELEMENT_INTEGER:
625		e->value.int_value = o->value.int_value;
626		break;
627	case ELEMENT_REAL:
628		e->value.double_value = o->value.double_value;
629		break;
630	case ELEMENT_BOOLEAN:
631		e->value.bool_value = o->value.bool_value;
632		break;
633	case ELEMENT_STRING:
634		e->value.string_value = o->value.string_value;
635		break;
636	case ELEMENT_LIST:
637		TAILQ_INIT(&e->value.list_value);
638		TAILQ_CONCAT(&e->value.list_value, &o->value.list_value);
639		break;
640	case ELEMENT_MAP:
641		TAILQ_INIT(&e->value.map_value);
642		TAILQ_CONCAT(&e->value.map_value, &o->value.map_value);
643		break;
644	default:
645		assert(0);
646	}
647	reset(o);
648}
649
650struct element *
651listGet(struct element *l, int i)
652{
653	struct element *elem;
654
655	assert(l != NULL);
656	assert(l->type == ELEMENT_LIST);
657	assert(i >= 0);
658
659	elem = TAILQ_FIRST(&l->value.list_value);
660	assert(elem != NULL);
661	assert(elem->key == NULL);
662
663	unsigned j;
664	for (j = i; j > 0; --j) {
665		elem = TAILQ_NEXT(elem);
666		assert(elem != NULL);
667		assert(elem->key == NULL);
668	}
669
670	return elem;
671}
672
673void
674listSet(struct element *l, struct element *e, int i)
675{
676	assert(l != NULL);
677	assert(l->type == ELEMENT_LIST);
678	assert(e != NULL);
679	assert(i >= 0);
680
681	if (i == 0) {
682		TAILQ_INSERT_HEAD(&l->value.list_value, e);
683	} else {
684		struct element *prev;
685
686		prev = TAILQ_FIRST(&l->value.list_value);
687		assert(prev != NULL);
688		assert(prev->key == NULL);
689
690		unsigned j;
691		for (j = i; j > 1; --j) {
692			prev = TAILQ_NEXT(prev);
693			assert(prev != NULL);
694			assert(prev->key == NULL);
695		}
696
697		TAILQ_INSERT_AFTER(&l->value.list_value, prev, e);
698	}
699}
700
701void
702listPush(struct element *l, struct element *e)
703{
704	assert(l != NULL);
705	assert(l->type == ELEMENT_LIST);
706	assert(e != NULL);
707
708	TAILQ_INSERT_TAIL(&l->value.list_value, e);
709}
710
711void
712listRemove(struct element *l, int i)
713{
714	struct element *elem;
715
716	assert(l != NULL);
717	assert(l->type == ELEMENT_LIST);
718	assert(i >= 0);
719
720	elem = TAILQ_FIRST(&l->value.list_value);
721	assert(elem != NULL);
722	assert(elem->key == NULL);
723
724	unsigned j;
725	for (j = i; j > 0; --j) {
726		elem = TAILQ_NEXT(elem);
727		assert(elem != NULL);
728		assert(elem->key == NULL);
729	}
730
731	TAILQ_REMOVE(&l->value.list_value, elem);
732}
733
734size_t
735listSize(const struct element *l)
736{
737	struct element *elem;
738	size_t cnt;
739
740	assert(l != NULL);
741	assert(l->type == ELEMENT_LIST);
742
743	cnt = 0;
744	TAILQ_FOREACH(elem, &l->value.list_value) {
745		assert(elem->key == NULL);
746		cnt++;
747	}
748
749	return cnt;
750}
751
752void
753concat(struct element *l, struct element *o)
754{
755	assert(l != NULL);
756	assert(l->type == ELEMENT_LIST);
757	assert(o != NULL);
758	assert(o->type == ELEMENT_LIST);
759
760	TAILQ_CONCAT(&l->value.list_value, &o->value.list_value);
761}
762
763struct element *
764mapGet(struct element *m, const char *k)
765{
766	struct element *elem;
767
768	assert(m != NULL);
769	assert(m->type == ELEMENT_MAP);
770	assert(k != NULL);
771
772	TAILQ_FOREACH(elem, &m->value.map_value) {
773		assert(elem->key != NULL);
774		if (strcmp(elem->key, k) == 0)
775			break;
776	}
777
778	return elem;
779}
780
781void
782mapSet(struct element *m, struct element *e, const char *k)
783{
784	assert(m != NULL);
785	assert(m->type == ELEMENT_MAP);
786	assert(e != NULL);
787	assert(k != NULL);
788#if 0
789	assert(mapGet(m, k) == NULL);
790#endif
791	e->key = strdup(k);
792	assert(e->key != NULL);
793	TAILQ_INSERT_TAIL(&m->value.map_value, e);
794}
795
796void
797mapRemove(struct element *m, const char *k)
798{
799	struct element *elem;
800
801	assert(m != NULL);
802	assert(m->type == ELEMENT_MAP);
803	assert(k != NULL);
804
805	TAILQ_FOREACH(elem, &m->value.map_value) {
806		assert(elem->key != NULL);
807		if (strcmp(elem->key, k) == 0)
808			break;
809	}
810
811	assert(elem != NULL);
812	TAILQ_REMOVE(&m->value.map_value, elem);
813}
814
815isc_boolean_t
816mapContains(const struct element *m, const char *k)
817{
818	struct element *elem;
819
820	assert(m != NULL);
821	assert(m->type == ELEMENT_MAP);
822	assert(k != NULL);
823
824	TAILQ_FOREACH(elem, &m->value.map_value) {
825		assert(elem->key != NULL);
826		if (strcmp(elem->key, k) == 0)
827			break;
828	}
829
830	return ISC_TF(elem != NULL);
831}
832
833size_t
834mapSize(const struct element *m)
835{
836	struct element *elem;
837	size_t cnt;
838
839	assert(m != NULL);
840	assert(m->type == ELEMENT_MAP);
841
842	cnt = 0;
843	TAILQ_FOREACH(elem, &m->value.map_value) {
844		assert(elem->key != NULL);
845		cnt++;
846	}
847
848	return cnt;
849}
850
851void
852merge(struct element *m, struct element *o)
853{
854	struct element *elem;
855	struct element *ne;
856
857	assert(m != NULL);
858	assert(m->type == ELEMENT_MAP);
859	assert(o != NULL);
860	assert(o->type == ELEMENT_MAP);
861
862	TAILQ_FOREACH_SAFE(elem, &o->value.map_value, ne) {
863		assert(elem->key != NULL);
864		TAILQ_REMOVE(&o->value.map_value, elem);
865		if (!mapContains(m, elem->key)) {
866			TAILQ_INSERT_TAIL(&m->value.map_value, elem);
867		}
868	}
869}
870
871const char *
872type2name(int t)
873{
874	switch (t) {
875	case ELEMENT_NONE:
876		return "not initialized?";
877	case ELEMENT_INTEGER:
878		return "integer";
879	case ELEMENT_REAL:
880		return "real";
881	case ELEMENT_BOOLEAN:
882		return "boolean";
883	case ELEMENT_NULL:
884		return "(unused) null";
885	case ELEMENT_STRING:
886		return "string";
887	case ELEMENT_LIST:
888		return "list";
889	case ELEMENT_MAP:
890		return "map";
891	default:
892#if 0
893		assert(0);
894#endif
895		return "unknown?";
896	}
897}
898
899int
900name2type(const char *n)
901{
902	assert(n != NULL);
903	if (strcmp(n, "integer") == 0)
904		return ELEMENT_INTEGER;
905	if (strcmp(n, "real") == 0)
906		return ELEMENT_REAL;
907	if (strcmp(n, "boolean") == 0)
908		return ELEMENT_BOOLEAN;
909	if (strcmp(n, "null") == 0)
910		return ELEMENT_NULL;
911	if (strcmp(n, "string") == 0)
912		return ELEMENT_STRING;
913	if (strcmp(n, "list") == 0)
914		return ELEMENT_LIST;
915	if (strcmp(n, "map") == 0)
916		return ELEMENT_MAP;
917#if 0
918	assert(0);
919#endif
920	return ELEMENT_NONE;
921}
922
923void
924print(FILE *fp, const struct element *e, isc_boolean_t skip, unsigned indent)
925{
926	assert(fp != NULL);
927	assert(e != NULL);
928
929	switch (e->type) {
930	case ELEMENT_LIST:
931		printList(fp, &e->value.list_value, skip, indent);
932		return;
933	case ELEMENT_MAP:
934		printMap(fp, &e->value.map_value, skip, indent);
935		return;
936	case ELEMENT_STRING:
937		printString(fp, &e->value.string_value);
938		return;
939	case ELEMENT_INTEGER:
940		fprintf(fp, "%lld", (long long)e->value.int_value);
941		return;
942	case ELEMENT_REAL:
943		fprintf(fp, "%f", e->value.double_value);
944		return;
945	case ELEMENT_BOOLEAN:
946		if (e->value.bool_value)
947			fprintf(fp, "true");
948		else
949			fprintf(fp, "false");
950		return;
951	case ELEMENT_NULL:
952		fprintf(fp, "null");
953		return;
954	default:
955		assert(0);
956	}
957}
958
959static void
960addIndent(FILE *fp, int skip, unsigned indent)
961{
962	unsigned sp;
963
964	if (skip) {
965		fprintf(fp, "//");
966		if (indent > 2)
967			for (sp = 0; sp < indent - 2; ++sp)
968				fprintf(fp, " ");
969	} else
970		for (sp = 0; sp < indent; ++sp)
971			fprintf(fp, " ");
972}
973
974void
975printList(FILE *fp, const struct list *l, isc_boolean_t skip, unsigned indent)
976{
977	struct element *elem;
978	struct comment *comment;
979	isc_boolean_t first;
980
981	assert(fp != NULL);
982	assert(l != NULL);
983
984	if (TAILQ_EMPTY(l)) {
985		fprintf(fp, "[ ]");
986		return;
987	}
988
989	fprintf(fp, "[\n");
990	first = ISC_TRUE;
991	TAILQ_FOREACH(elem, l) {
992		isc_boolean_t skip_elem = skip;
993
994		assert(elem->key == NULL);
995		if (!skip) {
996			skip_elem = elem->skip;
997			if (skip_to_end(elem)) {
998				if (!first)
999					fprintf(fp, "\n");
1000				first = ISC_TRUE;
1001			}
1002		}
1003		if (!first)
1004			fprintf(fp, ",\n");
1005		first = ISC_FALSE;
1006		TAILQ_FOREACH(comment, &elem->comments) {
1007			addIndent(fp, skip_elem, indent + 2);
1008			fprintf(fp, "%s\n", comment->line);
1009		}
1010		addIndent(fp, skip_elem, indent + 2);
1011		print(fp, elem, skip_elem, indent + 2);
1012	}
1013	fprintf(fp, "\n");
1014	addIndent(fp, skip, indent);
1015	fprintf(fp, "]");
1016}
1017
1018void
1019printMap(FILE *fp, const struct map *m, isc_boolean_t skip, unsigned indent)
1020{
1021	struct element *elem;
1022	struct comment *comment;
1023	isc_boolean_t first;
1024
1025	assert(fp != NULL);
1026	assert(m != NULL);
1027
1028	if (TAILQ_EMPTY(m)) {
1029		fprintf(fp, "{ }");
1030		return;
1031	}
1032
1033	fprintf(fp, "{\n");
1034	first = ISC_TRUE;
1035	TAILQ_FOREACH(elem, m) {
1036		isc_boolean_t skip_elem = skip;
1037
1038		assert(elem->key != NULL);
1039		if (!skip) {
1040			skip_elem = elem->skip;
1041			if (skip_to_end(elem)) {
1042				if (!first)
1043					fprintf(fp, "\n");
1044				first = ISC_TRUE;
1045			}
1046		}
1047		if (!first)
1048			fprintf(fp, ",\n");
1049		first = ISC_FALSE;
1050		TAILQ_FOREACH(comment, &elem->comments) {
1051			addIndent(fp, skip_elem, indent + 2);
1052			fprintf(fp, "%s\n", comment->line);
1053		}
1054		addIndent(fp, skip_elem, indent + 2);
1055		fprintf(fp, "\"%s\": ", elem->key);
1056		print(fp, elem, skip_elem, indent + 2);
1057	}
1058	fprintf(fp, "\n");
1059	addIndent(fp, skip, indent);
1060	fprintf(fp, "}");
1061}
1062
1063void
1064printString(FILE *fp, const struct string *s)
1065{
1066	size_t i;
1067
1068	assert(fp != NULL);
1069	assert(s != NULL);
1070
1071	fprintf(fp, "\"");
1072	for (i = 0; i < s->length; i++) {
1073		char c = *(s->content + i);
1074
1075		switch (c) {
1076		case '"':
1077			fprintf(fp, "\\\"");
1078			break;
1079		case '\\':
1080			fprintf(fp, "\\\\");
1081			break;
1082		case '\b':
1083			fprintf(fp, "\\b");
1084			break;
1085		case '\f':
1086			fprintf(fp, "\\f");
1087			break;
1088		case '\n':
1089			fprintf(fp, "\\n");
1090			break;
1091		case '\r':
1092			fprintf(fp, "\\r");
1093			break;
1094		case '\t':
1095			fprintf(fp, "\\t");
1096			break;
1097		default:
1098			if ((c >= 0) && (c < 0x20)) {
1099				fprintf(fp, "\\u%04x", (unsigned)c & 0xff);
1100			} else {
1101				fprintf(fp, "%c", c);
1102			}
1103		}
1104	}
1105	fprintf(fp, "\"");
1106}
1107
1108isc_boolean_t
1109skip_to_end(const struct element *e)
1110{
1111	do {
1112		if (!e->skip)
1113			return ISC_FALSE;
1114		e = TAILQ_NEXT(e);
1115	} while (e != NULL);
1116	return ISC_TRUE;
1117}
1118
1119struct element *
1120copy(struct element *e)
1121{
1122	struct element *result;
1123	struct comment *comment;
1124
1125	assert(e != NULL);
1126
1127	switch (e->type) {
1128	case ELEMENT_INTEGER:
1129		result = createInt(intValue(e));
1130		break;
1131	case ELEMENT_REAL:
1132		result = createDouble(doubleValue(e));
1133		break;
1134	case ELEMENT_BOOLEAN:
1135		result = createBool(boolValue(e));
1136		break;
1137	case ELEMENT_NULL:
1138		result = createNull();
1139		break;
1140	case ELEMENT_STRING:
1141		result = createString(stringValue(e));
1142		break;
1143	case ELEMENT_LIST:
1144		result = copyList(e);
1145		break;
1146	case ELEMENT_MAP:
1147		result = copyMap(e);
1148		break;
1149	default:
1150		assert(0);
1151	}
1152	result->kind = e->kind;
1153	result->skip = e->skip;
1154	/* don't copy key */
1155	/* copy comments */
1156	TAILQ_FOREACH(comment, &e->comments) {
1157		/* do not reuse comment variable! */
1158		struct comment *tmp;
1159
1160		tmp = createComment(comment->line);
1161		TAILQ_INSERT_TAIL(&result->comments, tmp);
1162	}
1163	return result;
1164}
1165
1166struct element *
1167copyList(struct element *l)
1168{
1169	struct element *result;
1170	size_t i;
1171
1172	result = createList();
1173	for (i = 0; i < listSize(l); i++)
1174		listPush(result, copy(listGet(l, i)));
1175	return result;
1176}
1177
1178struct element *
1179copyMap(struct element *m)
1180{
1181	struct element *result;
1182	struct element *item;
1183
1184	result = createMap();
1185	TAILQ_FOREACH(item, &m->value.map_value)
1186		mapSet(result, copy(item), item->key);
1187	return result;
1188}
1189
1190struct handle *
1191mapPop(struct element *m)
1192{
1193	struct element *item;
1194	struct handle *h;
1195
1196	assert(m != NULL);
1197	assert(m->type == ELEMENT_MAP);
1198
1199	h = (struct handle *)malloc(sizeof(struct handle));
1200	assert(h != NULL);
1201	memset(h, 0, sizeof(struct handle));
1202	TAILQ_INIT(&h->values);
1203
1204	item = TAILQ_FIRST(&m->value.map_value);
1205	assert(item != NULL);
1206	assert(item->key != NULL);
1207	h->key = strdup(item->key);
1208	assert(h->key != NULL);
1209	h->value = item;
1210
1211	TAILQ_REMOVE(&m->value.map_value, item);
1212
1213	return h;
1214}
1215
1216void
1217derive(struct handle *src, struct handle *dst)
1218{
1219	struct element *list;
1220	struct element *item;
1221	size_t i;
1222
1223	if (dst == NULL)
1224		return;
1225	list = dst->value;
1226	assert(list != NULL);
1227	assert(list->type == ELEMENT_LIST);
1228	for (i = 0; i < listSize(list); i++) {
1229		item = listGet(list, i);
1230		assert(item != NULL);
1231		assert(item->type == ELEMENT_MAP);
1232		if (mapContains(item, src->key))
1233			continue;
1234		mapSet(item, copy(src->value), src->key);
1235	}
1236}
1237
1238struct string *
1239hexaValue(struct element *s)
1240{
1241	struct string *h;
1242
1243	assert(s != NULL);
1244	assert(s->type == ELEMENT_STRING);
1245
1246	h = stringValue(s);
1247	assert(h->length >= 2);
1248
1249	/* string leading 0x */
1250	return makeString(h->length - 2, h->content + 2);
1251}
1252
1253struct element *
1254createHexa(struct string *h)
1255{
1256	struct string *s;
1257
1258	assert(h != NULL);
1259
1260	s = makeString(-1, "0x");
1261	concatString(s, h);
1262	return createString(s);
1263}
1264