mustach-json-c.c (6948B)
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-json-c.h" 19 20 struct expl { 21 struct json_object *root; 22 struct json_object *selection; 23 int depth; 24 struct { 25 struct json_object *cont; 26 struct json_object *obj; 27 struct json_object_iterator iter; 28 struct json_object_iterator enditer; 29 int is_objiter; 30 int index, count; 31 } stack[MUSTACH_MAX_DEPTH]; 32 }; 33 34 static int start(void *closure) 35 { 36 struct expl *e = closure; 37 e->depth = 0; 38 e->selection = NULL; 39 e->stack[0].cont = NULL; 40 e->stack[0].obj = e->root; 41 e->stack[0].index = 0; 42 e->stack[0].count = 1; 43 return MUSTACH_OK; 44 } 45 46 static int compare(void *closure, const char *value) 47 { 48 struct expl *e = closure; 49 struct json_object *o = e->selection; 50 double d; 51 int64_t i; 52 53 switch (json_object_get_type(o)) { 54 case json_type_double: 55 d = json_object_get_double(o) - atof(value); 56 return d < 0 ? -1 : d > 0 ? 1 : 0; 57 case json_type_int: 58 i = json_object_get_int64(o) - (int64_t)atoll(value); 59 return i < 0 ? -1 : i > 0 ? 1 : 0; 60 default: 61 return strcmp(json_object_get_string(o), value); 62 } 63 } 64 65 static int sel(void *closure, const char *name) 66 { 67 struct expl *e = closure; 68 struct json_object *o; 69 int i, r; 70 71 if (name == NULL) { 72 o = e->stack[e->depth].obj; 73 r = 1; 74 } else { 75 i = e->depth; 76 while (i >= 0 && !json_object_object_get_ex(e->stack[i].obj, name, &o)) 77 i--; 78 if (i >= 0) 79 r = 1; 80 else { 81 o = NULL; 82 r = 0; 83 } 84 } 85 e->selection = o; 86 return r; 87 } 88 89 static int subsel(void *closure, const char *name) 90 { 91 struct expl *e = closure; 92 struct json_object *o = NULL; 93 int r = 0; 94 95 if (json_object_is_type(e->selection, json_type_object)) 96 r = json_object_object_get_ex(e->selection, name, &o); 97 else if (json_object_is_type(e->selection, json_type_array)) { 98 char *end; 99 size_t idx = (size_t)strtol(name, &end, 10); 100 if (!*end && idx < json_object_array_length(e->selection)) { 101 o = json_object_array_get_idx(e->selection, idx); 102 r = 1; 103 } 104 } 105 if (r) 106 e->selection = o; 107 return r; 108 } 109 110 static int enter(void *closure, int objiter) 111 { 112 struct expl *e = closure; 113 struct json_object *o; 114 115 if (++e->depth >= MUSTACH_MAX_DEPTH) 116 return MUSTACH_ERROR_TOO_DEEP; 117 118 o = e->selection; 119 e->stack[e->depth].is_objiter = 0; 120 if (objiter) { 121 if (!json_object_is_type(o, json_type_object)) 122 goto not_entering; 123 124 e->stack[e->depth].iter = json_object_iter_begin(o); 125 e->stack[e->depth].enditer = json_object_iter_end(o); 126 if (json_object_iter_equal(&e->stack[e->depth].iter, &e->stack[e->depth].enditer)) 127 goto not_entering; 128 e->stack[e->depth].obj = json_object_iter_peek_value(&e->stack[e->depth].iter); 129 e->stack[e->depth].cont = o; 130 e->stack[e->depth].is_objiter = 1; 131 } else if (json_object_is_type(o, json_type_array)) { 132 e->stack[e->depth].count = json_object_array_length(o); 133 if (e->stack[e->depth].count == 0) 134 goto not_entering; 135 e->stack[e->depth].cont = o; 136 e->stack[e->depth].obj = json_object_array_get_idx(o, 0); 137 e->stack[e->depth].index = 0; 138 } else if ((json_object_is_type(o, json_type_object) && json_object_object_length(o) > 0) 139 || json_object_get_boolean(o)) { 140 e->stack[e->depth].count = 1; 141 e->stack[e->depth].cont = NULL; 142 e->stack[e->depth].obj = o; 143 e->stack[e->depth].index = 0; 144 } else 145 goto not_entering; 146 return 1; 147 148 not_entering: 149 e->depth--; 150 return 0; 151 } 152 153 static int next(void *closure) 154 { 155 struct expl *e = closure; 156 157 if (e->depth <= 0) 158 return MUSTACH_ERROR_CLOSING; 159 160 if (e->stack[e->depth].is_objiter) { 161 json_object_iter_next(&e->stack[e->depth].iter); 162 if (json_object_iter_equal(&e->stack[e->depth].iter, &e->stack[e->depth].enditer)) 163 return 0; 164 e->stack[e->depth].obj = json_object_iter_peek_value(&e->stack[e->depth].iter); 165 return 1; 166 } 167 168 e->stack[e->depth].index++; 169 if (e->stack[e->depth].index >= e->stack[e->depth].count) 170 return 0; 171 172 e->stack[e->depth].obj = json_object_array_get_idx(e->stack[e->depth].cont, e->stack[e->depth].index); 173 return 1; 174 } 175 176 static int leave(void *closure) 177 { 178 struct expl *e = closure; 179 180 if (e->depth <= 0) 181 return MUSTACH_ERROR_CLOSING; 182 183 e->depth--; 184 return 0; 185 } 186 187 static int get(void *closure, struct mustach_sbuf *sbuf, int key) 188 { 189 struct expl *e = closure; 190 const char *s; 191 int d; 192 193 if (key) { 194 s = ""; 195 for (d = e->depth ; d >= 0 ; d--) 196 if (e->stack[d].is_objiter) { 197 s = json_object_iter_peek_name(&e->stack[d].iter); 198 break; 199 } 200 } 201 else 202 switch (json_object_get_type(e->selection)) { 203 case json_type_string: 204 s = json_object_get_string(e->selection); 205 break; 206 case json_type_null: 207 s = ""; 208 break; 209 default: 210 s = json_object_to_json_string_ext(e->selection, 0); 211 break; 212 } 213 sbuf->value = s; 214 return 1; 215 } 216 217 const struct mustach_wrap_itf mustach_json_c_wrap_itf = { 218 .start = start, 219 .stop = NULL, 220 .compare = compare, 221 .sel = sel, 222 .subsel = subsel, 223 .enter = enter, 224 .next = next, 225 .leave = leave, 226 .get = get 227 }; 228 229 int mustach_json_c_file(const char *template, size_t length, struct json_object *root, int flags, FILE *file) 230 { 231 struct expl e; 232 e.root = root; 233 return mustach_wrap_file(template, length, &mustach_json_c_wrap_itf, &e, flags, file); 234 } 235 236 int mustach_json_c_fd(const char *template, size_t length, struct json_object *root, int flags, int fd) 237 { 238 struct expl e; 239 e.root = root; 240 return mustach_wrap_fd(template, length, &mustach_json_c_wrap_itf, &e, flags, fd); 241 } 242 243 int mustach_json_c_mem(const char *template, size_t length, struct json_object *root, int flags, char **result, size_t *size) 244 { 245 struct expl e; 246 e.root = root; 247 return mustach_wrap_mem(template, length, &mustach_json_c_wrap_itf, &e, flags, result, size); 248 } 249 250 int mustach_json_c_write(const char *template, size_t length, struct json_object *root, int flags, mustach_write_cb_t *writecb, void *closure) 251 { 252 struct expl e; 253 e.root = root; 254 return mustach_wrap_write(template, length, &mustach_json_c_wrap_itf, &e, flags, writecb, closure); 255 } 256 257 int mustach_json_c_emit(const char *template, size_t length, struct json_object *root, int flags, mustach_emit_cb_t *emitcb, void *closure) 258 { 259 struct expl e; 260 e.root = root; 261 return mustach_wrap_emit(template, length, &mustach_json_c_wrap_itf, &e, flags, emitcb, closure); 262 } 263 264 int fmustach_json_c(const char *template, struct json_object *root, FILE *file) 265 { 266 return mustach_json_c_file(template, 0, root, -1, file); 267 } 268 269 int fdmustach_json_c(const char *template, struct json_object *root, int fd) 270 { 271 return mustach_json_c_fd(template, 0, root, -1, fd); 272 } 273 274 int mustach_json_c(const char *template, struct json_object *root, char **result, size_t *size) 275 { 276 return mustach_json_c_mem(template, 0, root, -1, result, size); 277 } 278 279 int umustach_json_c(const char *template, struct json_object *root, mustach_write_cb_t *writecb, void *closure) 280 { 281 return mustach_json_c_write(template, 0, root, -1, writecb, closure); 282 } 283 284