The fifth batch
[alt-git.git] / json-writer.c
blob8c5187e9fdda81455531c6ad42f7f2d4d8b81a9b
1 #define DISABLE_SIGN_COMPARE_WARNINGS
3 #include "git-compat-util.h"
4 #include "json-writer.h"
6 void jw_init(struct json_writer *jw)
8 struct json_writer blank = JSON_WRITER_INIT;
9 memcpy(jw, &blank, sizeof(*jw));;
12 void jw_release(struct json_writer *jw)
14 strbuf_release(&jw->json);
15 strbuf_release(&jw->open_stack);
19 * Append JSON-quoted version of the given string to 'out'.
21 static void append_quoted_string(struct strbuf *out, const char *in)
23 unsigned char c;
25 strbuf_addch(out, '"');
26 while ((c = *in++) != '\0') {
27 if (c == '"')
28 strbuf_addstr(out, "\\\"");
29 else if (c == '\\')
30 strbuf_addstr(out, "\\\\");
31 else if (c == '\n')
32 strbuf_addstr(out, "\\n");
33 else if (c == '\r')
34 strbuf_addstr(out, "\\r");
35 else if (c == '\t')
36 strbuf_addstr(out, "\\t");
37 else if (c == '\f')
38 strbuf_addstr(out, "\\f");
39 else if (c == '\b')
40 strbuf_addstr(out, "\\b");
41 else if (c < 0x20)
42 strbuf_addf(out, "\\u%04x", c);
43 else
44 strbuf_addch(out, c);
46 strbuf_addch(out, '"');
49 static void indent_pretty(struct json_writer *jw)
51 strbuf_addstrings(&jw->json, " ", jw->open_stack.len);
55 * Begin an object or array (either top-level or nested within the currently
56 * open object or array).
58 static void begin(struct json_writer *jw, char ch_open, int pretty)
60 jw->pretty = pretty;
62 strbuf_addch(&jw->json, ch_open);
64 strbuf_addch(&jw->open_stack, ch_open);
65 jw->need_comma = 0;
69 * Assert that the top of the open-stack is an object.
71 static void assert_in_object(const struct json_writer *jw, const char *key)
73 if (!jw->open_stack.len)
74 BUG("json-writer: object: missing jw_object_begin(): '%s'", key);
75 if (jw->open_stack.buf[jw->open_stack.len - 1] != '{')
76 BUG("json-writer: object: not in object: '%s'", key);
80 * Assert that the top of the open-stack is an array.
82 static void assert_in_array(const struct json_writer *jw)
84 if (!jw->open_stack.len)
85 BUG("json-writer: array: missing jw_array_begin()");
86 if (jw->open_stack.buf[jw->open_stack.len - 1] != '[')
87 BUG("json-writer: array: not in array");
91 * Add comma if we have already seen a member at this level.
93 static void maybe_add_comma(struct json_writer *jw)
95 if (jw->need_comma)
96 strbuf_addch(&jw->json, ',');
97 else
98 jw->need_comma = 1;
101 static void fmt_double(struct json_writer *jw, int precision,
102 double value)
104 if (precision < 0) {
105 strbuf_addf(&jw->json, "%f", value);
106 } else {
107 struct strbuf fmt = STRBUF_INIT;
108 strbuf_addf(&fmt, "%%.%df", precision);
109 strbuf_addf(&jw->json, fmt.buf, value);
110 strbuf_release(&fmt);
114 static void object_common(struct json_writer *jw, const char *key)
116 assert_in_object(jw, key);
117 maybe_add_comma(jw);
119 if (jw->pretty) {
120 strbuf_addch(&jw->json, '\n');
121 indent_pretty(jw);
124 append_quoted_string(&jw->json, key);
125 strbuf_addch(&jw->json, ':');
126 if (jw->pretty)
127 strbuf_addch(&jw->json, ' ');
130 static void array_common(struct json_writer *jw)
132 assert_in_array(jw);
133 maybe_add_comma(jw);
135 if (jw->pretty) {
136 strbuf_addch(&jw->json, '\n');
137 indent_pretty(jw);
142 * Assert that the given JSON object or JSON array has been properly
143 * terminated. (Has closing bracket.)
145 static void assert_is_terminated(const struct json_writer *jw)
147 if (jw->open_stack.len)
148 BUG("json-writer: object: missing jw_end(): '%s'",
149 jw->json.buf);
152 void jw_object_begin(struct json_writer *jw, int pretty)
154 begin(jw, '{', pretty);
157 void jw_object_string(struct json_writer *jw, const char *key, const char *value)
159 object_common(jw, key);
160 append_quoted_string(&jw->json, value);
163 void jw_object_intmax(struct json_writer *jw, const char *key, intmax_t value)
165 object_common(jw, key);
166 strbuf_addf(&jw->json, "%"PRIdMAX, value);
169 void jw_object_double(struct json_writer *jw, const char *key, int precision,
170 double value)
172 object_common(jw, key);
173 fmt_double(jw, precision, value);
176 void jw_object_true(struct json_writer *jw, const char *key)
178 object_common(jw, key);
179 strbuf_addstr(&jw->json, "true");
182 void jw_object_false(struct json_writer *jw, const char *key)
184 object_common(jw, key);
185 strbuf_addstr(&jw->json, "false");
188 void jw_object_bool(struct json_writer *jw, const char *key, int value)
190 if (value)
191 jw_object_true(jw, key);
192 else
193 jw_object_false(jw, key);
196 void jw_object_null(struct json_writer *jw, const char *key)
198 object_common(jw, key);
199 strbuf_addstr(&jw->json, "null");
202 static void increase_indent(struct strbuf *sb,
203 const struct json_writer *jw,
204 int indent)
206 int k;
208 strbuf_reset(sb);
209 for (k = 0; k < jw->json.len; k++) {
210 char ch = jw->json.buf[k];
211 strbuf_addch(sb, ch);
212 if (ch == '\n')
213 strbuf_addchars(sb, ' ', indent);
217 static void kill_indent(struct strbuf *sb,
218 const struct json_writer *jw)
220 int k;
221 int eat_it = 0;
223 strbuf_reset(sb);
224 for (k = 0; k < jw->json.len; k++) {
225 char ch = jw->json.buf[k];
226 if (eat_it && ch == ' ')
227 continue;
228 if (ch == '\n') {
229 eat_it = 1;
230 continue;
232 eat_it = 0;
233 strbuf_addch(sb, ch);
237 static void append_sub_jw(struct json_writer *jw,
238 const struct json_writer *value)
241 * If both are pretty, increase the indentation of the sub_jw
242 * to better fit under the super.
244 * If the super is pretty, but the sub_jw is compact, leave the
245 * sub_jw compact. (We don't want to parse and rebuild the sub_jw
246 * for this debug-ish feature.)
248 * If the super is compact, and the sub_jw is pretty, convert
249 * the sub_jw to compact.
251 * If both are compact, keep the sub_jw compact.
253 if (jw->pretty && jw->open_stack.len && value->pretty) {
254 struct strbuf sb = STRBUF_INIT;
255 increase_indent(&sb, value, jw->open_stack.len * 2);
256 strbuf_addbuf(&jw->json, &sb);
257 strbuf_release(&sb);
258 return;
260 if (!jw->pretty && value->pretty) {
261 struct strbuf sb = STRBUF_INIT;
262 kill_indent(&sb, value);
263 strbuf_addbuf(&jw->json, &sb);
264 strbuf_release(&sb);
265 return;
268 strbuf_addbuf(&jw->json, &value->json);
272 * Append existing (properly terminated) JSON sub-data (object or array)
273 * as-is onto the given JSON data.
275 void jw_object_sub_jw(struct json_writer *jw, const char *key,
276 const struct json_writer *value)
278 assert_is_terminated(value);
280 object_common(jw, key);
281 append_sub_jw(jw, value);
284 void jw_object_inline_begin_object(struct json_writer *jw, const char *key)
286 object_common(jw, key);
288 jw_object_begin(jw, jw->pretty);
291 void jw_object_inline_begin_array(struct json_writer *jw, const char *key)
293 object_common(jw, key);
295 jw_array_begin(jw, jw->pretty);
298 void jw_array_begin(struct json_writer *jw, int pretty)
300 begin(jw, '[', pretty);
303 void jw_array_string(struct json_writer *jw, const char *value)
305 array_common(jw);
306 append_quoted_string(&jw->json, value);
309 void jw_array_intmax(struct json_writer *jw, intmax_t value)
311 array_common(jw);
312 strbuf_addf(&jw->json, "%"PRIdMAX, value);
315 void jw_array_double(struct json_writer *jw, int precision, double value)
317 array_common(jw);
318 fmt_double(jw, precision, value);
321 void jw_array_true(struct json_writer *jw)
323 array_common(jw);
324 strbuf_addstr(&jw->json, "true");
327 void jw_array_false(struct json_writer *jw)
329 array_common(jw);
330 strbuf_addstr(&jw->json, "false");
333 void jw_array_bool(struct json_writer *jw, int value)
335 if (value)
336 jw_array_true(jw);
337 else
338 jw_array_false(jw);
341 void jw_array_null(struct json_writer *jw)
343 array_common(jw);
344 strbuf_addstr(&jw->json, "null");
347 void jw_array_sub_jw(struct json_writer *jw, const struct json_writer *value)
349 assert_is_terminated(value);
351 array_common(jw);
352 append_sub_jw(jw, value);
355 void jw_array_argc_argv(struct json_writer *jw, int argc, const char **argv)
357 int k;
359 for (k = 0; k < argc; k++)
360 jw_array_string(jw, argv[k]);
363 void jw_array_argv(struct json_writer *jw, const char **argv)
365 while (*argv)
366 jw_array_string(jw, *argv++);
369 void jw_array_inline_begin_object(struct json_writer *jw)
371 array_common(jw);
373 jw_object_begin(jw, jw->pretty);
376 void jw_array_inline_begin_array(struct json_writer *jw)
378 array_common(jw);
380 jw_array_begin(jw, jw->pretty);
383 int jw_is_terminated(const struct json_writer *jw)
385 return !jw->open_stack.len;
388 void jw_end(struct json_writer *jw)
390 char ch_open;
391 int len;
393 if (!jw->open_stack.len)
394 BUG("json-writer: too many jw_end(): '%s'", jw->json.buf);
396 len = jw->open_stack.len - 1;
397 ch_open = jw->open_stack.buf[len];
399 strbuf_setlen(&jw->open_stack, len);
400 jw->need_comma = 1;
402 if (jw->pretty) {
403 strbuf_addch(&jw->json, '\n');
404 indent_pretty(jw);
407 if (ch_open == '{')
408 strbuf_addch(&jw->json, '}');
409 else
410 strbuf_addch(&jw->json, ']');