THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

415 lines
8.5KB

  1. #include "cache.h"
  2. #include "json-writer.h"
  3. void jw_init(struct json_writer *jw)
  4. {
  5. strbuf_init(&jw->json, 0);
  6. strbuf_init(&jw->open_stack, 0);
  7. jw->need_comma = 0;
  8. jw->pretty = 0;
  9. }
  10. void jw_release(struct json_writer *jw)
  11. {
  12. strbuf_release(&jw->json);
  13. strbuf_release(&jw->open_stack);
  14. }
  15. /*
  16. * Append JSON-quoted version of the given string to 'out'.
  17. */
  18. static void append_quoted_string(struct strbuf *out, const char *in)
  19. {
  20. unsigned char c;
  21. strbuf_addch(out, '"');
  22. while ((c = *in++) != '\0') {
  23. if (c == '"')
  24. strbuf_addstr(out, "\\\"");
  25. else if (c == '\\')
  26. strbuf_addstr(out, "\\\\");
  27. else if (c == '\n')
  28. strbuf_addstr(out, "\\n");
  29. else if (c == '\r')
  30. strbuf_addstr(out, "\\r");
  31. else if (c == '\t')
  32. strbuf_addstr(out, "\\t");
  33. else if (c == '\f')
  34. strbuf_addstr(out, "\\f");
  35. else if (c == '\b')
  36. strbuf_addstr(out, "\\b");
  37. else if (c < 0x20)
  38. strbuf_addf(out, "\\u%04x", c);
  39. else
  40. strbuf_addch(out, c);
  41. }
  42. strbuf_addch(out, '"');
  43. }
  44. static void indent_pretty(struct json_writer *jw)
  45. {
  46. int k;
  47. for (k = 0; k < jw->open_stack.len; k++)
  48. strbuf_addstr(&jw->json, " ");
  49. }
  50. /*
  51. * Begin an object or array (either top-level or nested within the currently
  52. * open object or array).
  53. */
  54. static void begin(struct json_writer *jw, char ch_open, int pretty)
  55. {
  56. jw->pretty = pretty;
  57. strbuf_addch(&jw->json, ch_open);
  58. strbuf_addch(&jw->open_stack, ch_open);
  59. jw->need_comma = 0;
  60. }
  61. /*
  62. * Assert that the top of the open-stack is an object.
  63. */
  64. static void assert_in_object(const struct json_writer *jw, const char *key)
  65. {
  66. if (!jw->open_stack.len)
  67. BUG("json-writer: object: missing jw_object_begin(): '%s'", key);
  68. if (jw->open_stack.buf[jw->open_stack.len - 1] != '{')
  69. BUG("json-writer: object: not in object: '%s'", key);
  70. }
  71. /*
  72. * Assert that the top of the open-stack is an array.
  73. */
  74. static void assert_in_array(const struct json_writer *jw)
  75. {
  76. if (!jw->open_stack.len)
  77. BUG("json-writer: array: missing jw_array_begin()");
  78. if (jw->open_stack.buf[jw->open_stack.len - 1] != '[')
  79. BUG("json-writer: array: not in array");
  80. }
  81. /*
  82. * Add comma if we have already seen a member at this level.
  83. */
  84. static void maybe_add_comma(struct json_writer *jw)
  85. {
  86. if (jw->need_comma)
  87. strbuf_addch(&jw->json, ',');
  88. else
  89. jw->need_comma = 1;
  90. }
  91. static void fmt_double(struct json_writer *jw, int precision,
  92. double value)
  93. {
  94. if (precision < 0) {
  95. strbuf_addf(&jw->json, "%f", value);
  96. } else {
  97. struct strbuf fmt = STRBUF_INIT;
  98. strbuf_addf(&fmt, "%%.%df", precision);
  99. strbuf_addf(&jw->json, fmt.buf, value);
  100. strbuf_release(&fmt);
  101. }
  102. }
  103. static void object_common(struct json_writer *jw, const char *key)
  104. {
  105. assert_in_object(jw, key);
  106. maybe_add_comma(jw);
  107. if (jw->pretty) {
  108. strbuf_addch(&jw->json, '\n');
  109. indent_pretty(jw);
  110. }
  111. append_quoted_string(&jw->json, key);
  112. strbuf_addch(&jw->json, ':');
  113. if (jw->pretty)
  114. strbuf_addch(&jw->json, ' ');
  115. }
  116. static void array_common(struct json_writer *jw)
  117. {
  118. assert_in_array(jw);
  119. maybe_add_comma(jw);
  120. if (jw->pretty) {
  121. strbuf_addch(&jw->json, '\n');
  122. indent_pretty(jw);
  123. }
  124. }
  125. /*
  126. * Assert that the given JSON object or JSON array has been properly
  127. * terminated. (Has closing bracket.)
  128. */
  129. static void assert_is_terminated(const struct json_writer *jw)
  130. {
  131. if (jw->open_stack.len)
  132. BUG("json-writer: object: missing jw_end(): '%s'",
  133. jw->json.buf);
  134. }
  135. void jw_object_begin(struct json_writer *jw, int pretty)
  136. {
  137. begin(jw, '{', pretty);
  138. }
  139. void jw_object_string(struct json_writer *jw, const char *key, const char *value)
  140. {
  141. object_common(jw, key);
  142. append_quoted_string(&jw->json, value);
  143. }
  144. void jw_object_intmax(struct json_writer *jw, const char *key, intmax_t value)
  145. {
  146. object_common(jw, key);
  147. strbuf_addf(&jw->json, "%"PRIdMAX, value);
  148. }
  149. void jw_object_double(struct json_writer *jw, const char *key, int precision,
  150. double value)
  151. {
  152. object_common(jw, key);
  153. fmt_double(jw, precision, value);
  154. }
  155. void jw_object_true(struct json_writer *jw, const char *key)
  156. {
  157. object_common(jw, key);
  158. strbuf_addstr(&jw->json, "true");
  159. }
  160. void jw_object_false(struct json_writer *jw, const char *key)
  161. {
  162. object_common(jw, key);
  163. strbuf_addstr(&jw->json, "false");
  164. }
  165. void jw_object_bool(struct json_writer *jw, const char *key, int value)
  166. {
  167. if (value)
  168. jw_object_true(jw, key);
  169. else
  170. jw_object_false(jw, key);
  171. }
  172. void jw_object_null(struct json_writer *jw, const char *key)
  173. {
  174. object_common(jw, key);
  175. strbuf_addstr(&jw->json, "null");
  176. }
  177. static void increase_indent(struct strbuf *sb,
  178. const struct json_writer *jw,
  179. int indent)
  180. {
  181. int k;
  182. strbuf_reset(sb);
  183. for (k = 0; k < jw->json.len; k++) {
  184. char ch = jw->json.buf[k];
  185. strbuf_addch(sb, ch);
  186. if (ch == '\n')
  187. strbuf_addchars(sb, ' ', indent);
  188. }
  189. }
  190. static void kill_indent(struct strbuf *sb,
  191. const struct json_writer *jw)
  192. {
  193. int k;
  194. int eat_it = 0;
  195. strbuf_reset(sb);
  196. for (k = 0; k < jw->json.len; k++) {
  197. char ch = jw->json.buf[k];
  198. if (eat_it && ch == ' ')
  199. continue;
  200. if (ch == '\n') {
  201. eat_it = 1;
  202. continue;
  203. }
  204. eat_it = 0;
  205. strbuf_addch(sb, ch);
  206. }
  207. }
  208. static void append_sub_jw(struct json_writer *jw,
  209. const struct json_writer *value)
  210. {
  211. /*
  212. * If both are pretty, increase the indentation of the sub_jw
  213. * to better fit under the super.
  214. *
  215. * If the super is pretty, but the sub_jw is compact, leave the
  216. * sub_jw compact. (We don't want to parse and rebuild the sub_jw
  217. * for this debug-ish feature.)
  218. *
  219. * If the super is compact, and the sub_jw is pretty, convert
  220. * the sub_jw to compact.
  221. *
  222. * If both are compact, keep the sub_jw compact.
  223. */
  224. if (jw->pretty && jw->open_stack.len && value->pretty) {
  225. struct strbuf sb = STRBUF_INIT;
  226. increase_indent(&sb, value, jw->open_stack.len * 2);
  227. strbuf_addbuf(&jw->json, &sb);
  228. strbuf_release(&sb);
  229. return;
  230. }
  231. if (!jw->pretty && value->pretty) {
  232. struct strbuf sb = STRBUF_INIT;
  233. kill_indent(&sb, value);
  234. strbuf_addbuf(&jw->json, &sb);
  235. strbuf_release(&sb);
  236. return;
  237. }
  238. strbuf_addbuf(&jw->json, &value->json);
  239. }
  240. /*
  241. * Append existing (properly terminated) JSON sub-data (object or array)
  242. * as-is onto the given JSON data.
  243. */
  244. void jw_object_sub_jw(struct json_writer *jw, const char *key,
  245. const struct json_writer *value)
  246. {
  247. assert_is_terminated(value);
  248. object_common(jw, key);
  249. append_sub_jw(jw, value);
  250. }
  251. void jw_object_inline_begin_object(struct json_writer *jw, const char *key)
  252. {
  253. object_common(jw, key);
  254. jw_object_begin(jw, jw->pretty);
  255. }
  256. void jw_object_inline_begin_array(struct json_writer *jw, const char *key)
  257. {
  258. object_common(jw, key);
  259. jw_array_begin(jw, jw->pretty);
  260. }
  261. void jw_array_begin(struct json_writer *jw, int pretty)
  262. {
  263. begin(jw, '[', pretty);
  264. }
  265. void jw_array_string(struct json_writer *jw, const char *value)
  266. {
  267. array_common(jw);
  268. append_quoted_string(&jw->json, value);
  269. }
  270. void jw_array_intmax(struct json_writer *jw, intmax_t value)
  271. {
  272. array_common(jw);
  273. strbuf_addf(&jw->json, "%"PRIdMAX, value);
  274. }
  275. void jw_array_double(struct json_writer *jw, int precision, double value)
  276. {
  277. array_common(jw);
  278. fmt_double(jw, precision, value);
  279. }
  280. void jw_array_true(struct json_writer *jw)
  281. {
  282. array_common(jw);
  283. strbuf_addstr(&jw->json, "true");
  284. }
  285. void jw_array_false(struct json_writer *jw)
  286. {
  287. array_common(jw);
  288. strbuf_addstr(&jw->json, "false");
  289. }
  290. void jw_array_bool(struct json_writer *jw, int value)
  291. {
  292. if (value)
  293. jw_array_true(jw);
  294. else
  295. jw_array_false(jw);
  296. }
  297. void jw_array_null(struct json_writer *jw)
  298. {
  299. array_common(jw);
  300. strbuf_addstr(&jw->json, "null");
  301. }
  302. void jw_array_sub_jw(struct json_writer *jw, const struct json_writer *value)
  303. {
  304. assert_is_terminated(value);
  305. array_common(jw);
  306. append_sub_jw(jw, value);
  307. }
  308. void jw_array_argc_argv(struct json_writer *jw, int argc, const char **argv)
  309. {
  310. int k;
  311. for (k = 0; k < argc; k++)
  312. jw_array_string(jw, argv[k]);
  313. }
  314. void jw_array_argv(struct json_writer *jw, const char **argv)
  315. {
  316. while (*argv)
  317. jw_array_string(jw, *argv++);
  318. }
  319. void jw_array_inline_begin_object(struct json_writer *jw)
  320. {
  321. array_common(jw);
  322. jw_object_begin(jw, jw->pretty);
  323. }
  324. void jw_array_inline_begin_array(struct json_writer *jw)
  325. {
  326. array_common(jw);
  327. jw_array_begin(jw, jw->pretty);
  328. }
  329. int jw_is_terminated(const struct json_writer *jw)
  330. {
  331. return !jw->open_stack.len;
  332. }
  333. void jw_end(struct json_writer *jw)
  334. {
  335. char ch_open;
  336. int len;
  337. if (!jw->open_stack.len)
  338. BUG("json-writer: too many jw_end(): '%s'", jw->json.buf);
  339. len = jw->open_stack.len - 1;
  340. ch_open = jw->open_stack.buf[len];
  341. strbuf_setlen(&jw->open_stack, len);
  342. jw->need_comma = 1;
  343. if (jw->pretty) {
  344. strbuf_addch(&jw->json, '\n');
  345. indent_pretty(jw);
  346. }
  347. if (ch_open == '{')
  348. strbuf_addch(&jw->json, '}');
  349. else
  350. strbuf_addch(&jw->json, ']');
  351. }