X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fjson_out%2Fjson_out.c;h=87deaca85f9ce0375ff9bd299ced923669f7c739;hp=b8c798fc0dae7527cbf5986da619cdf7cb8ed437;hb=4fc7da62b4a9632ea19e1f485d6a384a3b24ed00;hpb=2fd44331077429da94f8f7eb43513068257742f8 diff --git a/ccan/json_out/json_out.c b/ccan/json_out/json_out.c index b8c798fc..87deaca8 100644 --- a/ccan/json_out/json_out.c +++ b/ccan/json_out/json_out.c @@ -11,7 +11,7 @@ struct json_out { void *cb_arg; #ifdef CCAN_JSON_OUT_DEBUG - /* tal_arr of types ( or [ we're enclosed in. */ + /* tal_arr of types ( or [ we're enclosed in. NULL if oom. */ char *wrapping; #endif /* True if we haven't yet put an element in current wrapping */ @@ -27,16 +27,23 @@ static void *membuf_tal_realloc(struct membuf *mb, { char *p = rawelems; - tal_resize(&p, newsize); + if (!tal_resize(&p, newsize)) + return NULL; return p; } struct json_out *json_out_new(const tal_t *ctx) { struct json_out *jout = tal(ctx, struct json_out); + char *pool; - membuf_init(&jout->outbuf, - tal_arr(jout, char, 64), 64, membuf_tal_realloc); + if (!jout) + return NULL; + pool = tal_arr(jout, char, 64); + if (!pool) + return tal_free(jout); + + membuf_init(&jout->outbuf, pool, tal_count(pool), membuf_tal_realloc); #ifdef CCAN_JSON_OUT_DEBUG jout->wrapping = tal_arr(jout, char, 0); #endif @@ -61,9 +68,14 @@ struct json_out *json_out_dup(const tal_t *ctx, const struct json_out *src) size_t num_elems = membuf_num_elems(&src->outbuf); char *elems = membuf_elems(&src->outbuf); struct json_out *jout = tal_dup(ctx, struct json_out, src); - membuf_init(&jout->outbuf, - tal_dup_arr(jout, char, elems, num_elems, 0), - num_elems, membuf_tal_realloc); + char *pool; + + if (!jout) + return NULL; + pool = tal_dup_arr(jout, char, elems, num_elems, 0); + if (!pool) + return tal_free(jout); + membuf_init(&jout->outbuf, pool, num_elems, membuf_tal_realloc); membuf_added(&jout->outbuf, num_elems); #ifdef CCAN_JSON_OUT_DEBUG jout->wrapping = tal_dup_arr(jout, char, @@ -76,9 +88,14 @@ struct json_out *json_out_dup(const tal_t *ctx, const struct json_out *src) static void indent(struct json_out *jout, char type) { #ifdef CCAN_JSON_OUT_DEBUG - size_t n = tal_count(jout->wrapping); - tal_resize(&jout->wrapping, n+1); - jout->wrapping[n] = type; + /* Can't check if we ran out of memory. */ + if (jout->wrapping) { + size_t n = tal_count(jout->wrapping); + if (!tal_resize(&jout->wrapping, n+1)) + jout->wrapping = tal_free(jout->wrapping); + else + jout->wrapping[n] = type; + } #endif jout->empty = true; } @@ -86,11 +103,14 @@ static void indent(struct json_out *jout, char type) static void unindent(struct json_out *jout, char type) { #ifdef CCAN_JSON_OUT_DEBUG - size_t indent = tal_count(jout->wrapping); - assert(indent > 0); - /* Both [ and ] and { and } are two apart in ASCII */ - assert(jout->wrapping[indent-1] == type - 2); - tal_resize(&jout->wrapping, indent-1); + /* Can't check if we ran out of memory. */ + if (jout->wrapping) { + size_t indent = tal_count(jout->wrapping); + assert(indent > 0); + /* Both [ and ] and { and } are two apart in ASCII */ + assert(jout->wrapping[indent-1] == type - 2); + tal_resize(&jout->wrapping, indent-1); + } #endif jout->empty = false; } @@ -110,18 +130,22 @@ static void check_fieldname(const struct json_out *jout, const char *fieldname) { #ifdef CCAN_JSON_OUT_DEBUG - size_t n = tal_count(jout->wrapping); - if (n == 0) - /* Can't have a fieldname if not in anything! */ - assert(!fieldname); - else if (jout->wrapping[n-1] == '[') - /* No fieldnames in arrays. */ - assert(!fieldname); - else { - /* Must have fieldnames in objects. */ - assert(fieldname); - /* We don't escape this for you */ - assert(!json_escape_needed(fieldname, strlen(fieldname))); + /* We don't escape this for you */ + assert(!fieldname || !json_escape_needed(fieldname, strlen(fieldname))); + + /* Can't check anything else if we ran out of memory. */ + if (jout->wrapping) { + size_t n = tal_count(jout->wrapping); + if (n == 0) + /* Can't have a fieldname if not in anything! */ + assert(!fieldname); + else if (jout->wrapping[n-1] == '[') + /* No fieldnames in arrays. */ + assert(!fieldname); + else { + /* Must have fieldnames in objects. */ + assert(fieldname); + } } #endif } @@ -139,12 +163,9 @@ char *json_out_member_direct(struct json_out *jout, if (fieldname) extra += 1 + strlen(fieldname) + 2; - if (!extra) { - dest = NULL; - goto out; - } - dest = mkroom(jout, extra); + if (!dest) + goto out; if (!jout->empty) *(dest++) = ','; @@ -162,21 +183,33 @@ out: return dest; } -void json_out_start(struct json_out *jout, const char *fieldname, char type) +bool json_out_start(struct json_out *jout, const char *fieldname, char type) { + char *p; + assert(type == '[' || type == '{'); - json_out_member_direct(jout, fieldname, 1)[0] = type; + p = json_out_member_direct(jout, fieldname, 1); + if (p) + p[0] = type; indent(jout, type); + + return p != NULL; } -void json_out_end(struct json_out *jout, char type) +bool json_out_end(struct json_out *jout, char type) { + char *p; + assert(type == '}' || type == ']'); - json_out_direct(jout, 1)[0] = type; + p = json_out_direct(jout, 1); + if (p) + p[0] = type; unindent(jout, type); + + return p != NULL; } -void json_out_addv(struct json_out *jout, +bool json_out_addv(struct json_out *jout, const char *fieldname, bool quote, const char *fmt, @@ -186,7 +219,8 @@ void json_out_addv(struct json_out *jout, va_list ap2; char *dst; - json_out_member_direct(jout, fieldname, 0); + if (!json_out_member_direct(jout, fieldname, 0)) + return false; /* Make a copy in case we need it below. */ va_copy(ap2, ap); @@ -210,52 +244,78 @@ void json_out_addv(struct json_out *jout, if (fmtlen + (int)quote*2 >= membuf_num_space(&jout->outbuf)) { /* Make room for NUL terminator, even though we don't want it */ dst = mkroom(jout, fmtlen + 1 + (int)quote*2); + if (!dst) + goto out; vsprintf(dst + quote, fmt, ap2); } - /* Of course, if we need to escape it, we have to redo it all. */ - if (json_escape_needed(dst + quote, fmtlen)) { - struct json_escape *e; - e = json_escape_len(NULL, dst + quote, fmtlen); - fmtlen = strlen(e->s); - dst = mkroom(jout, fmtlen + (int)quote*2); - memcpy(dst + quote, e, fmtlen); - tal_free(e); - } +#ifdef CCAN_JSON_OUT_DEBUG + /* You're not inserting junk here, are you? */ + assert(quote || !json_escape_needed(dst, fmtlen)); +#endif + /* Of course, if we need to escape it, we have to redo it all. */ if (quote) { + if (json_escape_needed(dst + quote, fmtlen)) { + struct json_escape *e; + e = json_escape_len(NULL, dst + quote, fmtlen); + fmtlen = strlen(e->s); + dst = mkroom(jout, fmtlen + (int)quote*2); + if (!dst) + goto out; + memcpy(dst + quote, e, fmtlen); + tal_free(e); + } dst[0] = '"'; dst[fmtlen+1] = '"'; } membuf_added(&jout->outbuf, fmtlen + (int)quote*2); + +out: va_end(ap2); + return dst != NULL; } -void json_out_add(struct json_out *jout, +bool json_out_add(struct json_out *jout, const char *fieldname, bool quote, const char *fmt, ...) { va_list ap; + bool ret; va_start(ap, fmt); - json_out_addv(jout, fieldname, quote, fmt, ap); + ret = json_out_addv(jout, fieldname, quote, fmt, ap); va_end(ap); + return ret; } -void json_out_addstr(struct json_out *jout, +bool json_out_addstr(struct json_out *jout, const char *fieldname, const char *str) { size_t len = strlen(str); char *p; + struct json_escape *e; + + if (json_escape_needed(str, len)) { + e = json_escape(NULL, str); + str = e->s; + len = strlen(str); + } else + e = NULL; p = json_out_member_direct(jout, fieldname, len + 2); - p[0] = p[1+len] = '"'; - memcpy(p+1, str, len); + if (p) { + p[0] = p[1+len] = '"'; + memcpy(p+1, str, len); + } + tal_free(e); + + return p != NULL; } -void json_out_add_splice(struct json_out *jout, +bool json_out_add_splice(struct json_out *jout, const char *fieldname, const struct json_out *src) { @@ -263,13 +323,17 @@ void json_out_add_splice(struct json_out *jout, size_t len; p = json_out_contents(src, &len); + if (!p) + return false; memcpy(json_out_member_direct(jout, fieldname, len), p, len); + return true; } char *json_out_direct(struct json_out *jout, size_t len) { char *p = mkroom(jout, len); - membuf_added(&jout->outbuf, len); + if (p) + membuf_added(&jout->outbuf, len); return p; }