return streq(a->s, b->s);
}
+bool json_escape_needed(const char *str, size_t len)
+{
+ for (size_t i = 0; i < len; i++) {
+ if ((unsigned)str[i] < ' '
+ || str[i] == 127
+ || str[i] == '"'
+ || str[i] == '\\')
+ return true;
+ }
+ return false;
+}
+
static struct json_escape *escape(const tal_t *ctx,
const char *str TAKES,
size_t len,
struct json_escape *esc;
size_t i, n;
+ /* Fast path: can steal, and nothing to escape. */
+ if (is_taken(str)
+ && tal_count(str) > len
+ && !json_escape_needed(str, len)) {
+ taken(str);
+ esc = (struct json_escape *)tal_steal(ctx, str);
+ esc->s[len] = '\0';
+ return esc;
+ }
+
/* Worst case: all \uXXXX */
esc = (struct json_escape *)tal_arr(ctx, char, len * 6 + 1);
struct json_escape *json_partial_escape(const tal_t *ctx,
const char *str TAKES);
-/* Extract a JSON-escaped string. */
+/* Do we need to escape this str? */
+bool json_escape_needed(const char *str, size_t len);
/* Are two escape json strings identical? */
bool json_escape_eq(const struct json_escape *a,
--- /dev/null
+#include <ccan/json_escape/json_escape.h>
+/* Include the C files directly. */
+#include <ccan/json_escape/json_escape.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+ const tal_t *ctx = tal(NULL, char);
+ struct json_escape *e;
+ char *p;
+
+ /* This is how many tests you plan to run */
+ plan_tests(5);
+
+ /* This should simply be tal_steal */
+ p = tal_dup_arr(NULL, char, "Hello", 6, 0);
+ e = json_escape(ctx, take(p));
+ ok1(!strcmp(e->s, "Hello"));
+ ok1((void *)e == (void *)p);
+ ok1(tal_parent(e) == ctx);
+
+ /* This can't be tal_steal, but still should be freed. */
+ p = tal_dup_arr(NULL, char,
+ "\\\b\f\n\r\t\""
+ "\\\\\\b\\f\\n\\r\\t\\\"", 22, 0);
+ e = json_escape(ctx, take(p));
+ ok1(tal_parent(e) == ctx);
+ ok1(!strcmp(e->s,
+ "\\\\\\b\\f\\n\\r\\t\\\""
+ "\\\\\\\\\\\\b\\\\f\\\\n\\\\r\\\\t\\\\\\\""));
+ tal_free(ctx);
+
+ /* This exits depending on whether all tests passed */
+ return exit_status();
+}