aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/json.c
blob: 8abeea724bcb8fdf9537468c4bfe40d42ff57641 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "json.h"
#include "common.h"

struct JsonBuilder {
    StrBuilder buf;
    BOOL has_output_element[256];
    int depth;
};

JsonBuilder* jsonbuilder_new() {
    JsonBuilder* b = calloc(1, sizeof(JsonBuilder));
    strbuilder_init(&b->buf);
    return b;
}

const char* jsonbuilder_get_output(JsonBuilder* b) {
    return b->buf.buf;
}

static void emit_comma_if_needed(JsonBuilder* b) {
    if (b->has_output_element[b->depth - 1]) {
        strbuilder_append_char(&b->buf, ',');
    }
}

void jsonbuilder_object_start(JsonBuilder* b) {
    strbuilder_append_char(&b->buf, '{');
    b->has_output_element[b->depth++] = FALSE;
}

void jsonbuilder_object_end(JsonBuilder* b) {
    b->depth--;
    strbuilder_append_char(&b->buf, '}');
}

void jsonbuilder_object_member_start(JsonBuilder* b, const char* key) {
    emit_comma_if_needed(b);
    jsonbuilder_string(b, key);
    strbuilder_append_char(&b->buf, ':');
}

void jsonbuilder_object_member_end(JsonBuilder* b) {
    b->has_output_element[b->depth - 1] = TRUE;
}

void jsonbuilder_array_start(JsonBuilder* b) {
    strbuilder_append_char(&b->buf, '[');
    b->has_output_element[b->depth++] = FALSE;
}

void jsonbuilder_array_end(JsonBuilder* b) {
    b->depth--;
    strbuilder_append_char(&b->buf, ']');
}

void jsonbuilder_array_element_start(JsonBuilder* b) {
    emit_comma_if_needed(b);
}

void jsonbuilder_array_element_end(JsonBuilder* b) {
    b->has_output_element[b->depth - 1] = TRUE;
}

void jsonbuilder_null(JsonBuilder* b) {
    strbuilder_append_string(&b->buf, "null");
}

void jsonbuilder_boolean(JsonBuilder* b, BOOL value) {
    strbuilder_append_string(&b->buf, value ? "true" : "false");
}

void jsonbuilder_integer(JsonBuilder* b, int value) {
    char buf[32];
    sprintf(buf, "%d", value);
    strbuilder_append_string(&b->buf, buf);
}

void jsonbuilder_string(JsonBuilder* b, const char* value) {
    if (!value) {
        jsonbuilder_null(b);
        return;
    }

    strbuilder_append_char(&b->buf, '"');

    for (const char* p = value; *p; p++) {
        if (*p == '"') {
            strbuilder_append_string(&b->buf, "\\\"");
        } else if (*p == '\\') {
            strbuilder_append_string(&b->buf, "\\\\");
        } else if (*p == '\b') {
            strbuilder_append_string(&b->buf, "\\b");
        } else if (*p == '\f') {
            strbuilder_append_string(&b->buf, "\\f");
        } else if (*p == '\n') {
            strbuilder_append_string(&b->buf, "\\n");
        } else if (*p == '\r') {
            strbuilder_append_string(&b->buf, "\\r");
        } else if (*p == '\t') {
            strbuilder_append_string(&b->buf, "\\t");
        } else {
            strbuilder_append_char(&b->buf, *p);
        }
    }

    strbuilder_append_char(&b->buf, '"');
}