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 : json_t *root;
22 : json_t *selection;
23 : int depth;
24 : struct {
25 : json_t *cont;
26 : json_t *obj;
27 : void *iter;
28 : int is_objiter;
29 : size_t index, count;
30 : } stack[MUSTACH_MAX_DEPTH];
31 : };
32 :
33 6 : static int start(void *closure)
34 : {
35 6 : struct expl *e = closure;
36 6 : e->depth = 0;
37 6 : e->selection = json_null();
38 6 : e->stack[0].cont = NULL;
39 6 : e->stack[0].obj = e->root;
40 6 : e->stack[0].index = 0;
41 6 : e->stack[0].count = 1;
42 6 : return MUSTACH_OK;
43 : }
44 :
45 0 : static int compare(void *closure, const char *value)
46 : {
47 0 : struct expl *e = closure;
48 0 : json_t *o = e->selection;
49 : double d;
50 : json_int_t i;
51 :
52 0 : switch (json_typeof(o)) {
53 0 : case JSON_REAL:
54 0 : d = json_number_value(o) - atof(value);
55 0 : return d < 0 ? -1 : d > 0 ? 1 : 0;
56 0 : case JSON_INTEGER:
57 0 : i = (json_int_t)json_integer_value(o) - (json_int_t)atoll(value);
58 0 : return i < 0 ? -1 : i > 0 ? 1 : 0;
59 0 : case JSON_STRING:
60 0 : return strcmp(json_string_value(o), value);
61 0 : case JSON_TRUE:
62 0 : return strcmp("true", value);
63 0 : case JSON_FALSE:
64 0 : return strcmp("false", value);
65 0 : case JSON_NULL:
66 0 : return strcmp("null", value);
67 0 : default:
68 0 : return 1;
69 : }
70 : }
71 :
72 10 : static int sel(void *closure, const char *name)
73 : {
74 10 : struct expl *e = closure;
75 : json_t *o;
76 : int i, r;
77 :
78 10 : if (name == NULL) {
79 2 : o = e->stack[e->depth].obj;
80 2 : r = 1;
81 : } else {
82 8 : i = e->depth;
83 10 : while (i >= 0 && !(o = json_object_get(e->stack[i].obj, name)))
84 2 : i--;
85 8 : if (i >= 0)
86 7 : r = 1;
87 : else {
88 1 : o = json_null();
89 1 : r = 0;
90 : }
91 : }
92 10 : e->selection = o;
93 10 : return r;
94 : }
95 :
96 1 : static int subsel(void *closure, const char *name)
97 : {
98 1 : struct expl *e = closure;
99 1 : json_t *o = NULL;
100 1 : int r = 0;
101 :
102 1 : if (json_is_object(e->selection)) {
103 1 : o = json_object_get(e->selection, name);
104 1 : r = o != NULL;
105 : }
106 0 : else if (json_is_array(e->selection)) {
107 : char *end;
108 0 : size_t idx = (size_t)strtol(name, &end, 10);
109 0 : if (!*end && idx < json_array_size(e->selection)) {
110 0 : o = json_array_get(e->selection, idx);
111 0 : r = 1;
112 : }
113 : }
114 1 : if (r)
115 1 : e->selection = o;
116 1 : return r;
117 : }
118 :
119 3 : static int enter(void *closure, int objiter)
120 : {
121 3 : struct expl *e = closure;
122 : json_t *o;
123 :
124 3 : if (++e->depth >= MUSTACH_MAX_DEPTH)
125 0 : return MUSTACH_ERROR_TOO_DEEP;
126 :
127 3 : o = e->selection;
128 3 : e->stack[e->depth].is_objiter = 0;
129 3 : if (objiter) {
130 0 : if (!json_is_object(o))
131 0 : goto not_entering;
132 0 : e->stack[e->depth].iter = json_object_iter(o);
133 0 : if (e->stack[e->depth].iter == NULL)
134 0 : goto not_entering;
135 0 : e->stack[e->depth].obj = json_object_iter_value(e->stack[e->depth].iter);
136 0 : e->stack[e->depth].cont = o;
137 0 : e->stack[e->depth].is_objiter = 1;
138 3 : } else if (json_is_array(o)) {
139 2 : e->stack[e->depth].count = json_array_size(o);
140 2 : if (e->stack[e->depth].count == 0)
141 1 : goto not_entering;
142 1 : e->stack[e->depth].cont = o;
143 1 : e->stack[e->depth].obj = json_array_get(o, 0);
144 1 : e->stack[e->depth].index = 0;
145 1 : } else if ((json_is_object(o) && json_object_size(o))
146 0 : || json_is_true(o)
147 0 : || (json_is_string(o) && json_string_length(o) > 0)
148 0 : || (json_is_integer(o) && json_integer_value(o) != 0)
149 0 : || (json_is_real(o) && json_real_value(o) != 0)) {
150 1 : e->stack[e->depth].count = 1;
151 1 : e->stack[e->depth].cont = NULL;
152 1 : e->stack[e->depth].obj = o;
153 1 : e->stack[e->depth].index = 0;
154 : } else
155 0 : goto not_entering;
156 2 : return 1;
157 :
158 1 : not_entering:
159 1 : e->depth--;
160 1 : return 0;
161 : }
162 :
163 3 : static int next(void *closure)
164 : {
165 3 : struct expl *e = closure;
166 :
167 3 : if (e->depth <= 0)
168 0 : return MUSTACH_ERROR_CLOSING;
169 :
170 3 : if (e->stack[e->depth].is_objiter) {
171 0 : e->stack[e->depth].iter = json_object_iter_next(e->stack[e->depth].cont, e->stack[e->depth].iter);
172 0 : if (e->stack[e->depth].iter == NULL)
173 0 : return 0;
174 0 : e->stack[e->depth].obj = json_object_iter_value(e->stack[e->depth].iter);
175 0 : return 1;
176 : }
177 :
178 3 : e->stack[e->depth].index++;
179 3 : if (e->stack[e->depth].index >= e->stack[e->depth].count)
180 2 : return 0;
181 :
182 1 : e->stack[e->depth].obj = json_array_get(e->stack[e->depth].cont, e->stack[e->depth].index);
183 1 : return 1;
184 : }
185 :
186 2 : static int leave(void *closure)
187 : {
188 2 : struct expl *e = closure;
189 :
190 2 : if (e->depth <= 0)
191 0 : return MUSTACH_ERROR_CLOSING;
192 :
193 2 : e->depth--;
194 2 : return 0;
195 : }
196 :
197 6 : static int get(void *closure, struct mustach_sbuf *sbuf, int key)
198 : {
199 6 : struct expl *e = closure;
200 : const char *s;
201 : int d;
202 :
203 6 : if (key) {
204 0 : s = "";
205 0 : for (d = e->depth ; d >= 0 ; d--)
206 0 : if (e->stack[d].is_objiter) {
207 0 : s = json_object_iter_key(e->stack[d].iter);
208 0 : break;
209 : }
210 : }
211 6 : else if (json_is_string(e->selection))
212 6 : s = json_string_value(e->selection);
213 0 : else if (json_is_null(e->selection))
214 0 : s = "";
215 : else {
216 0 : s = json_dumps(e->selection, JSON_ENCODE_ANY | JSON_COMPACT);
217 0 : if (s == NULL)
218 0 : return MUSTACH_ERROR_SYSTEM;
219 0 : sbuf->freecb = free;
220 : }
221 6 : sbuf->value = s;
222 6 : return 1;
223 : }
224 :
225 : const struct mustach_wrap_itf mustach_jansson_wrap_itf = {
226 : .start = start,
227 : .stop = NULL,
228 : .compare = compare,
229 : .sel = sel,
230 : .subsel = subsel,
231 : .enter = enter,
232 : .next = next,
233 : .leave = leave,
234 : .get = get
235 : };
236 :
237 0 : int mustach_jansson_file(const char *template, size_t length, json_t *root, int flags, FILE *file)
238 : {
239 : struct expl e;
240 0 : e.root = root;
241 0 : return mustach_wrap_file(template, length, &mustach_jansson_wrap_itf, &e, flags, file);
242 : }
243 :
244 0 : int mustach_jansson_fd(const char *template, size_t length, json_t *root, int flags, int fd)
245 : {
246 : struct expl e;
247 0 : e.root = root;
248 0 : return mustach_wrap_fd(template, length, &mustach_jansson_wrap_itf, &e, flags, fd);
249 : }
250 :
251 6 : int mustach_jansson_mem(const char *template, size_t length, json_t *root, int flags, char **result, size_t *size)
252 : {
253 : struct expl e;
254 6 : e.root = root;
255 6 : return mustach_wrap_mem(template, length, &mustach_jansson_wrap_itf, &e, flags, result, size);
256 : }
257 :
258 0 : int mustach_jansson_write(const char *template, size_t length, json_t *root, int flags, mustach_write_cb_t *writecb, void *closure)
259 : {
260 : struct expl e;
261 0 : e.root = root;
262 0 : return mustach_wrap_write(template, length, &mustach_jansson_wrap_itf, &e, flags, writecb, closure);
263 : }
264 :
265 0 : int mustach_jansson_emit(const char *template, size_t length, json_t *root, int flags, mustach_emit_cb_t *emitcb, void *closure)
266 : {
267 : struct expl e;
268 0 : e.root = root;
269 0 : return mustach_wrap_emit(template, length, &mustach_jansson_wrap_itf, &e, flags, emitcb, closure);
270 : }
271 :
|