#include "json.h" #include #include #include static const char *p; static int bad; static void ws(void){ while(*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') p++; } static void *xcalloc(size_t n, size_t s){ void *r = calloc(n, s); if(!r){ fprintf(stderr, "out of memory\n"); exit(2); } return r; } static char *parse_str(void){ const char *s = ++p; char *out, *o; while(*p && *p != '"'){ if(*p == '\\' && p[1]) p++; p++; } if(*p != '"'){ bad = 1; return NULL; } out = o = xcalloc((size_t)(p - s) + 1, 1); for(; s < p; s++){ if(*s == '\\') s++; *o++ = *s; } p++; return out; } static jval *parse_val(void); static void add(jval *v, jval *item){ v->items = realloc(v->items, sizeof(jval *) * (size_t)(v->n + 1)); if(!v->items){ fprintf(stderr, "out of memory\n"); exit(2); } v->items[v->n++] = item; } static jval *parse_val(void){ jval *v = xcalloc(1, sizeof *v); ws(); if(*p == '{'){ v->type = J_OBJ; p++; ws(); if(*p == '}'){ p++; return v; } for(;;){ char *k; jval *item; ws(); if(*p != '"'){ bad = 1; return v; } k = parse_str(); ws(); if(*p != ':'){ bad = 1; free(k); return v; } p++; item = parse_val(); item->key = k; add(v, item); ws(); if(*p == ','){ p++; continue; } if(*p == '}'){ p++; return v; } bad = 1; return v; } } if(*p == '['){ v->type = J_ARR; p++; ws(); if(*p == ']'){ p++; return v; } for(;;){ add(v, parse_val()); ws(); if(*p == ','){ p++; continue; } if(*p == ']'){ p++; return v; } bad = 1; return v; } } if(*p == '"'){ v->type = J_STR; v->str = parse_str(); return v; } if(!strncmp(p, "true", 4)){ v->type = J_BOOL; v->num = 1; p += 4; return v; } if(!strncmp(p, "false", 5)){ v->type = J_BOOL; v->num = 0; p += 5; return v; } if(!strncmp(p, "null", 4)){ v->type = J_NULL; p += 4; return v; } if(*p == '-' || (*p >= '0' && *p <= '9')){ char *end; v->type = J_NUM; v->num = strtoll(p, &end, 10); if(*end == '.' || *end == 'e' || *end == 'E') bad = 1; /* the vectors are integer-only */ p = end; return v; } bad = 1; return v; } jval *json_parse_file(const char *path){ FILE *f = fopen(path, "rb"); long n; char *buf; jval *v; if(!f) return NULL; fseek(f, 0, SEEK_END); n = ftell(f); fseek(f, 0, SEEK_SET); buf = xcalloc((size_t)n + 1, 1); if(fread(buf, 1, (size_t)n, f) != (size_t)n){ fclose(f); free(buf); return NULL; } fclose(f); p = buf; bad = 0; v = parse_val(); ws(); if(*p) bad = 1; free(buf); if(bad){ json_free(v); return NULL; } return v; } jval *json_get(const jval *o, const char *key){ int i; if(!o || o->type != J_OBJ) return NULL; for(i = 0; i < o->n; i++) if(!strcmp(o->items[i]->key, key)) return o->items[i]; return NULL; } jval *json_at(const jval *a, int i){ return (a && (a->type == J_ARR || a->type == J_OBJ) && i >= 0 && i < a->n) ? a->items[i] : NULL; } void json_free(jval *v){ int i; if(!v) return; for(i = 0; i < v->n; i++) json_free(v->items[i]); free(v->items); free(v->str); free(v->key); free(v); }