#include #include #include #include "json.h" #include "sortedmap.h" #include "arraylist.h" Json * parse_null(FILE *stream) { Json * json; if (getc(stream) == 'u' && getc(stream) == 'l' && getc(stream) == 'l') { json = malloc(sizeof(Json)); json->type = NIL; return json; } return NULL; } Json * parse_true(FILE *stream) { Json * json; if (getc(stream) == 'r' && getc(stream) == 'u' && getc(stream) == 'e') { json = malloc(sizeof(Json)); json->type = BOOLEAN; json->value.boolean = 1; return json; } return NULL; } Json * parse_false(FILE *stream) { Json * json; if (getc(stream) == 'a' && getc(stream) == 'l' && getc(stream) == 's' && getc(stream) == 'e') { json = malloc(sizeof(Json)); json->type = BOOLEAN; json->value.boolean = 0; return json; } return NULL; } /* TODO: scientific notation */ Json * parse_number(FILE *stream, int sign) { Json * json; long num = 0, den = 0; char c; while (1) { c = getc(stream); switch(c) { case '0': num = num * 10; den *= 10; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': num = num * 10 + (c - '1' + 1); den *= 10; break; case '.': den = 1; break; default: if (c != EOF) ungetc(c, stream); if (den == 0) den = 1; json = malloc(sizeof(Json)); json->type = NUMBER; json->value.number = sign * num * 1.0 / den; return json; } } } /* TODO: more escaped characters, unicode? */ Json * parse_string(FILE *stream) { int i = 0, cap = 10; char * buffer = calloc(cap, sizeof(char)); char c; int escaped = 0; Json * json; while ((c = getc(stream)) != EOF) { switch (c) { case '\\': escaped = 1; break; case '"': if (!escaped) { json = malloc(sizeof(Json)); json->type = STRING; json->value.string = calloc(i + 1, sizeof(char)); memcpy(json->value.string, buffer, i); free(buffer); return json; } default: if (i == cap) { cap *= 2; buffer = realloc(buffer, cap * sizeof(char)); } buffer[i++] = c; } } free(buffer); return NULL; } Json * parse_list(FILE *stream) { char c; Json * json; ArrayList * values = list(); int expect_comma = 0; while ((c = getc(stream)) != EOF) { switch (c) { case ']': json = malloc(sizeof(Json)); json->type = LIST; json->value.list = values; return json; case ' ': case '\n': case '\t': break; case ',': if (expect_comma) { expect_comma = 0; break; } default: ungetc(c, stream); json = json_parse(stream); add_list(values, (void *) json); expect_comma = 1; } } fold_list(values, NULL, free_listitem); free_list(values); return NULL; } enum map_state { MKEY, MCOLON, MVALUE, MCOMMA }; Json * parse_map(FILE *stream) { char c; Json * json = NULL; char * key = NULL; SortedMap * values = map(); enum map_state s = MKEY; while ((c = getc(stream)) != EOF) { switch (s) { case MKEY: switch (c) { case ' ': case '\n': case '\t': break; case '}': json = malloc(sizeof(Json)); json->type = MAP; json->value.map = values; return json; case '"': json = parse_string(stream); key = json->value.string; free(json); json = NULL; s = MCOLON; } break; case MCOLON: switch (c) { case ' ': case '\n': case '\t': break; case ':': s = MVALUE; } break; case MVALUE: switch (c) { case ' ': case '\n': case '\t': break; default: ungetc(c, stream); json = json_parse(stream); values = put_map(values, key, (void *) json); json = NULL; s = MCOMMA; } break; case MCOMMA: switch (c) { case ' ': case '\n': case '\t': break; case ',': s = MKEY; break; case '}': json = malloc(sizeof(Json)); json->type = MAP; json->value.map = values; return json; } break; } } fold_map(values, NULL, free_mappair); free_map(values); return NULL; } Json * json_parse(FILE *stream) { char c; while ((c = getc(stream)) != EOF) { switch (c) { case '{': return parse_map(stream); case '[': return parse_list(stream); case '"': return parse_string(stream); case 't': return parse_true(stream); case 'f': return parse_false(stream); case 'n': return parse_null(stream); case '-': return parse_number(stream, -1); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ungetc(c, stream); return parse_number(stream, 1); case ' ': case '\n': case '\t': break; /* whitespace */ default: fprintf(stderr, "encountered char: '%c'", c); } } return NULL; } void print_string(FILE *stream, char *string) { fprintf(stream, "\"%s\"", string); } struct printacc { FILE *stream; int index; }; void * json_print_map(void * voidacc, char *key, void *value) { struct printacc *acc = (struct printacc *) voidacc; if (acc->index++ > 0) { fprintf(acc->stream, ", "); } print_string(acc->stream, key); fprintf(acc->stream, ": "); json_print((Json *) value, acc->stream); return acc; } void json_print(Json *this, FILE *stream) { int i; struct printacc acc = { NULL, 0 }; switch (this->type) { case NIL: fprintf(stream, "null"); break; case BOOLEAN: fprintf(stream, this->value.boolean == 0 ? "false" : "true"); break; case STRING: print_string(stream, this->value.string); break; case NUMBER: fprintf(stream, "%f", this->value.number); break; case LIST: fprintf(stream, "["); if (this->value.list->size > 0) { json_print((Json *) get_list(this->value.list, 0), stream); for(i = 1; i < this->value.list->size; i++) { fprintf(stream, ", "); json_print((Json *) get_list(this->value.list, i), stream); } } fprintf(stream, "]"); break; case MAP: fprintf(stream, "{"); acc.stream = stream; fold_map(this->value.map, (void *) &acc, json_print_map); fprintf(stream, "}"); break; } } void * json_freelist(void *acc, int index, void *item) { json_free((Json *) item); return NULL; } void * json_freemap(void *acc, char *key, void *value) { free(key); json_free((Json *) value); return NULL; } void json_free(Json *this) { switch (this->type) { case NIL: case BOOLEAN: case NUMBER: break; case STRING: free(this->value.string); break; case LIST: fold_list(this->value.list, NULL, json_freelist); free_list(this->value.list); break; case MAP: fold_map(this->value.map, NULL, json_freemap); free_map(this->value.map); break; } free(this); }