mustach-cjson.c (5534B)
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 #include <stdlib.h> 16 17 #include "mustach.h" 18 #include "mustach-wrap.h" 19 #include "mustach-cjson.h" 20 21 struct expl { 22 cJSON null; 23 cJSON *root; 24 cJSON *selection; 25 int depth; 26 struct { 27 cJSON *cont; 28 cJSON *obj; 29 cJSON *next; 30 int is_objiter; 31 } stack[MUSTACH_MAX_DEPTH]; 32 }; 33 34 static int start(void *closure) 35 { 36 struct expl *e = closure; 37 e->depth = 0; 38 memset(&e->null, 0, sizeof e->null); 39 e->null.type = cJSON_NULL; 40 e->selection = &e->null; 41 e->stack[0].cont = NULL; 42 e->stack[0].obj = e->root; 43 return MUSTACH_OK; 44 } 45 46 static int compare(void *closure, const char *value) 47 { 48 struct expl *e = closure; 49 cJSON *o = e->selection; 50 double d; 51 52 if (cJSON_IsNumber(o)) { 53 d = o->valuedouble - atof(value); 54 return d < 0 ? -1 : d > 0 ? 1 : 0; 55 } else if (cJSON_IsString(o)) { 56 return strcmp(o->valuestring, value); 57 } else if (cJSON_IsTrue(o)) { 58 return strcmp("true", value); 59 } else if (cJSON_IsFalse(o)) { 60 return strcmp("false", value); 61 } else if (cJSON_IsNull(o)) { 62 return strcmp("null", value); 63 } else { 64 return 1; 65 } 66 } 67 68 static int sel(void *closure, const char *name) 69 { 70 struct expl *e = closure; 71 cJSON *o; 72 int i, r; 73 74 if (name == NULL) { 75 o = e->stack[e->depth].obj; 76 r = 1; 77 } else { 78 i = e->depth; 79 while (i >= 0 && !(o = cJSON_GetObjectItemCaseSensitive(e->stack[i].obj, name))) 80 i--; 81 if (i >= 0) 82 r = 1; 83 else { 84 o = &e->null; 85 r = 0; 86 } 87 } 88 e->selection = o; 89 return r; 90 } 91 92 static int subsel(void *closure, const char *name) 93 { 94 struct expl *e = closure; 95 cJSON *o = NULL; 96 int r = 0; 97 98 if (cJSON_IsObject(e->selection)) { 99 o = cJSON_GetObjectItemCaseSensitive(e->selection, name); 100 r = o != NULL; 101 } 102 else if (cJSON_IsArray(e->selection) && *name) { 103 char *end; 104 int idx = (int)strtol(name, &end, 10); 105 if (!*end && idx >= 0 && idx < cJSON_GetArraySize(e->selection)) { 106 o = cJSON_GetArrayItem(e->selection, idx); 107 r = 1; 108 } 109 } 110 if (r) 111 e->selection = o; 112 return r; 113 } 114 115 static int enter(void *closure, int objiter) 116 { 117 struct expl *e = closure; 118 cJSON *o; 119 120 if (++e->depth >= MUSTACH_MAX_DEPTH) 121 return MUSTACH_ERROR_TOO_DEEP; 122 123 o = e->selection; 124 e->stack[e->depth].is_objiter = 0; 125 if (objiter) { 126 if (! cJSON_IsObject(o)) 127 goto not_entering; 128 if (o->child == NULL) 129 goto not_entering; 130 e->stack[e->depth].obj = o->child; 131 e->stack[e->depth].next = o->child->next; 132 e->stack[e->depth].cont = o; 133 e->stack[e->depth].is_objiter = 1; 134 } else if (cJSON_IsArray(o)) { 135 if (o->child == NULL) 136 goto not_entering; 137 e->stack[e->depth].obj = o->child; 138 e->stack[e->depth].next = o->child->next; 139 e->stack[e->depth].cont = o; 140 } else if ((cJSON_IsObject(o) && o->child != NULL) 141 || cJSON_IsTrue(o) 142 || (cJSON_IsString(o) && cJSON_GetStringValue(o)[0] != '\0') 143 || (cJSON_IsNumber(o) && cJSON_GetNumberValue(o) != 0)) { 144 e->stack[e->depth].obj = o; 145 e->stack[e->depth].cont = NULL; 146 e->stack[e->depth].next = NULL; 147 } else 148 goto not_entering; 149 return 1; 150 151 not_entering: 152 e->depth--; 153 return 0; 154 } 155 156 static int next(void *closure) 157 { 158 struct expl *e = closure; 159 cJSON *o; 160 161 if (e->depth <= 0) 162 return MUSTACH_ERROR_CLOSING; 163 164 o = e->stack[e->depth].next; 165 if (o == NULL) 166 return 0; 167 168 e->stack[e->depth].obj = o; 169 e->stack[e->depth].next = o->next; 170 return 1; 171 } 172 173 static int leave(void *closure) 174 { 175 struct expl *e = closure; 176 177 if (e->depth <= 0) 178 return MUSTACH_ERROR_CLOSING; 179 180 e->depth--; 181 return 0; 182 } 183 184 static int get(void *closure, struct mustach_sbuf *sbuf, int key) 185 { 186 struct expl *e = closure; 187 const char *s; 188 int d; 189 190 if (key) { 191 s = ""; 192 for (d = e->depth ; d >= 0 ; d--) 193 if (e->stack[d].is_objiter) { 194 s = e->stack[d].obj->string; 195 break; 196 } 197 } 198 else if (cJSON_IsString(e->selection)) 199 s = e->selection->valuestring; 200 else if (cJSON_IsNull(e->selection)) 201 s = ""; 202 else { 203 s = cJSON_PrintUnformatted(e->selection); 204 if (s == NULL) 205 return MUSTACH_ERROR_SYSTEM; 206 sbuf->freecb = cJSON_free; 207 } 208 sbuf->value = s; 209 return 1; 210 } 211 212 const struct mustach_wrap_itf mustach_cJSON_wrap_itf = { 213 .start = start, 214 .stop = NULL, 215 .compare = compare, 216 .sel = sel, 217 .subsel = subsel, 218 .enter = enter, 219 .next = next, 220 .leave = leave, 221 .get = get 222 }; 223 224 int mustach_cJSON_file(const char *template, size_t length, cJSON *root, int flags, FILE *file) 225 { 226 struct expl e; 227 e.root = root; 228 return mustach_wrap_file(template, length, &mustach_cJSON_wrap_itf, &e, flags, file); 229 } 230 231 int mustach_cJSON_fd(const char *template, size_t length, cJSON *root, int flags, int fd) 232 { 233 struct expl e; 234 e.root = root; 235 return mustach_wrap_fd(template, length, &mustach_cJSON_wrap_itf, &e, flags, fd); 236 } 237 238 int mustach_cJSON_mem(const char *template, size_t length, cJSON *root, int flags, char **result, size_t *size) 239 { 240 struct expl e; 241 e.root = root; 242 return mustach_wrap_mem(template, length, &mustach_cJSON_wrap_itf, &e, flags, result, size); 243 } 244 245 int mustach_cJSON_write(const char *template, size_t length, cJSON *root, int flags, mustach_write_cb_t *writecb, void *closure) 246 { 247 struct expl e; 248 e.root = root; 249 return mustach_wrap_write(template, length, &mustach_cJSON_wrap_itf, &e, flags, writecb, closure); 250 } 251 252 int mustach_cJSON_emit(const char *template, size_t length, cJSON *root, int flags, mustach_emit_cb_t *emitcb, void *closure) 253 { 254 struct expl e; 255 e.root = root; 256 return mustach_wrap_emit(template, length, &mustach_cJSON_wrap_itf, &e, flags, emitcb, closure); 257 } 258