tippecanoe/json.c

143 lines
2.9 KiB
C
Raw Normal View History

2014-02-05 23:16:23 +00:00
#include <stdio.h>
#include <stdlib.h>
2014-02-05 23:33:43 +00:00
#include <ctype.h>
2014-02-05 23:16:23 +00:00
typedef enum json_type {
2014-02-05 23:33:43 +00:00
JSON_STRING, JSON_NUMBER, JSON_ARRAY, JSON_HASH, JSON_NULL, JSON_TRUE, JSON_FALSE,
2014-02-05 23:16:23 +00:00
} json_type;
typedef struct json_array {
struct json_object *object;
struct json_array *next;
} json_array;
typedef struct json_hash {
struct json_object *key;
struct json_object *value;
struct json_hash *next;
} json_hash;
typedef struct json_object {
json_type type;
struct json_object *parent;
char *string;
double number;
json_array *array;
2014-02-06 00:10:22 +00:00
json_hash *hash;
2014-02-05 23:16:23 +00:00
} json_object;
2014-02-05 23:33:43 +00:00
2014-02-06 00:10:22 +00:00
static json_object *add_object(json_type type, json_object *parent) {
2014-02-05 23:33:43 +00:00
json_object *o = malloc(sizeof(struct json_object));
o->type = type;
o->parent = parent;
2014-02-06 00:10:22 +00:00
o->array = NULL;
o->hash = NULL;
if (parent != NULL) {
if (parent->type == JSON_ARRAY) {
json_array *a = malloc(sizeof(json_array));
a->next = parent->array;
a->object = o;
parent->array = a;
}
if (parent->type == JSON_HASH) {
if (parent->hash != NULL && parent->hash->value == NULL) {
parent->hash->value = o;
} else {
json_hash *h = malloc(sizeof(json_hash));
h->next = parent->hash;
h->key = o;
parent->hash = h;
}
}
}
2014-02-05 23:33:43 +00:00
return o;
}
static void json_error(char *s) {
fprintf(stderr, "%s\n", s);
exit(EXIT_FAILURE);
}
json_object *parse(FILE *f, json_object *current) {
int c = getc(f);
if (c == EOF) {
return NULL;
}
2014-02-05 23:42:15 +00:00
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
2014-02-05 23:33:43 +00:00
c = getc(f);
if (c == EOF) {
return NULL;
}
}
if (c == '[') {
2014-02-06 00:10:22 +00:00
return parse(f, add_object(JSON_ARRAY, current));
2014-02-05 23:33:43 +00:00
} else if (c == ']') {
if (current->parent == NULL || current->parent->type != JSON_ARRAY) {
json_error("] without [");
}
return current->parent;
}
if (c == '{') {
2014-02-06 00:10:22 +00:00
return parse(f, add_object(JSON_HASH, current));
2014-02-05 23:33:43 +00:00
} else if (c == '}') {
if (current->parent == NULL || current->parent->type != JSON_HASH) {
json_error("} without {");
}
return current->parent;
}
2014-02-05 23:42:15 +00:00
if (c == 'n') {
if (getc(f) != 'u' || getc(f) != 'l' || getc(f) != 'l') {
json_error("misspelled null");
}
2014-02-06 00:10:22 +00:00
return add_object(JSON_NULL, current);
2014-02-05 23:42:15 +00:00
}
if (c == 't') {
if (getc(f) != 'r' || getc(f) != 'u' || getc(f) != 'e') {
json_error("misspelled true");
}
2014-02-06 00:10:22 +00:00
return add_object(JSON_TRUE, current);
2014-02-05 23:42:15 +00:00
}
if (c == 'f') {
if (getc(f) != 'a' || getc(f) != 'l' || getc(f) != 's' || getc(f) != 'e') {
json_error("misspelled false");
}
2014-02-06 00:10:22 +00:00
return add_object(JSON_FALSE, current);
2014-02-05 23:42:15 +00:00
}
2014-02-06 00:00:01 +00:00
if (c == ',') {
if (current->parent == NULL ||
(current->parent->type != JSON_ARRAY ||
current->parent->type != JSON_HASH)) {
json_error(", not in array or hash");
}
return parse(f, current);
}
if (c == ':') {
if (current->parent == NULL || current->parent->type != JSON_HASH) {
json_error(": not in hash");
}
2014-02-06 00:10:22 +00:00
if (current->parent->hash == NULL || current->parent->hash->value != NULL) {
json_error(": without key");
}
2014-02-06 00:00:01 +00:00
return parse(f, current);
}
2014-02-05 23:33:43 +00:00
}