2 Author: José Bollo <jobol@nonadev.net>
3 Author: José Bollo <jose.bollo@iot.bzh>
5 https://gitlab.com/jobol/mustach
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
25 #include <json-c/json.h>
33 struct json_object *root;
36 struct json_object *cont;
37 struct json_object *obj;
43 * Scan a key=val text.
44 * If the sign = is found, drop it and returns a pointer to the value.
45 * If the sign = is not here, returns NULL.
46 * Replace any \= of the key by its unescaped version =.
48 static char *keyval(char *read, int isptr)
53 while (c && c != '=') {
55 if (c == '~' && read[1] == '=') {
61 case '\\': *write++ = c;
62 case '=': c = *++read;
71 return c == '=' ? ++read : NULL;
75 * Returns the unescaped version of the first component
76 * and update 'name' to point the next components if any.
78 static char *first(char **name, int isptr)
80 char *r, *read, *write, c;
88 while (c && c != '/') {
100 while (c && c != '.') {
101 if (c == '\\' && (read[1] == '.' || read[1] == '\\'))
114 * Replace the last occurence of ':' followed by
115 * any character not being '*' by ':*', the
116 * globalisation of the key.
117 * Returns NULL if no globalisation is done
118 * or else the key globalized.
120 static char *globalize(char *key)
125 for (r = key; *r ; r++) {
126 if (r[0] == ':' && r[1] && r[1] != '*')
138 * find the object of 'name'
140 static struct json_object *find(struct expl *e, const char *name)
143 struct json_object *o, *r;
146 /* get a local key */
149 /* is it a JSON pointer? */
153 /* extract its value */
154 v = keyval(n, isptr);
156 /* search the first component for each valid globalisation */
158 c = first(&n, isptr);
161 /* next globalisation */
165 else if (json_object_object_get_ex(e->stack[i].obj, c, &o)) {
167 /* found the root, search the subcomponents */
168 c = first(&n, isptr);
170 while (!json_object_object_get_ex(o, c, &r)) {
176 c = first(&n, isptr);
179 /* check the value if requested */
182 if (i == !strcmp(&v[i], json_object_get_string(o)))
192 static int start(void *closure)
194 struct expl *e = closure;
196 e->stack[0].cont = NULL;
197 e->stack[0].obj = e->root;
198 e->stack[0].index = 0;
199 e->stack[0].count = 1;
203 static void print(FILE *file, const char *string, int escape)
210 case '%': fputs("%%", file); break;
211 case '\n': fputs("\\n\\\n", file); break;
212 default: putc(*string, file); break;
217 static int put(void *closure, const char *name, int escape, FILE *file)
219 struct expl *e = closure;
220 struct json_object *o = find(e, name);
222 print(file, json_object_get_string(o), escape);
226 static int enter(void *closure, const char *name)
228 struct expl *e = closure;
229 struct json_object *o = find(e, name);
230 if (++e->depth >= MAX_DEPTH)
231 return MUSTACH_ERROR_TOO_DEPTH;
232 if (json_object_is_type(o, json_type_array)) {
233 e->stack[e->depth].count = json_object_array_length(o);
234 if (e->stack[e->depth].count == 0) {
238 e->stack[e->depth].cont = o;
239 e->stack[e->depth].obj = json_object_array_get_idx(o, 0);
240 e->stack[e->depth].index = 0;
241 } else if (json_object_is_type(o, json_type_object) || json_object_get_boolean(o)) {
242 e->stack[e->depth].count = 1;
243 e->stack[e->depth].cont = NULL;
244 e->stack[e->depth].obj = o;
245 e->stack[e->depth].index = 0;
253 static int next(void *closure)
255 struct expl *e = closure;
257 return MUSTACH_ERROR_CLOSING;
258 e->stack[e->depth].index++;
259 if (e->stack[e->depth].index >= e->stack[e->depth].count)
261 e->stack[e->depth].obj = json_object_array_get_idx(e->stack[e->depth].cont, e->stack[e->depth].index);
265 static int leave(void *closure)
267 struct expl *e = closure;
269 return MUSTACH_ERROR_CLOSING;
274 static struct mustach_itf itf = {
283 * Apply the object 'root' to the mustache 'template'.
284 * In case of success, the function returns 0, the pointer
285 * 'result' receives the allocated instanciation and
286 * the pointer 'size' its size. Note that the real size
287 * is one byte more to effectively store the terminating
289 * In case of error, it returns a negative error code.
291 int apply_mustach(const char *template, struct json_object *root, char **result, size_t *size)
295 return mustach(template, &itf, &e, result, size);