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