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