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