From patchwork Mon Oct 10 13:23:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 680406 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3st1R46m4Bz9s9Y for ; Tue, 11 Oct 2016 00:38:08 +1100 (AEDT) Received: from localhost ([::1]:50186 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btamL-0007xU-HY for incoming@patchwork.ozlabs.org; Mon, 10 Oct 2016 09:38:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58077) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btaYr-00050q-Hm for qemu-devel@nongnu.org; Mon, 10 Oct 2016 09:24:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1btaYo-0007G7-Si for qemu-devel@nongnu.org; Mon, 10 Oct 2016 09:24:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47278) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btaYo-0007Fr-Iv for qemu-devel@nongnu.org; Mon, 10 Oct 2016 09:24:06 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 27BDCC04B949 for ; Mon, 10 Oct 2016 13:24:06 +0000 (UTC) Received: from red.redhat.com (ovpn-116-125.phx2.redhat.com [10.3.116.125]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u9ADO21a017734; Mon, 10 Oct 2016 09:24:05 -0400 From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 10 Oct 2016 08:23:47 -0500 Message-Id: <1476105837-9861-6-git-send-email-eblake@redhat.com> In-Reply-To: <1476105837-9861-1-git-send-email-eblake@redhat.com> References: <1476105837-9861-1-git-send-email-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 10 Oct 2016 13:24:06 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v6 05/15] qapi: Add qstring_append_printf() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Amit Shah , armbru@redhat.com, Juan Quintela Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Back in commit 764c1ca (Nov 2009), we added qstring_append_int(). However, it did not see any use until commit 190c882 (Jan 2015). Furthermore, it has a rather limited use case - to print anything else, callers still have to format into a temporary buffer, unless we want to introduce an explosion of new qstring_append_* methods for each useful type to print. A much better approach is to add a wrapper that merges printf behavior onto qstring_append, via the new qstring_append_printf() (and its vararg counterpart), with a name based on glib's g_string_append_printf(). In fact, with our wrapper in place, we no longer need qstring_append_int(). Other immediate uses for the new function include simplifying two existing clients of qstring_append() on a just-formatted buffer, and the fact that we can take advantage of printf width manipulations for more efficient indentation. Signed-off-by: Eric Blake --- v6: no change [no v5 due to series split] v4: retitle, s/_format/_printf/, drop R-b, move up in series v3: rebase to master v2: also simplify qstring_append_json_string(), add assertion that format is well-formed --- include/qapi/qmp/qstring.h | 7 +++++-- migration/qjson.c | 2 +- qobject/qjson.c | 38 ++++++++++---------------------------- qobject/qstring.c | 26 +++++++++++++++++++++----- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 10076b7..a987f3b 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -1,7 +1,7 @@ /* * QString Module * - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009-2016 Red Hat Inc. * * Authors: * Luiz Capitulino @@ -27,9 +27,12 @@ QString *qstring_from_str(const char *str); QString *qstring_from_substr(const char *str, int start, int end); size_t qstring_get_length(const QString *qstring); const char *qstring_get_str(const QString *qstring); -void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); void qstring_append_chr(QString *qstring, int c); +void qstring_append_printf(QString *qstring, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); +void qstring_append_vprintf(QString *qstring, const char *fmt, va_list ap) + GCC_FMT_ATTR(2, 0); QString *qobject_to_qstring(const QObject *obj); void qstring_destroy_obj(QObject *obj); diff --git a/migration/qjson.c b/migration/qjson.c index 741f9e6..f11effd 100644 --- a/migration/qjson.c +++ b/migration/qjson.c @@ -77,7 +77,7 @@ void json_end_array(QJSON *json) void json_prop_int(QJSON *json, const char *name, int64_t val) { json_emit_element(json, name); - qstring_append_int(json->str, val); + qstring_append_printf(json->str, "%" PRId64, val); } void json_prop_str(QJSON *json, const char *name, const char *str) diff --git a/qobject/qjson.c b/qobject/qjson.c index b47a361..7dc694c 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -82,16 +82,13 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent); static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) { ToJsonIterState *s = opaque; - int j; if (s->count) { qstring_append(s->str, s->pretty ? "," : ", "); } if (s->pretty) { - qstring_append(s->str, "\n"); - for (j = 0 ; j < s->indent ; j++) - qstring_append(s->str, " "); + qstring_append_printf(s->str, "\n%*s", 4 * s->indent, ""); } qstring_append_json_string(s->str, key); @@ -104,16 +101,13 @@ static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) static void to_json_list_iter(QObject *obj, void *opaque) { ToJsonIterState *s = opaque; - int j; if (s->count) { qstring_append(s->str, s->pretty ? "," : ", "); } if (s->pretty) { - qstring_append(s->str, "\n"); - for (j = 0 ; j < s->indent ; j++) - qstring_append(s->str, " "); + qstring_append_printf(s->str, "\n%*s", 4 * s->indent, ""); } to_json(obj, s->str, s->pretty, s->indent); @@ -128,10 +122,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) break; case QTYPE_QINT: { QInt *val = qobject_to_qint(obj); - char buffer[1024]; - - snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); - qstring_append(str, buffer); + qstring_append_printf(str, "%" PRId64, qint_get_int(val)); break; } case QTYPE_QSTRING: { @@ -152,10 +143,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) qstring_append(str, "{"); qdict_iter(val, to_json_dict_iter, &s); if (pretty) { - int j; - qstring_append(str, "\n"); - for (j = 0 ; j < indent ; j++) - qstring_append(str, " "); + qstring_append_printf(str, "\n%*s", 4 * indent, ""); } qstring_append(str, "}"); break; @@ -171,10 +159,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) qstring_append(str, "["); qlist_iter(val, (void *)to_json_list_iter, &s); if (pretty) { - int j; - qstring_append(str, "\n"); - for (j = 0 ; j < indent ; j++) - qstring_append(str, " "); + qstring_append_printf(str, "\n%*s", 4 * indent, ""); } qstring_append(str, "]"); break; @@ -230,7 +215,6 @@ int qstring_append_json_string(QString *qstring, const char *str) { const char *ptr; int cp; - char buf[16]; char *end; int result = 0; @@ -267,16 +251,14 @@ int qstring_append_json_string(QString *qstring, const char *str) } if (cp > 0xFFFF) { /* beyond BMP; need a surrogate pair */ - snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", - 0xD800 + ((cp - 0x10000) >> 10), - 0xDC00 + ((cp - 0x10000) & 0x3FF)); + qstring_append_printf(qstring, "\\u%04X\\u%04X", + 0xD800 + ((cp - 0x10000) >> 10), + 0xDc00 + ((cp - 0x10000) & 0x3FF)); } else if (cp < 0x20 || cp >= 0x7F) { - snprintf(buf, sizeof(buf), "\\u%04X", cp); + qstring_append_printf(qstring, "\\u%04X", cp); } else { - buf[0] = cp; - buf[1] = 0; + qstring_append_chr(qstring, cp); } - qstring_append(qstring, buf); } }; diff --git a/qobject/qstring.c b/qobject/qstring.c index 5da7b5f..fbfae27 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -1,7 +1,7 @@ /* * QString Module * - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009-2016 Red Hat Inc. * * Authors: * Luiz Capitulino @@ -88,12 +88,28 @@ void qstring_append(QString *qstring, const char *str) qstring->string[qstring->length] = 0; } -void qstring_append_int(QString *qstring, int64_t value) +void qstring_append_printf(QString *qstring, const char *fmt, ...) { - char num[32]; + va_list ap; - snprintf(num, sizeof(num), "%" PRId64, value); - qstring_append(qstring, num); + va_start(ap, fmt); + qstring_append_vprintf(qstring, fmt, ap); + va_end(ap); +} + +void qstring_append_vprintf(QString *qstring, const char *fmt, va_list ap) +{ + va_list ap2; + int len; + + va_copy(ap2, ap); + len = vsnprintf(NULL, 0, fmt, ap2); + assert(len >= 0); + va_end(ap2); + + capacity_increase(qstring, len); + vsnprintf(qstring->string + qstring->length, len + 1, fmt, ap); + qstring->length += len; } /**