qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 30/36] qtest: Avoid dynamic JSON in qmp_fd_sendv()


From: Eric Blake
Subject: [Qemu-devel] [PATCH 30/36] qtest: Avoid dynamic JSON in qmp_fd_sendv()
Date: Wed, 30 Nov 2016 13:44:48 -0600

The only format specifier left in any client of qmp() and friends
is %s.  Rather than having to make our JSON parser support varargs,
and use a conversion from string to QObject and back to string, we
can instead just directly build the string and substitute %s
ourselves.  With this, the final caller of qobject_from_jsonv() is
eliminated, and followup patches can simplify the parser.

Signed-off-by: Eric Blake <address@hidden>

---
Too bad glibc's strchrnul() is not universal; also, this patch
could avoid "%.*s" format shenanigans (with the nastiness of
converting ptrdiff_t to int) if we want to first enhance QString
to support a length-limited append primitive.
---
 tests/libqtest.c | 42 ++++++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index 22bf0ad..a9559d8 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -427,27 +427,37 @@ QDict *qtest_qmp_receive(QTestState *s)
  */
 static void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
 {
-    va_list ap_copy;
-    QObject *qobj;
+    QString *qstr;

-    /* Going through qobject ensures we escape strings properly.
-     * This seemingly unnecessary copy is required in case va_list
-     * is an array type.
+    if (!strchr(fmt, '%')) {
+        return qmp_fd_send(fd, fmt);
+    }
+
+    /* Construct a single string, turning %s in fmt into proper JSON
+     * strings.  For now, we don't support any other format specifiers.
      */
-    va_copy(ap_copy, ap);
-    qobj = qobject_from_jsonv(fmt, &ap_copy);
-    va_end(ap_copy);
+    qstr = qstring_new();
+    while (*fmt) {
+        /* Too bad strchrnul() is not universal */
+        const char *p = strchr(fmt, '%');

-    /* No need to send anything for an empty QObject.  */
-    if (qobj) {
-        QString *qstr = qobject_to_json(qobj);
-        const char *str = qstring_get_str(qstr);
+        if (!p) {
+            p = strchr(fmt, '\0');
+        }

-        qmp_fd_send(fd, str);
-
-        QDECREF(qstr);
-        qobject_decref(qobj);
+        assert(p - fmt < INT_MAX);
+        qstring_append_printf(qstr, "%.*s", (int)(p - fmt), fmt);
+        if (*p) {
+            assert(p[1] == 's');
+            p += 2;
+            qstring_append_json_string(qstr, va_arg(ap, const char *));
+        }
+        fmt = p;
     }
+
+    qmp_fd_send(fd, qstring_get_str(qstr));
+
+    QDECREF(qstr);
 }

 QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]