+struct json_node *json_parse2(const char *json_str, const char **errmsg,
+ size_t *pos)
+{
+ json_parser_t p = json_parser_create();
+ struct json_node *n = 0;
+ if (!p)
+ {
+ if (errmsg)
+ *errmsg = "could not create parser";
+ }
+ else
+ {
+ n = json_parser_parse(p, json_str);
+ if (!n && errmsg)
+ *errmsg = json_parser_get_errmsg(p);
+ if (pos)
+ *pos = json_parser_get_position(p);
+ json_parser_destroy(p);
+ }
+ return n;
+}
+
+struct json_node *json_parse(const char *json_str, const char **errmsg)
+{
+ return json_parse2(json_str, errmsg, 0);
+}
+
+static void wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
+{
+ size_t i;
+ for (i = 0; i < sz; i++)
+ {
+ if (cp[i] > 0 && cp[i] < 32)
+ {
+ wrbuf_putc(b, '\\');
+ switch (cp[i])
+ {
+ case '\b': wrbuf_putc(b, 'b'); break;
+ case '\f': wrbuf_putc(b, 'f'); break;
+ case '\n': wrbuf_putc(b, 'n'); break;
+ case '\r': wrbuf_putc(b, 'r'); break;
+ case '\t': wrbuf_putc(b, 't'); break;
+ default:
+ wrbuf_printf(b, "u%04x", cp[i]);
+ }
+ }
+ else if (cp[i] == '"')
+ {
+ wrbuf_putc(b, '\\'); wrbuf_putc(b, '"');
+ }
+ else if (cp[i] == '\\')
+ {
+ wrbuf_putc(b, '\\'); wrbuf_putc(b, '\\');
+ }
+ else
+ { /* leave encoding as raw UTF-8 */
+ wrbuf_putc(b, cp[i]);
+ }
+ }
+
+}
+
+void wrbuf_json_puts(WRBUF b, const char *str)
+{
+ wrbuf_json_write(b, str, strlen(str));
+}
+
+static void json_indent(WRBUF result, int indent)
+{
+ size_t l = wrbuf_len(result);
+ if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
+ {
+ int i;
+ for (i = 0; i < indent; i++)
+ wrbuf_putc(result, ' ');
+ }
+}
+
+static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)