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>
32 * exploration state when instanciating mustache
35 struct json_object *root;
38 struct json_object *cont;
39 struct json_object *obj;
45 * Scan a key=val text.
46 * If the sign = is found, drop it and returns a pointer to the value.
47 * If the sign = is not here, returns NULL.
48 * Replace any \= of the key by its unescaped version =.
50 static char *keyval(char *read, int isptr)
55 while (c && c != '=') {
57 if (c == '~' && read[1] == '=') {
63 case '\\': *write++ = c;
64 case '=': c = *++read;
73 return c == '=' ? ++read : NULL;
77 * Returns the unescaped version of the first component
78 * and update 'name' to point the next components if any.
80 static char *first(char **name, int isptr)
82 char *r, *read, *write, c;
90 while (c && c != '/') {
102 while (c && c != '.') {
103 if (c == '\\' && (read[1] == '.' || read[1] == '\\'))
116 * Returns the unescaped version of the first value
117 * and update 'val' to point the next value if any.
119 static char *value(char **val)
121 char *r, *read, *write, c;
128 while (c && c != '|') {
129 if (c == '\\' && (read[1] == '|' || read[1] == '\\'))
141 * Replace the last occurence of ':' followed by
142 * any character not being '*' by ':*', the
143 * globalisation of the key.
144 * Returns NULL if no globalisation is done
145 * or else the key globalized.
147 static char *globalize(char *key)
152 for (r = key; *r ; r++) {
153 if (r[0] == ':' && r[1] && r[1] != '*')
165 * find the object of 'name'
167 static struct json_object *find(struct expl *e, const char *name)
170 struct json_object *o, *r;
173 /* get a local key */
176 /* is it a JSON pointer? */
180 /* extract its value */
181 v = keyval(n, isptr);
183 /* search the first component for each valid globalisation */
185 c = first(&n, isptr);
188 /* next globalisation */
192 else if (json_object_object_get_ex(e->stack[i].obj, c, &o)) {
194 /* found the root, search the subcomponents */
195 c = first(&n, isptr);
197 while (!json_object_object_get_ex(o, c, &r)) {
203 c = first(&n, isptr);
206 /* check the value if requested */
212 } while (c && strcmp(c, json_object_get_string(o)));
223 static int start(void *closure)
225 struct expl *e = closure;
227 e->stack[0].cont = NULL;
228 e->stack[0].obj = e->root;
229 e->stack[0].index = 0;
230 e->stack[0].count = 1;
234 static void print(FILE *file, const char *string, int escape)
241 case '%': fputs("%%", file); break;
242 case '\n': fputs("\\n\\\n", file); break;
243 default: putc(*string, file); break;
248 static int put(void *closure, const char *name, int escape, FILE *file)
250 struct expl *e = closure;
251 struct json_object *o = find(e, name);
253 print(file, json_object_get_string(o), escape);
257 static int enter(void *closure, const char *name)
259 struct expl *e = closure;
260 struct json_object *o = find(e, name);
261 if (++e->depth >= MAX_DEPTH)
262 return MUSTACH_ERROR_TOO_DEPTH;
263 if (json_object_is_type(o, json_type_array)) {
264 e->stack[e->depth].count = json_object_array_length(o);
265 if (e->stack[e->depth].count == 0) {
269 e->stack[e->depth].cont = o;
270 e->stack[e->depth].obj = json_object_array_get_idx(o, 0);
271 e->stack[e->depth].index = 0;
272 } else if (json_object_is_type(o, json_type_object) || json_object_get_boolean(o)) {
273 e->stack[e->depth].count = 1;
274 e->stack[e->depth].cont = NULL;
275 e->stack[e->depth].obj = o;
276 e->stack[e->depth].index = 0;
284 static int next(void *closure)
286 struct expl *e = closure;
288 return MUSTACH_ERROR_CLOSING;
289 e->stack[e->depth].index++;
290 if (e->stack[e->depth].index >= e->stack[e->depth].count)
292 e->stack[e->depth].obj = json_object_array_get_idx(e->stack[e->depth].cont, e->stack[e->depth].index);
296 static int leave(void *closure)
298 struct expl *e = closure;
300 return MUSTACH_ERROR_CLOSING;
305 static struct mustach_itf itf = {
314 * Apply the object 'root' to the mustache 'template'.
315 * In case of success, the function returns 0, the pointer
316 * 'result' receives the allocated instanciation and
317 * the pointer 'size' its size. Note that the real size
318 * is one byte more to effectively store the terminating
320 * In case of error, it returns a negative error code.
322 int apply_mustach(const char *template, struct json_object *root, char **result, size_t *size)
326 return mustach(template, &itf, &e, result, size);