7 struct sprinter vtable;
9 /* Top of the state stack, or NULL if the printer is not currently
10 * inside any aggregate types. */
11 struct json_state *state;
13 /* A flag to signify that a separator should be inserted in the
14 * output as soon as possible.
16 notmuch_bool_t insert_separator;
20 struct json_state *parent;
21 /* True if nothing has been printed in this aggregate yet.
22 * Suppresses the comma before a value. */
24 /* The character that closes the current aggregate. */
28 /* Helper function to set up the stream to print a value. If this
29 * value follows another value, prints a comma. */
30 static struct sprinter_json *
31 json_begin_value (struct sprinter *sp)
33 struct sprinter_json *spj = (struct sprinter_json *) sp;
36 if (! spj->state->first) {
37 fputc (',', spj->stream);
38 if (spj->insert_separator) {
39 fputc ('\n', spj->stream);
40 spj->insert_separator = FALSE;
42 fputc (' ', spj->stream);
45 spj->state->first = FALSE;
51 /* Helper function to begin an aggregate type. Prints the open
52 * character and pushes a new state frame. */
54 json_begin_aggregate (struct sprinter *sp, char open, char close)
56 struct sprinter_json *spj = json_begin_value (sp);
57 struct json_state *state = talloc (spj, struct json_state);
59 fputc (open, spj->stream);
60 state->parent = spj->state;
67 json_begin_map (struct sprinter *sp)
69 json_begin_aggregate (sp, '{', '}');
73 json_begin_list (struct sprinter *sp)
75 json_begin_aggregate (sp, '[', ']');
79 json_end (struct sprinter *sp)
81 struct sprinter_json *spj = (struct sprinter_json *) sp;
82 struct json_state *state = spj->state;
84 fputc (spj->state->close, spj->stream);
85 spj->state = state->parent;
87 if (spj->state == NULL)
88 fputc ('\n', spj->stream);
92 json_string (struct sprinter *sp, const char *val)
94 static const char *const escapes[] = {
95 ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",
96 ['\f'] = "\\f", ['\n'] = "\\n", ['\t'] = "\\t"
98 struct sprinter_json *spj = json_begin_value (sp);
100 fputc ('"', spj->stream);
101 for (; *val; ++val) {
102 unsigned char ch = *val;
103 if (ch < ARRAY_SIZE (escapes) && escapes[ch])
104 fputs (escapes[ch], spj->stream);
106 fputc (ch, spj->stream);
108 fprintf (spj->stream, "\\u%04x", ch);
110 fputc ('"', spj->stream);
114 json_integer (struct sprinter *sp, int val)
116 struct sprinter_json *spj = json_begin_value (sp);
118 fprintf (spj->stream, "%d", val);
122 json_boolean (struct sprinter *sp, notmuch_bool_t val)
124 struct sprinter_json *spj = json_begin_value (sp);
126 fputs (val ? "true" : "false", spj->stream);
130 json_null (struct sprinter *sp)
132 struct sprinter_json *spj = json_begin_value (sp);
134 fputs ("null", spj->stream);
138 json_map_key (struct sprinter *sp, const char *key)
140 struct sprinter_json *spj = (struct sprinter_json *) sp;
142 json_string (sp, key);
143 fputs (": ", spj->stream);
144 spj->state->first = TRUE;
148 json_set_prefix (unused (struct sprinter *sp), unused (const char *name))
153 json_separator (struct sprinter *sp)
155 struct sprinter_json *spj = (struct sprinter_json *) sp;
157 spj->insert_separator = TRUE;
161 sprinter_json_create (const void *ctx, FILE *stream)
163 static const struct sprinter_json template = {
165 .begin_map = json_begin_map,
166 .begin_list = json_begin_list,
168 .string = json_string,
169 .integer = json_integer,
170 .boolean = json_boolean,
172 .map_key = json_map_key,
173 .separator = json_separator,
174 .set_prefix = json_set_prefix,
175 .is_text_printer = FALSE,
178 struct sprinter_json *res;
180 res = talloc (ctx, struct sprinter_json);
185 res->stream = stream;