8 struct sprinter vtable;
10 /* Top of the state stack, or NULL if the printer is not currently
11 * inside any aggregate types. */
12 struct json_state *state;
14 /* A flag to signify that a separator should be inserted in the
15 * output as soon as possible.
17 bool insert_separator;
21 struct json_state *parent;
22 /* True if nothing has been printed in this aggregate yet.
23 * Suppresses the comma before a value. */
25 /* The character that closes the current aggregate. */
29 /* Helper function to set up the stream to print a value. If this
30 * value follows another value, prints a comma. */
31 static struct sprinter_json *
32 json_begin_value (struct sprinter *sp)
34 struct sprinter_json *spj = (struct sprinter_json *) sp;
37 if (! spj->state->first) {
38 fputc (',', spj->stream);
39 if (spj->insert_separator) {
40 fputc ('\n', spj->stream);
41 spj->insert_separator = false;
43 fputc (' ', spj->stream);
46 spj->state->first = false;
52 /* Helper function to begin an aggregate type. Prints the open
53 * character and pushes a new state frame. */
55 json_begin_aggregate (struct sprinter *sp, char open, char close)
57 struct sprinter_json *spj = json_begin_value (sp);
58 struct json_state *state = talloc (spj, struct json_state);
60 fputc (open, spj->stream);
61 state->parent = spj->state;
68 json_begin_map (struct sprinter *sp)
70 json_begin_aggregate (sp, '{', '}');
74 json_begin_list (struct sprinter *sp)
76 json_begin_aggregate (sp, '[', ']');
80 json_end (struct sprinter *sp)
82 struct sprinter_json *spj = (struct sprinter_json *) sp;
83 struct json_state *state = spj->state;
85 fputc (spj->state->close, spj->stream);
86 spj->state = state->parent;
88 if (spj->state == NULL)
89 fputc ('\n', spj->stream);
92 /* This implementation supports embedded NULs as allowed by the JSON
93 * specification and Unicode. Support for *parsing* embedded NULs
94 * varies, but is generally not a problem outside of C-based parsers
95 * (Python's json module and Emacs' json.el take embedded NULs in
98 json_string_len (struct sprinter *sp, const char *val, size_t len)
100 static const char *const escapes[] = {
101 ['\"'] = "\\\"", ['\\'] = "\\\\", ['\b'] = "\\b",
102 ['\f'] = "\\f", ['\n'] = "\\n", ['\t'] = "\\t"
104 struct sprinter_json *spj = json_begin_value (sp);
106 fputc ('"', spj->stream);
107 for (; len; ++val, --len) {
108 unsigned char ch = *val;
109 if (ch < ARRAY_SIZE (escapes) && escapes[ch])
110 fputs (escapes[ch], spj->stream);
112 fputc (ch, spj->stream);
114 fprintf (spj->stream, "\\u%04x", ch);
116 fputc ('"', spj->stream);
120 json_string (struct sprinter *sp, const char *val)
124 json_string_len (sp, val, strlen (val));
128 json_integer (struct sprinter *sp, int64_t val)
130 struct sprinter_json *spj = json_begin_value (sp);
132 fprintf (spj->stream, "%" PRId64, val);
136 json_boolean (struct sprinter *sp, bool val)
138 struct sprinter_json *spj = json_begin_value (sp);
140 fputs (val ? "true" : "false", spj->stream);
144 json_null (struct sprinter *sp)
146 struct sprinter_json *spj = json_begin_value (sp);
148 fputs ("null", spj->stream);
152 json_map_key (struct sprinter *sp, const char *key)
154 struct sprinter_json *spj = (struct sprinter_json *) sp;
156 json_string (sp, key);
157 fputs (": ", spj->stream);
158 spj->state->first = true;
162 json_set_prefix (unused (struct sprinter *sp), unused (const char *name))
167 json_separator (struct sprinter *sp)
169 struct sprinter_json *spj = (struct sprinter_json *) sp;
171 spj->insert_separator = true;
175 sprinter_json_create (notmuch_database_t *db, FILE *stream)
177 static const struct sprinter_json template = {
179 .begin_map = json_begin_map,
180 .begin_list = json_begin_list,
182 .string = json_string,
183 .string_len = json_string_len,
184 .integer = json_integer,
185 .boolean = json_boolean,
187 .map_key = json_map_key,
188 .separator = json_separator,
189 .set_prefix = json_set_prefix,
190 .is_text_printer = false,
193 struct sprinter_json *res;
195 res = talloc (db, struct sprinter_json);
200 res->vtable.notmuch = db;
201 res->stream = stream;