Line data Source code
1 : /*
2 : Author: José Bollo <jobol@nonadev.net>
3 :
4 : https://gitlab.com/jobol/mustach
5 :
6 : SPDX-License-Identifier: ISC
7 : */
8 :
9 : #ifndef _GNU_SOURCE
10 : #define _GNU_SOURCE
11 : #endif
12 :
13 : #include <stdio.h>
14 : #include <string.h>
15 :
16 : #include "mustach.h"
17 : #include "mustach-wrap.h"
18 : #include "mustach-jansson.h"
19 :
20 : struct expl
21 : {
22 : json_t *root;
23 : json_t *selection;
24 : int depth;
25 : struct
26 : {
27 : json_t *cont;
28 : json_t *obj;
29 : void *iter;
30 : int is_objiter;
31 : size_t index, count;
32 : } stack[MUSTACH_MAX_DEPTH];
33 : };
34 :
35 : static int
36 9 : start (void *closure)
37 : {
38 9 : struct expl *e = closure;
39 9 : e->depth = 0;
40 9 : e->selection = json_null ();
41 9 : e->stack[0].cont = NULL;
42 9 : e->stack[0].obj = e->root;
43 9 : e->stack[0].index = 0;
44 9 : e->stack[0].count = 1;
45 9 : return MUSTACH_OK;
46 : }
47 :
48 :
49 : static int
50 0 : compare (void *closure, const char *value)
51 : {
52 0 : struct expl *e = closure;
53 0 : json_t *o = e->selection;
54 : double d;
55 : json_int_t i;
56 :
57 0 : switch (json_typeof (o))
58 : {
59 0 : case JSON_REAL:
60 0 : d = json_number_value (o) - atof (value);
61 0 : return d < 0 ? -1 : d > 0 ? 1 : 0;
62 0 : case JSON_INTEGER:
63 0 : i = (json_int_t) json_integer_value (o) - (json_int_t) atoll (value);
64 0 : return i < 0 ? -1 : i > 0 ? 1 : 0;
65 0 : case JSON_STRING:
66 0 : return strcmp (json_string_value (o), value);
67 0 : case JSON_TRUE:
68 0 : return strcmp ("true", value);
69 0 : case JSON_FALSE:
70 0 : return strcmp ("false", value);
71 0 : case JSON_NULL:
72 0 : return strcmp ("null", value);
73 0 : default:
74 0 : return 1;
75 : }
76 : }
77 :
78 :
79 : static int
80 17 : sel (void *closure, const char *name)
81 : {
82 17 : struct expl *e = closure;
83 : json_t *o;
84 : int i, r;
85 :
86 17 : if (name == NULL)
87 : {
88 2 : o = e->stack[e->depth].obj;
89 2 : r = 1;
90 : }
91 : else
92 : {
93 15 : i = e->depth;
94 18 : while (i >= 0 && ! (o = json_object_get (e->stack[i].obj, name)))
95 3 : i--;
96 15 : if (i >= 0)
97 13 : r = 1;
98 : else
99 : {
100 2 : o = json_null ();
101 2 : r = 0;
102 : }
103 : }
104 17 : e->selection = o;
105 17 : return r;
106 : }
107 :
108 :
109 : static int
110 1 : subsel (void *closure, const char *name)
111 : {
112 1 : struct expl *e = closure;
113 1 : json_t *o = NULL;
114 1 : int r = 0;
115 :
116 1 : if (json_is_object (e->selection))
117 : {
118 1 : o = json_object_get (e->selection, name);
119 1 : r = o != NULL;
120 : }
121 0 : else if (json_is_array (e->selection))
122 : {
123 : char *end;
124 0 : size_t idx = (size_t) strtol (name, &end, 10);
125 0 : if (! *end && idx < json_array_size (e->selection))
126 : {
127 0 : o = json_array_get (e->selection, idx);
128 0 : r = 1;
129 : }
130 : }
131 1 : if (r)
132 1 : e->selection = o;
133 1 : return r;
134 : }
135 :
136 :
137 : static int
138 3 : enter (void *closure, int objiter)
139 : {
140 3 : struct expl *e = closure;
141 : json_t *o;
142 :
143 3 : if (++e->depth >= MUSTACH_MAX_DEPTH)
144 0 : return MUSTACH_ERROR_TOO_DEEP;
145 :
146 3 : o = e->selection;
147 3 : e->stack[e->depth].is_objiter = 0;
148 : /* Squash warning for comparing float to 0.0 */
149 : #pragma GCC diagnostic push
150 : #pragma GCC diagnostic ignored "-Wfloat-equal"
151 3 : if (objiter)
152 : {
153 0 : if (! json_is_object (o))
154 0 : goto not_entering;
155 0 : e->stack[e->depth].iter = json_object_iter (o);
156 0 : if (e->stack[e->depth].iter == NULL)
157 0 : goto not_entering;
158 0 : e->stack[e->depth].obj = json_object_iter_value (e->stack[e->depth].iter);
159 0 : e->stack[e->depth].cont = o;
160 0 : e->stack[e->depth].is_objiter = 1;
161 : }
162 3 : else if (json_is_array (o))
163 : {
164 2 : e->stack[e->depth].count = json_array_size (o);
165 2 : if (e->stack[e->depth].count == 0)
166 1 : goto not_entering;
167 1 : e->stack[e->depth].cont = o;
168 1 : e->stack[e->depth].obj = json_array_get (o, 0);
169 1 : e->stack[e->depth].index = 0;
170 : }
171 1 : else if ((json_is_object (o) && json_object_size (o))
172 0 : || json_is_true (o)
173 0 : || (json_is_string (o) && json_string_length (o) > 0)
174 0 : || (json_is_integer (o) && json_integer_value (o) != 0)
175 0 : || (json_is_real (o) && json_real_value (o) != 0))
176 : {
177 1 : e->stack[e->depth].count = 1;
178 1 : e->stack[e->depth].cont = NULL;
179 1 : e->stack[e->depth].obj = o;
180 1 : e->stack[e->depth].index = 0;
181 : }
182 : else
183 0 : goto not_entering;
184 : #pragma GCC diagnostic pop
185 2 : return 1;
186 :
187 1 : not_entering:
188 1 : e->depth--;
189 1 : return 0;
190 : }
191 :
192 :
193 : static int
194 3 : next (void *closure)
195 : {
196 3 : struct expl *e = closure;
197 :
198 3 : if (e->depth <= 0)
199 0 : return MUSTACH_ERROR_CLOSING;
200 :
201 3 : if (e->stack[e->depth].is_objiter)
202 : {
203 0 : e->stack[e->depth].iter = json_object_iter_next (e->stack[e->depth].cont, e->stack[e->depth].
204 : iter);
205 0 : if (e->stack[e->depth].iter == NULL)
206 0 : return 0;
207 0 : e->stack[e->depth].obj = json_object_iter_value (e->stack[e->depth].iter);
208 0 : return 1;
209 : }
210 :
211 3 : e->stack[e->depth].index++;
212 3 : if (e->stack[e->depth].index >= e->stack[e->depth].count)
213 2 : return 0;
214 :
215 1 : e->stack[e->depth].obj = json_array_get (e->stack[e->depth].cont, e->stack[e->depth].index);
216 1 : return 1;
217 : }
218 :
219 :
220 : static int
221 2 : leave (void *closure)
222 : {
223 2 : struct expl *e = closure;
224 :
225 2 : if (e->depth <= 0)
226 0 : return MUSTACH_ERROR_CLOSING;
227 :
228 2 : e->depth--;
229 2 : return 0;
230 : }
231 :
232 :
233 : static int
234 12 : get (void *closure, struct mustach_sbuf *sbuf, int key)
235 : {
236 12 : struct expl *e = closure;
237 : const char *s;
238 : int d;
239 :
240 12 : if (key)
241 : {
242 0 : s = "";
243 0 : for (d = e->depth ; d >= 0 ; d--)
244 0 : if (e->stack[d].is_objiter)
245 : {
246 0 : s = json_object_iter_key (e->stack[d].iter);
247 0 : break;
248 : }
249 : }
250 12 : else if (json_is_string (e->selection))
251 10 : s = json_string_value (e->selection);
252 2 : else if (json_is_null (e->selection))
253 0 : s = "";
254 : else
255 : {
256 2 : s = json_dumps (e->selection, JSON_ENCODE_ANY | JSON_COMPACT);
257 2 : if (s == NULL)
258 0 : return MUSTACH_ERROR_SYSTEM;
259 2 : sbuf->freecb = free;
260 : }
261 12 : sbuf->value = s;
262 12 : return 1;
263 : }
264 :
265 :
266 : const struct mustach_wrap_itf mustach_jansson_wrap_itf = {
267 : .start = start,
268 : .stop = NULL,
269 : .compare = compare,
270 : .sel = sel,
271 : .subsel = subsel,
272 : .enter = enter,
273 : .next = next,
274 : .leave = leave,
275 : .get = get
276 : };
277 :
278 : int
279 0 : mustach_jansson_file (const char *template, size_t length, json_t *root, int flags, FILE *file)
280 : {
281 : struct expl e;
282 0 : e.root = root;
283 0 : return mustach_wrap_file (template, length, &mustach_jansson_wrap_itf, &e, flags, file);
284 : }
285 :
286 :
287 : int
288 0 : mustach_jansson_fd (const char *template, size_t length, json_t *root, int flags, int fd)
289 : {
290 : struct expl e;
291 0 : e.root = root;
292 0 : return mustach_wrap_fd (template, length, &mustach_jansson_wrap_itf, &e, flags, fd);
293 : }
294 :
295 :
296 : int
297 9 : mustach_jansson_mem (const char *template, size_t length, json_t *root, int flags, char **result,
298 : size_t *size)
299 : {
300 : struct expl e;
301 9 : e.root = root;
302 9 : return mustach_wrap_mem (template, length, &mustach_jansson_wrap_itf, &e, flags, result, size);
303 : }
304 :
305 :
306 : int
307 0 : mustach_jansson_write (const char *template, size_t length, json_t *root, int flags,
308 : mustach_write_cb_t *writecb, void *closure)
309 : {
310 : struct expl e;
311 0 : e.root = root;
312 0 : return mustach_wrap_write (template, length, &mustach_jansson_wrap_itf, &e, flags, writecb,
313 : closure);
314 : }
315 :
316 :
317 : int
318 0 : mustach_jansson_emit (const char *template, size_t length, json_t *root, int flags,
319 : mustach_emit_cb_t *emitcb, void *closure)
320 : {
321 : struct expl e;
322 0 : e.root = root;
323 0 : return mustach_wrap_emit (template, length, &mustach_jansson_wrap_itf, &e, flags, emitcb, closure)
324 : ;
325 : }
|