diff --git a/common/json_stream.c b/common/json_stream.c index 740defa7c..f55603352 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -128,15 +128,6 @@ void json_stream_flush(struct json_stream *js) io_wake(js); } -char *json_member_direct(struct json_stream *js, - const char *fieldname, size_t extra) -{ - char *dest; - - dest = json_out_member_direct(js->jout, fieldname, extra); - return dest; -} - void json_array_start(struct json_stream *js, const char *fieldname) { json_out_start(js->jout, fieldname, '['); @@ -157,18 +148,55 @@ void json_object_end(struct json_stream *js) json_out_end(js->jout, '}'); } -void json_add_member(struct json_stream *js, - const char *fieldname, - bool quote, - const char *fmt, ...) +void json_add_primitive_fmt(struct json_stream *js, + const char *fieldname, + const char *fmt, ...) { va_list ap; va_start(ap, fmt); - json_out_addv(js->jout, fieldname, quote, fmt, ap); + json_out_addv(js->jout, fieldname, false, fmt, ap); va_end(ap); } +void json_add_str_fmt(struct json_stream *js, + const char *fieldname, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + json_out_addv(js->jout, fieldname, true, fmt, ap); + va_end(ap); +} + +void json_add_primitive(struct json_stream *js, + const char *fieldname, + const char *val TAKES) +{ + json_add_primitive_fmt(js, fieldname, "%s", val); + if (taken(val)) + tal_free(val); +} + +void json_add_string(struct json_stream *js, + const char *fieldname, + const char *str TAKES) +{ + json_out_addstr(js->jout, fieldname, str); + if (taken(str)) + tal_free(str); +} + +static char *json_member_direct(struct json_stream *js, + const char *fieldname, size_t extra) +{ + char *dest; + + dest = json_out_member_direct(js->jout, fieldname, extra); + return dest; +} + void json_add_jsonstr(struct json_stream *js, const char *fieldname, const char *jsonstr) @@ -225,76 +253,62 @@ struct io_plan *json_stream_output_(struct json_stream *js, void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value) { - json_add_member(result, fieldname, false, "%u", value); + json_add_primitive_fmt(result, fieldname, "%u", value); } void json_add_u64(struct json_stream *result, const char *fieldname, uint64_t value) { - json_add_member(result, fieldname, false, "%"PRIu64, value); + json_add_primitive_fmt(result, fieldname, "%"PRIu64, value); } void json_add_s64(struct json_stream *result, const char *fieldname, int64_t value) { - json_add_member(result, fieldname, false, "%"PRIi64, value); + json_add_primitive_fmt(result, fieldname, "%"PRIi64, value); } void json_add_u32(struct json_stream *result, const char *fieldname, uint32_t value) { - json_add_member(result, fieldname, false, "%u", value); + json_add_primitive_fmt(result, fieldname, "%u", value); } void json_add_s32(struct json_stream *result, const char *fieldname, int32_t value) { - json_add_member(result, fieldname, false, "%d", value); -} - -void json_add_literal(struct json_stream *result, const char *fieldname, - const char *literal, int len) -{ - /* Literal may contain quotes, so bypass normal checks */ - char *dest = json_member_direct(result, fieldname, len); - memcpy(dest, literal, len); + json_add_primitive_fmt(result, fieldname, "%d", value); } void json_add_stringn(struct json_stream *result, const char *fieldname, const char *value TAKES, size_t value_len) { - json_add_member(result, fieldname, true, "%.*s", (int)value_len, value); + json_add_str_fmt(result, fieldname, "%.*s", (int)value_len, value); if (taken(value)) tal_free(value); } -void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES) -{ - json_add_stringn(result, fieldname, value, strlen(value)); -} - void json_add_bool(struct json_stream *result, const char *fieldname, bool value) { - json_add_member(result, fieldname, false, value ? "true" : "false"); + json_add_primitive(result, fieldname, value ? "true" : "false"); } void json_add_null(struct json_stream *stream, const char *fieldname) { - json_add_member(stream, fieldname, false, "null"); + json_add_primitive(stream, fieldname, "null"); } void json_add_hex(struct json_stream *js, const char *fieldname, const void *data, size_t len) { /* Size without NUL term */ - size_t hexlen = hex_str_size(len) - 1; - char *dest; + size_t hexlen = hex_str_size(len); + char str[hexlen]; - dest = json_member_direct(js, fieldname, 1 + hexlen + 1); - dest[0] = '"'; - if (!hex_encode(data, len, dest + 1, hexlen + 1)) + if (!hex_encode(data, len, str, hexlen)) abort(); - dest[1+hexlen] = '"'; + + json_add_string(js, fieldname, str); } void json_add_hex_talarr(struct json_stream *result, @@ -321,8 +335,9 @@ void json_add_escaped_string(struct json_stream *result, const char *fieldname, void json_add_timeabs(struct json_stream *result, const char *fieldname, struct timeabs t) { - json_add_member(result, fieldname, false, "%" PRIu64 ".%03" PRIu64, - (u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000); + json_add_primitive_fmt(result, fieldname, + "%" PRIu64 ".%03" PRIu64, + (u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000); } void json_add_time(struct json_stream *result, const char *fieldname, @@ -365,7 +380,7 @@ void json_add_tok(struct json_stream *result, const char *fieldname, void json_add_errcode(struct json_stream *result, const char *fieldname, errcode_t code) { - json_add_member(result, fieldname, false, "%"PRIerrcode, code); + json_add_primitive_fmt(result, fieldname, "%" PRIerrcode, code); } void json_add_invstring(struct json_stream *result, const char *invstring) @@ -431,17 +446,17 @@ void json_add_outpoint(struct json_stream *result, const char *fieldname, { char hex[hex_str_size(sizeof(out->txid))]; bitcoin_txid_to_hex(&out->txid, hex, sizeof(hex)); - json_add_member(result, fieldname, true, "%s:%d", hex, out->n); + json_add_str_fmt(result, fieldname, "%s:%d", hex, out->n); } void json_add_short_channel_id(struct json_stream *response, const char *fieldname, const struct short_channel_id *scid) { - json_add_member(response, fieldname, true, "%dx%dx%d", - short_channel_id_blocknum(scid), - short_channel_id_txnum(scid), - short_channel_id_outnum(scid)); + json_add_str_fmt(response, fieldname, "%dx%dx%d", + short_channel_id_blocknum(scid), + short_channel_id_txnum(scid), + short_channel_id_outnum(scid)); } void json_add_address(struct json_stream *response, const char *fieldname, diff --git a/common/json_stream.h b/common/json_stream.h index 71bf82814..7743a29a8 100644 --- a/common/json_stream.h +++ b/common/json_stream.h @@ -107,19 +107,50 @@ void json_object_end(struct json_stream *js); void json_stream_append(struct json_stream *js, const char *str, size_t len); /** - * json_add_member - add a generic member. + * json_add_primitive_fmt - add an unquoted literal member. * @js: the json_stream. * @fieldname: fieldname (if in object), otherwise must be NULL. - * @quote: true if should be escaped and wrapped in "". * @fmt...: the printf-style format - * - * The resulting string from @fmt is escaped if quote is true: - * see json_member_direct to avoid quoting. */ -void json_add_member(struct json_stream *js, +void json_add_primitive_fmt(struct json_stream *js, + const char *fieldname, + const char *fmt, ...) PRINTF_FMT(3,4); + +/** + * json_add_primitive - add an unquoted literal member. + * @js: the json_stream. + * @fieldname: fieldname (if in object), otherwise must be NULL. + * @val: the primitive + */ +void json_add_primitive(struct json_stream *js, + const char *fieldname, + const char *val TAKES); + +/** + * json_add_str_fmt - add a string member (printf-style). + * @js: the json_stream. + * @fieldname: fieldname (if in object), otherwise must be NULL. + * @fmt...: the printf-style format + */ +void json_add_str_fmt(struct json_stream *js, + const char *fieldname, + const char *fmt, ...) PRINTF_FMT(3,4); + +/** + * json_add_string - add a string member. + * @js: the json_stream. + * @fieldname: fieldname (if in object), otherwise must be NULL. + * @str: the string + */ +void json_add_string(struct json_stream *js, const char *fieldname, - bool quote, - const char *fmt, ...) PRINTF_FMT(4,5); + const char *str TAKES); + +/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. String must + * already be JSON escaped as necessary. */ +void json_add_escaped_string(struct json_stream *result, + const char *fieldname, + const struct json_escape *esc TAKES); /** * json_add_jsonstr - add a JSON entity in a string that is already @@ -133,17 +164,6 @@ void json_add_jsonstr(struct json_stream *js, const char *fieldname, const char *jsonstr); -/** - * json_member_direct - start a generic member. - * @js: the json_stream. - * @fieldname: fieldname (if in object), otherwise must be NULL. - * @extra: the space to reserve. - * - * Returns a ptr to @extra bytes. - */ -char *json_member_direct(struct json_stream *js, - const char *fieldname, size_t extra); - /** * json_stream_output - start writing out a json_stream to this conn. * @js: the json_stream diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index f9ece1ce4..317346ca1 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -506,9 +506,9 @@ static void json_command_malformed(struct json_connection *jcon, json_object_start(js, NULL); json_add_string(js, "jsonrpc", "2.0"); - json_add_literal(js, "id", id, strlen(id)); + json_add_primitive(js, "id", id); json_object_start(js, "error"); - json_add_member(js, "code", false, "%" PRIerrcode, JSONRPC2_INVALID_REQUEST); + json_add_errcode(js, "code", JSONRPC2_INVALID_REQUEST); json_add_string(js, "message", error); json_object_end(js); json_object_end(js); @@ -578,7 +578,7 @@ static struct json_stream *json_start(struct command *cmd) json_object_start(js, NULL); json_add_string(js, "jsonrpc", "2.0"); - json_add_literal(js, "id", cmd->id, strlen(cmd->id)); + json_add_jsonstr(js, "id", cmd->id); return js; } @@ -598,7 +598,7 @@ struct json_stream *json_stream_fail_nodata(struct command *cmd, assert(code); json_object_start(js, "error"); - json_add_member(js, "code", false, "%" PRIerrcode, code); + json_add_errcode(js, "code", code); json_add_string(js, "message", errmsg); return js; diff --git a/lightningd/log.c b/lightningd/log.c index 11a66a092..dd44636b1 100644 --- a/lightningd/log.c +++ b/lightningd/log.c @@ -606,8 +606,8 @@ void json_add_opt_log_levels(struct json_stream *response, struct log *log) struct print_filter *i; list_for_each(&log->lr->print_filters, i, list) { - json_add_member(response, "log-level", true, "%s:%s", - log_level_name(i->level), i->prefix); + json_add_str_fmt(response, "log-level", "%s:%s", + log_level_name(i->level), i->prefix); } } diff --git a/lightningd/notification.c b/lightningd/notification.c index 8f1528a67..a11602c72 100644 --- a/lightningd/notification.c +++ b/lightningd/notification.c @@ -399,7 +399,7 @@ static void sendpay_failure_notification_serialize(struct json_stream *stream, /* In line with the format of json error returned * by sendpay_fail(). */ - json_add_member(stream, "code", false, "%" PRIerrcode, pay_errcode); + json_add_errcode(stream, "code", pay_errcode); json_add_string(stream, "message", errmsg); json_object_start(stream, "data"); diff --git a/lightningd/options.c b/lightningd/options.c index 590f17e19..fc3263a21 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -1563,8 +1563,7 @@ static void add_config(struct lightningd *ld, || (!streq(buf, "") && strspn(buf, "0123456789.") == strlen(buf))) { /* Let pure numbers and true/false through as * literals. */ - json_add_literal(response, name0, - buf, strlen(buf)); + json_add_primitive(response, name0, buf); return; } diff --git a/lightningd/test/run-log-pruning.c b/lightningd/test/run-log-pruning.c index 9449cbc82..390368835 100644 --- a/lightningd/test/run-log-pruning.c +++ b/lightningd/test/run-log-pruning.c @@ -32,12 +32,6 @@ void json_add_hex_talarr(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const tal_t *data UNNEEDED) { fprintf(stderr, "json_add_hex_talarr called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } /* Generated stub for json_add_node_id */ void json_add_node_id(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED, @@ -47,6 +41,11 @@ void json_add_node_id(struct json_stream *response UNNEEDED, void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, unsigned int value UNNEEDED) { fprintf(stderr, "json_add_num called!\n"); abort(); } +/* Generated stub for json_add_str_fmt */ +void json_add_str_fmt(struct json_stream *js UNNEEDED, + const char *fieldname UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "json_add_str_fmt called!\n"); abort(); } /* Generated stub for json_add_string */ void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value TAKES UNNEEDED) { fprintf(stderr, "json_add_string called!\n"); abort(); } diff --git a/plugins/libplugin.c b/plugins/libplugin.c index c684a658a..74311b81c 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -208,7 +208,7 @@ struct json_stream *jsonrpc_stream_fail(struct command *cmd, struct json_stream *js = jsonrpc_stream_start(cmd); json_object_start(js, "error"); - json_add_member(js, "code", false, "%d", code); + json_add_primitive_fmt(js, "code", "%d", code); json_add_string(js, "message", err); return js; diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index 3a991ad49..a75817bba 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -634,7 +634,7 @@ static struct command_result *convert_currency(struct command *cmd, json_add_stringn(req->js, "currency", (const char *)ir->offer->currency, tal_bytelen(ir->offer->currency)); - json_add_member(req->js, "amount", false, "%f", double_amount); + json_add_primitive_fmt(req->js, "amount", "%f", double_amount); return send_outreq(cmd->plugin, req); }