7 #if defined(_MSC_VER) || defined(__WATCOMC__)
10 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
18 #define strncasecmp strnicmp
21 struct json_obj *json_alloc_obj(void)
25 if(!(obj = malloc(sizeof *obj))) {
26 fprintf(stderr, "json_alloc_obj: failed to allocate object\n");
33 void json_free_obj(struct json_obj *obj)
35 json_destroy_obj(obj);
39 void json_init_obj(struct json_obj *obj)
41 memset(obj, 0, sizeof *obj);
44 void json_destroy_obj(struct json_obj *obj)
48 for(i=0; i<obj->num_items; i++) {
49 json_destroy_item(obj->items + i);
54 struct json_arr *json_alloc_arr(void)
58 if(!(arr = malloc(sizeof *arr))) {
59 fprintf(stderr, "json_alloc_arr: failed to allocate array\n");
66 void json_free_arr(struct json_arr *arr)
68 json_destroy_arr(arr);
72 void json_init_arr(struct json_arr *arr)
74 memset(arr, 0, sizeof *arr);
77 void json_destroy_arr(struct json_arr *arr)
81 for(i=0; i<arr->size; i++) {
82 json_destroy_value(arr->val + i);
88 int json_item(struct json_item *item, const char *name)
90 memset(item, 0, sizeof *item);
92 if(!(item->name = strdup(name))) {
93 fprintf(stderr, "json_item: failed to allocate name\n");
99 void json_destroy_item(struct json_item *item)
102 json_destroy_value(&item->val);
105 int json_value_str(struct json_value *jv, const char *str)
110 if(str && !(jv->str = strdup(str))) {
111 fprintf(stderr, "json_value_str: failed to duplicate string\n");
117 void json_value_num(struct json_value *jv, double num)
123 void json_value_bool(struct json_value *jv, int bval)
125 jv->type = JSON_BOOL;
129 void json_value_obj(struct json_value *jv, struct json_obj *obj)
135 json_init_obj(&jv->obj);
139 void json_value_arr(struct json_value *jv, struct json_arr *arr)
145 json_init_arr(&jv->arr);
149 void json_destroy_value(struct json_value *jv)
157 json_destroy_obj(&jv->obj);
161 json_destroy_arr(&jv->arr);
169 int json_obj_append(struct json_obj *obj, const struct json_item *item)
171 if(obj->num_items >= obj->max_items) {
172 int newsz = obj->max_items ? (obj->max_items << 1) : 8;
173 void *tmp = realloc(obj->items, newsz * sizeof *obj->items);
175 fprintf(stderr, "json_obj_append: failed to grow items array (%d)\n", newsz);
179 obj->max_items = newsz;
182 obj->items[obj->num_items++] = *item;
186 int json_arr_append(struct json_arr *arr, const struct json_value *val)
188 if(arr->size >= arr->maxsize) {
189 int newsz = arr->maxsize ? (arr->maxsize << 1) : 8;
190 void *tmp = realloc(arr->val, newsz * sizeof *arr->val);
192 fprintf(stderr, "json_arr_append: failed to grow array (%d)\n", newsz);
196 arr->maxsize = newsz;
199 arr->val[arr->size++] = *val;
203 struct json_item *json_find_item(const struct json_obj *obj, const char *name)
206 for(i=0; i<obj->num_items; i++) {
207 if(strcmp(obj->items[i].name, name) == 0) {
208 return obj->items + i;
214 /* lookup functions */
216 struct json_value *json_lookup(struct json_obj *obj, const char *path)
221 struct json_item *it = 0;
223 pelem = alloca(strlen(path) + 1);
226 while(*endp && *endp != '.') endp++;
227 if(!(len = endp - path)) break;
229 memcpy(pelem, path, len);
232 /* continue after the . or point at the terminator */
234 if(*path == '.') path++;
236 if(!(it = json_find_item(obj, pelem))) {
240 if(it->val.type != JSON_OBJ) {
241 /* we hit a leaf. If the path continues we failed */
245 /* item is an object, we can continue the lookup if necessary */
249 return it ? &it->val : 0;
252 const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def)
254 struct json_value *val;
256 if(!(val = json_lookup(obj, path)) || val->type != JSON_STR) {
262 double json_lookup_num(struct json_obj *obj, const char *path, double def)
264 struct json_value *val;
266 if(!(val = json_lookup(obj, path)) || val->type != JSON_NUM) {
272 int json_lookup_bool(struct json_obj *obj, const char *path, int def)
274 struct json_value *val;
276 if(!(val = json_lookup(obj, path)) || val->type != JSON_BOOL) {
282 struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def)
284 struct json_value *val;
286 if(!(val = json_lookup(obj, path)) || val->type != JSON_OBJ) {
292 struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def)
294 struct json_value *val;
296 if(!(val = json_lookup(obj, path)) || val->type != JSON_ARR) {
303 /* ---- parser ---- */
305 #define MAX_TOKEN_SIZE 512
312 enum { TOKEN_NUM, TOKEN_STR, TOKEN_BOOL }; /* plus all the single-char tokens */
315 static int item(struct parser *p, struct json_item *it);
316 static int array(struct parser *p, struct json_arr *arr);
317 static int object(struct parser *p, struct json_obj *obj);
320 static int next_char(struct parser *p)
323 p->nextc = *p->text++;
324 if(!isspace(p->nextc)) break;
329 #define SET_TOKEN(token, str, len) \
331 DYNARR_RESIZE(token, (len) + 1); \
332 memcpy(token, str, len); \
336 static int next_token(struct parser *p)
341 if(!p->nextc) return -1;
350 SET_TOKEN(p->token, &p->nextc, 1);
355 DYNARR_CLEAR(p->token);
357 while(p->nextc && p->nextc != '"') {
358 DYNARR_STRPUSH(p->token, p->nextc);
373 SET_TOKEN(p->token, s, len);
379 if(strncasecmp(s, "true", 4) == 0) {
380 SET_TOKEN(p->token, "true", 4);
385 if(strncasecmp(s, "false", 5) == 0) {
386 SET_TOKEN(p->token, "false", 5);
392 SET_TOKEN(p->token, &p->nextc, 1);
393 fprintf(stderr, "json_parse: unexpected character: %c\n", p->nextc);
397 static int expect(struct parser *p, int tok)
399 return next_token(p) == tok ? 1 : 0;
402 static const char *toktypestr(int tok)
404 static char buf[] = "' '";
406 case TOKEN_NUM: return "number";
407 case TOKEN_STR: return "string";
408 case TOKEN_BOOL: return "boolean";
416 #define EXPECT(p, x) \
418 if(!expect(p, x)) { \
419 fprintf(stderr, "json_parse: expected: %s, found: %s\n", toktypestr(x), (p)->token); \
424 static int value(struct parser *p, struct json_value *val)
430 toktype = next_token(p);
433 if(json_value_str(val, p->token) == -1) {
439 json_value_num(val, atof(p->token));
443 json_value_bool(val, *p->token == 't' ? 1 : 0);
446 case '{': /* object */
447 if(object(p, &obj) == -1) {
450 json_value_obj(val, &obj);
453 case '[': /* array */
454 if(array(p, &arr) == -1) {
457 json_value_arr(val, &arr);
461 fprintf(stderr, "json_parse: unexpected token %s while parsing item\n", p->text);
467 static int item(struct parser *p, struct json_item *it)
469 EXPECT(p, TOKEN_STR);
470 if(json_item(it, p->token) == -1) {
474 if(value(p, &it->val) == -1) {
481 static int array(struct parser *p, struct json_arr *arr)
483 struct json_value val;
487 while(p->nextc != -1 && p->nextc != ']') {
488 if(value(p, &val) == -1) {
489 fprintf(stderr, "json_parse: expected value in array\n");
490 json_destroy_arr(arr);
494 if(json_arr_append(arr, &val) == -1) {
495 json_destroy_value(&val);
496 json_destroy_arr(arr);
500 if(p->nextc == ',') expect(p, ','); /* eat up comma separator */
506 static int object(struct parser *p, struct json_obj *obj)
512 while(p->nextc != -1 && p->nextc != '}') {
513 if(item(p, &it) == -1) {
514 fprintf(stderr, "json_parse: expected item in object\n");
515 json_destroy_obj(obj);
519 if(json_obj_append(obj, &it) == -1) {
520 json_destroy_item(&it);
521 json_destroy_obj(obj);
525 if(p->nextc == ',') expect(p, ','); /* eat up comma separator */
531 int json_parse(struct json_obj *root, const char *text)
535 if(!text || !*text) return -1;
538 p.text = (char*)(text + 1);
539 if(!(p.token = dynarr_alloc(0, 1))) {
540 fprintf(stderr, "json_parse: failed to allocate token dynamic array\n");
545 if(object(&p, root) == -1) {
546 dynarr_free(p.token);
549 dynarr_free(p.token);
554 static void putind(FILE *fp, int ind)
557 for(i=0; i<ind; i++) {
562 void json_print(FILE *fp, struct json_obj *root)
564 json_print_obj(fp, root, 0);
568 void json_print_obj(FILE *fp, struct json_obj *obj, int ind)
574 for(i=0; i<obj->num_items; i++) {
576 json_print_item(fp, obj->items + i, ind + 1);
577 if(i < obj->num_items - 1) {
588 void json_print_arr(FILE *fp, struct json_arr *arr, int ind)
594 for(i=0; i<arr->size; i++) {
596 json_print_value(fp, arr->val + i, ind + 1);
597 if(i < arr->size - 1) {
608 void json_print_item(FILE *fp, struct json_item *item, int ind)
610 fprintf(fp, "\"%s\": ", item->name);
611 json_print_value(fp, &item->val, ind);
614 void json_print_value(FILE *fp, struct json_value *val, int ind)
618 fprintf(fp, "\"%s\"", val->str);
621 fprintf(fp, "%g", val->num);
624 fprintf(fp, "%s", val->boolean ? "true" : "false");
627 json_print_obj(fp, &val->obj, ind);
630 json_print_arr(fp, &val->arr, ind);
633 fputs("<UNKNOWN>", fp);