1 /* grecs - Gray's Extensible Configuration System
2    Copyright (C) 2007-2016 Sergey Poznyakoff
3 
4    Grecs is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 3 of the License, or (at your
7    option) any later version.
8 
9    Grecs is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with Grecs. If not, see <http://www.gnu.org/licenses/>. */
16 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <string.h>
21 #include <stdlib.h>
22 #include "grecs.h"
23 #include "grecs/json.h"
24 
25 static void
json_writez(struct json_format * fmt,char const * str)26 json_writez(struct json_format *fmt, char const *str)
27 {
28 	size_t len = strlen(str);
29 	fmt->write(fmt->data, str, len);
30 }
31 
32 static void
json_writec(struct json_format * fmt,char c)33 json_writec(struct json_format *fmt, char c)
34 {
35 	fmt->write(fmt->data, &c, 1);
36 }
37 
38 static void
json_indent(struct json_format * fmt,size_t level)39 json_indent(struct json_format *fmt, size_t level)
40 {
41 	level *= fmt->indent;
42 	while (level--)
43 		json_writec(fmt, ' ');
44 }
45 
46 static void
json_format_delim(struct json_format * fmt,size_t level)47 json_format_delim(struct json_format *fmt, size_t level)
48 {
49 	json_writec(fmt, ',');
50 	if (fmt->indent) {
51 		json_writec(fmt, '\n');
52 		json_indent(fmt, level);
53 	} else
54 		json_writec(fmt, ' ');
55 }
56 
57 static int
escape(char c,char * o)58 escape(char c, char *o)
59 {
60 	static char transtab[] = "\\\\\"\"b\bf\fn\nr\rt\t";
61 	char *p;
62 
63 	for (p = transtab; *p; p += 2) {
64 		if (p[1] == c) {
65 			*o = p[0];
66 			return 0;
67 		}
68 	}
69 	return -1;
70 }
71 
72 static void
json_format_string(struct json_format * fmt,const char * s)73 json_format_string(struct json_format *fmt, const char *s)
74 {
75 	json_writec(fmt, '"');
76 	for (; *s; s++) {
77 		char c;
78 		if (!escape(*s, &c)) {
79 			json_writec(fmt, '\\');
80 			json_writec(fmt, c);
81 		} else
82 			json_writec(fmt, *s);
83 	}
84 	json_writec(fmt, '"');
85 }
86 
87 static void
json_format_number(struct json_format * fmt,double n)88 json_format_number(struct json_format *fmt, double n)
89 {
90 	char *buffer = NULL;
91 	size_t size = 0;
92 	if (fmt->precision == -1)
93 		grecs_asprintf(&buffer, &size, "%e", n);
94 	else
95 		grecs_asprintf(&buffer, &size, "%.*f", fmt->precision, n);
96 	json_writez(fmt, buffer);
97 	free(buffer);
98 }
99 
100 static int
collect_keypairs(void * sym,void * data)101 collect_keypairs(void *sym, void *data)
102 {
103 	struct json_pair *p = sym;
104 	struct json_pair ***kp = data;
105 	**kp = p;
106 	++*kp;
107 	return 0;
108 }
109 
110 static void json_formatter(struct json_format *fmt, struct json_value *obj,
111 			   size_t level);
112 
113 static int
keypair_cmp_name(const void * a,const void * b)114 keypair_cmp_name(const void *a, const void *b)
115 {
116 	struct json_pair const * const *kpa = a;
117 	struct json_pair const * const *kpb = b;
118 	return strcmp((*kpa)->k, (*kpb)->k);
119 }
120 
121 static void
json_format_obj(struct json_format * fmt,struct json_value * obj,size_t level)122 json_format_obj(struct json_format *fmt, struct json_value *obj, size_t level)
123 {
124 	size_t count, i;
125 	struct json_pair **keypairs, **kp;
126 
127 	count = grecs_symtab_count(obj->v.o);
128 	keypairs = grecs_calloc(count, sizeof(*keypairs));
129 	kp = keypairs;
130 	grecs_symtab_foreach(obj->v.o, collect_keypairs, &kp);
131 	qsort(keypairs, count, sizeof(*keypairs), keypair_cmp_name);
132 
133 	json_writec(fmt, '{');
134 	if (count) {
135 		if (fmt->indent)
136 			json_writec(fmt, '\n');
137 		for (i = 0; i < count; i++) {
138 			(i ? json_format_delim : json_indent)(fmt, level);
139 			json_format_string(fmt, keypairs[i]->k);
140 			json_writec(fmt, ':');
141 			if (fmt->indent)
142 				json_writec(fmt, ' ');
143 			json_formatter(fmt, keypairs[i]->v, level);
144 		}
145 		if (fmt->indent) {
146 			json_writec(fmt, '\n');
147 			json_indent(fmt, level-1);
148 		}
149 	}
150 	json_writec(fmt, '}');
151 	grecs_free(keypairs);
152 }
153 
154 static void
json_format_array(struct json_format * fmt,struct json_value * obj,size_t level)155 json_format_array(struct json_format *fmt, struct json_value *obj,
156 		  size_t level)
157 {
158 	size_t i;
159 
160 	json_array_flatten(obj);
161 
162 	json_writec(fmt, '[');
163 	if (obj->v.a->oc) {
164 		if (fmt->indent)
165 			json_writec(fmt, '\n');
166 		for (i = 0; i < obj->v.a->oc; i++) {
167 			(i ? json_format_delim : json_indent)(fmt, level);
168 			json_formatter(fmt, obj->v.a->ov[i], level);
169 		}
170 		if (fmt->indent) {
171 			json_writec(fmt, '\n');
172 			json_indent(fmt, level-1);
173 		}
174 	}
175 	json_writec(fmt, ']');
176 }
177 
178 static void
json_formatter(struct json_format * fmt,struct json_value * obj,size_t level)179 json_formatter(struct json_format *fmt, struct json_value *obj, size_t level)
180 {
181 	if (!obj) {
182 		json_writez(fmt, "null");
183 		return;
184 	}
185 
186 	++level;
187 	switch (obj->type) {
188 	case json_null:
189 		json_writez(fmt, "null");
190 		break;
191 
192 	case json_bool:
193 		json_writez(fmt, obj->v.b ? "true" : "false");
194 		break;
195 
196 	case json_number:
197 		json_format_number(fmt, obj->v.n);
198 		break;
199 
200 	case json_string:
201 		json_format_string(fmt, obj->v.s);
202 		break;
203 
204 	case json_arr:
205 		json_format_array(fmt, obj, level);
206 		break;
207 
208 	case json_object:
209 		json_format_obj(fmt, obj, level);
210 		break;
211 	}
212 }
213 
214 void
json_format_value(struct json_value * obj,struct json_format * fmt)215 json_format_value(struct json_value *obj, struct json_format *fmt)
216 {
217 	json_formatter(fmt, obj, 0);
218 }
219 
220 
221