qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject
@ 2009-10-17  7:55 Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 1/7] add qemu_memdup Paolo Bonzini
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel

This patch adds to the QObject system a method to encode JSON
objects.  It also adds printf-like capabilities where you can
write %{a.b} in a format string and the method will walk a
QDict to find the "a" first and "b" in a QDict inside that one
(and then print what's found).

Since QEMU does not have (or I could not find...) a variable-length
string buffer object, I added that to QString, thus making it mutable.
I talked to Luiz and he mentioned that QString were immutable not
by design, but rather due to not having the need so far.

Paolo Bonzini (7):
    add qemu_memdup
    allow passing NULL to qobject_type
    forward declare all QObject subclasses in qobject.h
    add mutable qstring functions
    add json encoder for qobjects
    add testsuite for qobject json encoder
    add formatted printing of QObjects

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 1/7] add qemu_memdup
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type Paolo Bonzini
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

A nice-to-have utility function, it helps avoiding useless strlen+strdup
pairs.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-common.h |    1 +
 qemu-malloc.c |    8 ++++++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/qemu-common.h b/qemu-common.h
index 820dd37..351f1ac 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -141,6 +141,7 @@ void *qemu_realloc(void *ptr, size_t size);
 void *qemu_mallocz(size_t size);
 void qemu_free(void *ptr);
 char *qemu_strdup(const char *str);
+void *qemu_memdup(const void *str, size_t size);
 char *qemu_strndup(const char *str, size_t size);
 
 void *get_mmap_addr(unsigned long size);
diff --git a/qemu-malloc.c b/qemu-malloc.c
index 295d185..9e11e4b 100644
--- a/qemu-malloc.c
+++ b/qemu-malloc.c
@@ -70,6 +70,14 @@ void *qemu_mallocz(size_t size)
     return ptr;
 }
 
+void *qemu_memdup(const void *str, size_t n)
+{
+    char *ptr;
+    ptr = qemu_malloc(n);
+    memcpy(ptr, str, n);
+    return ptr;
+}
+
 char *qemu_strdup(const char *str)
 {
     char *ptr;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 1/7] add qemu_memdup Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h Paolo Bonzini
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qobject.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/qobject.h b/qobject.h
index 4cc9287..200644d 100644
--- a/qobject.h
+++ b/qobject.h
@@ -102,6 +102,8 @@ static inline void qobject_decref(QObject *obj)
  */
 static inline qtype_code qobject_type(const QObject *obj)
 {
+    if (!obj)
+        return QTYPE_NONE;
     assert(obj->type != NULL);
     return obj->type->code;
 }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 1/7] add qemu_memdup Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17 13:02   ` Anthony Liguori
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 4/7] add mutable qstring functions Paolo Bonzini
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

This gives more freedom to define prototypes without dragging in
the whole header files.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qobject.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/qobject.h b/qobject.h
index 200644d..f5c78b2 100644
--- a/qobject.h
+++ b/qobject.h
@@ -44,6 +44,10 @@ typedef enum {
 } qtype_code;
 
 struct QObject;
+struct QInt;
+struct QString;
+struct QDict;
+struct QList;
 
 typedef struct QType {
     qtype_code code;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 4/7] add mutable qstring functions
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
                   ` (2 preceding siblings ...)
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17 13:03   ` Anthony Liguori
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 5/7] add json encoder for qobjects Paolo Bonzini
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

qemu does not have a string buffer object, so I added this capability
to QString.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 check-qstring.c |   79 ++++++++++++++++++++++++++++++++++++++++-
 qstring.c       |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 qstring.h       |    5 +++
 3 files changed, 186 insertions(+), 3 deletions(-)

diff --git a/check-qstring.c b/check-qstring.c
index ea4dfd0..842cd7f 100644
--- a/check-qstring.c
+++ b/check-qstring.c
@@ -17,6 +17,23 @@
  * (with some violations to access 'private' data)
  */
 
+START_TEST(qstring_new_test)
+{
+    QString *qstring;
+
+    qstring = qstring_new();
+    fail_unless(qstring != NULL);
+    fail_unless(qstring->base.refcnt == 1);
+    fail_unless(qstring->n == 0);
+    fail_unless(qstring->alloc < 1000);
+    fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
+
+    // destroy doesn't exit yet
+    qemu_free(qstring->string);
+    qemu_free(qstring);
+}
+END_TEST
+
 START_TEST(qstring_from_str_test)
 {
     QString *qstring;
@@ -25,7 +42,9 @@ START_TEST(qstring_from_str_test)
     qstring = qstring_from_str(str);
     fail_unless(qstring != NULL);
     fail_unless(qstring->base.refcnt == 1);
-    fail_unless(strcmp(str, qstring->string) == 0);
+    fail_unless(qstring->n == 4);
+    fail_unless(qstring->alloc >= 4);
+    fail_unless(memcmp(str, qstring->string, 4) == 0);
     fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
 
     // destroy doesn't exit yet
@@ -55,6 +74,60 @@ START_TEST(qstring_get_str_test)
 }
 END_TEST
 
+START_TEST(qstring_append_test)
+{
+    QString *qstring;
+    const char *str = "QEM";
+    const char *longstr = "QEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMU";
+
+    qstring = qstring_from_str(str);
+    qstring_append(qstring, "U");
+    fail_unless(qstring->n == 4);
+    fail_unless(qstring->alloc >= 4);
+    fail_unless(memcmp(longstr, qstring->string, 4) == 0);
+
+    qstring_append(qstring, "Q");
+    fail_unless(qstring->n == 5);
+    fail_unless(qstring->alloc >= 5);
+    fail_unless(memcmp(longstr, qstring->string, 5) == 0);
+
+    qstring_append(qstring, longstr + 5);
+    fail_unless(qstring->n == strlen (longstr));
+    fail_unless(qstring->alloc >= qstring->n);
+    fail_unless(memcmp(longstr, qstring->string, qstring->n) == 0);
+    QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_append_ch_test)
+{
+    QString *qstring;
+    const char *str = "QEM";
+
+    qstring = qstring_from_str(str);
+    qstring_append_ch(qstring, 'U');
+    fail_unless(qstring->n == 4);
+    fail_unless(qstring->alloc >= 4);
+    fail_unless(memcmp("QEMU", qstring->string, 4) == 0);
+    QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_append_escaped_test)
+{
+    QString *qstring;
+    const char *str = "\"Q\x0EMU\t";
+    const char *result = "\\\"Q\\u000eMU\\t";
+
+    qstring = qstring_new();
+    qstring_append_escaped(qstring, str);
+    fail_unless(qstring->n == strlen (result));
+    fail_unless(qstring->alloc >= qstring->n);
+    fail_unless(memcmp(result, qstring->string, strlen (result)) == 0);
+    QDECREF(qstring);
+}
+END_TEST
+
 START_TEST(qobject_to_qstring_test)
 {
     QString *qstring;
@@ -75,9 +148,13 @@ static Suite *qstring_suite(void)
 
     qstring_public_tcase = tcase_create("Public Interface");
     suite_add_tcase(s, qstring_public_tcase);
+    tcase_add_test(qstring_public_tcase, qstring_new_test);
     tcase_add_test(qstring_public_tcase, qstring_from_str_test);
     tcase_add_test(qstring_public_tcase, qstring_destroy_test);
     tcase_add_test(qstring_public_tcase, qstring_get_str_test);
+    tcase_add_test(qstring_public_tcase, qstring_append_test);
+    tcase_add_test(qstring_public_tcase, qstring_append_ch_test);
+    tcase_add_test(qstring_public_tcase, qstring_append_escaped_test);
     tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
 
     return s;
diff --git a/qstring.c b/qstring.c
index 6d411da..ab77fba 100644
--- a/qstring.c
+++ b/qstring.c
@@ -21,6 +21,29 @@ static const QType qstring_type = {
 };
 
 /**
+ * Invariant: all strings have an empty byte at the end so that
+ * it is easy to convert them to C strings.
+ */
+
+
+/**
+ * qstring_new(): Create a new empty QString
+ *
+ * Return strong reference.
+ */
+QString *qstring_new(void)
+{
+    QString *qstring;
+    qstring = qemu_malloc(sizeof(*qstring));
+    qstring->n = 0;
+    qstring->alloc = 16;
+    qstring->string = qemu_malloc(qstring->alloc);
+    QOBJECT_INIT(qstring, &qstring_type);
+
+    return qstring;
+}
+
+/**
  * qstring_from_str(): Create a new QString from a regular C string
  *
  * Return strong reference.
@@ -28,15 +51,91 @@ static const QType qstring_type = {
 QString *qstring_from_str(const char *str)
 {
     QString *qstring;
+    size_t n = strlen(str);
 
     qstring = qemu_malloc(sizeof(*qstring));
-    qstring->string = qemu_strdup(str);
+    qstring->n = n;
+    qstring->alloc = n + 1;
+    qstring->string = qemu_memdup(str, qstring->alloc);
     QOBJECT_INIT(qstring, &qstring_type);
 
     return qstring;
 }
 
 /**
+ * qstring_append(): Append a regular C string to a QString
+ */
+void qstring_append(QString *qstring, const char *str)
+{
+    size_t n = strlen(str);
+    size_t total = qstring->n + n + 1;
+
+    if (total > qstring->alloc) {
+        if (qstring->alloc * 2 < total) {
+            qstring->alloc = total;
+        } else {
+            qstring->alloc *= 2;
+        }
+        qstring->string = qemu_realloc (qstring->string, qstring->alloc);
+    }
+    memcpy (qstring->string + qstring->n, str, n + 1);
+    qstring->n += n;
+}
+
+/**
+ * qstring_append(): Append a regular C string to a QString, escaping it
+ * according to JSON syntax.
+ */
+void qstring_append_escaped(QString *qstring, const char *str)
+{
+    for (; *str; str++) {
+        unsigned char ch = *str;
+        switch (*str) {
+        case '\f': ch = 'f'; goto backslash;
+        case '\n': ch = 'n'; goto backslash;
+        case '\r': ch = 'r'; goto backslash;
+        case '\t': ch = 't'; goto backslash;
+        case '\b': ch = 'b'; goto backslash;
+
+        backslash:
+        case '\\':
+        case '\"':
+            qstring_append_ch (qstring, '\\');
+            break;
+
+        default:
+            if (ch < 0x20) {
+                    qstring_append_ch (qstring, '\\');
+                    qstring_append_ch (qstring, 'u');
+                    qstring_append_ch (qstring, '0');
+                    qstring_append_ch (qstring, '0');
+                    qstring_append_ch (qstring, '0' + (ch >> 4));
+                    ch = (ch & 15) + ((ch & 15) > 9 ? 'a' - 10 : '0');
+            }
+            break;
+        }
+
+        qstring_append_ch (qstring, ch);
+    }
+}
+
+/**
+ * qstring_append_ch(): Append a character to a QString
+ */
+void qstring_append_ch(QString *qstring, char c)
+{
+    if (qstring->n == qstring->alloc - 1) {
+        if (qstring->alloc < 10) {
+            qstring->alloc = 10;
+        } else {
+            qstring->alloc *= 2;
+        }
+        qstring->string = qemu_realloc (qstring->string, qstring->alloc);
+    }
+    qstring->string[qstring->n++] = c;
+}
+
+/**
  * qobject_to_qstring(): Convert a QObject to a QString
  */
 QString *qobject_to_qstring(const QObject *obj)
@@ -51,10 +150,12 @@ QString *qobject_to_qstring(const QObject *obj)
  * qstring_get_str(): Return a pointer to the stored string
  *
  * NOTE: Should be used with caution, if the object is deallocated
- * this pointer becomes invalid.
+ * or modified this pointer becomes invalid.
  */
 const char *qstring_get_str(const QString *qstring)
 {
+    /* NULL-terminate it here.  */
+    qstring->string[qstring->n] = 0;
     return qstring->string;
 }
 
diff --git a/qstring.h b/qstring.h
index e012cb7..6e16d58 100644
--- a/qstring.h
+++ b/qstring.h
@@ -5,11 +5,16 @@
 
 typedef struct QString {
     QObject_HEAD;
+    size_t n, alloc;
     char *string;
 } QString;
 
+QString *qstring_new(void);
 QString *qstring_from_str(const char *str);
 const char *qstring_get_str(const QString *qstring);
+void qstring_append(QString *qstring, const char *str);
+void qstring_append_escaped(QString *qstring, const char *str);
+void qstring_append_ch(QString *qstring, char c);
 QString *qobject_to_qstring(const QObject *obj);
 
 #endif /* QSTRING_H */
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 5/7] add json encoder for qobjects
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
                   ` (3 preceding siblings ...)
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 4/7] add mutable qstring functions Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17 13:03   ` Anthony Liguori
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects Paolo Bonzini
  6 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

The JSON encoder is just a virtual method on QObject.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile  |    4 ++--
 qdict.c   |   32 ++++++++++++++++++++++++++++++++
 qint.c    |   16 ++++++++++++++++
 qlist.c   |   28 ++++++++++++++++++++++++++++
 qobject.h |   10 ++++++++++
 qstring.c |   32 ++++++++++++++++++++++++++++++++
 qstring.h |    5 +++++
 7 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 7d4d75c..2447d23 100644
--- a/Makefile
+++ b/Makefile
@@ -210,10 +210,10 @@ qemu-io$(EXESUF):  qemu-io.o qemu-tool.o cmd.o $(block-obj-y)
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
-check-qint: check-qint.o qint.o qemu-malloc.o
+check-qint: check-qint.o qint.o qstring.o qemu-malloc.o
 check-qstring: check-qstring.o qstring.o qemu-malloc.o
 check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o
-check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
+check-qlist: check-qlist.o qlist.o qint.o qstring.o qemu-malloc.o
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
diff --git a/qdict.c b/qdict.c
index a302f4c..efbc53d 100644
--- a/qdict.c
+++ b/qdict.c
@@ -18,10 +18,12 @@
 #include "qemu-common.h"
 
 static void qdict_destroy_obj(QObject *obj);
+static void qdict_encode_json(const QObject *obj, QString *str);
 
 static const QType qdict_type = {
     .code = QTYPE_QDICT,
     .destroy = qdict_destroy_obj,
+    .encode_json = qdict_encode_json,
 };
 
 /**
@@ -295,3 +297,33 @@ static void qdict_destroy_obj(QObject *obj)
 
     qemu_free(qdict);
 }
+
+/**
+ * qdict_encode_json(): Encode the dictionary to JSON on a QString.
+ */
+static void qdict_encode_json(const QObject *obj, QString *str)
+{
+    int i, first;
+    const QDict *qdict;
+
+    assert(obj != NULL);
+    qdict = qobject_to_qdict((QObject *) obj);
+
+    qstring_append_ch (str, '{');
+    for (first = 1, i = 0; i < QDICT_HASH_SIZE; i++) {
+        QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
+        while (entry) {
+            if (!first)
+                qstring_append_ch (str, ',');
+            qstring_append_ch (str, '"');
+            qstring_append_escaped (str, entry->key);
+            qstring_append_ch (str, '"');
+            qstring_append_ch (str, ':');
+            qobject_encode_json (entry->value, str);
+            entry = QLIST_NEXT(entry, next);
+            first = 0;
+        }
+    }
+
+    qstring_append_ch (str, '}');
+}
diff --git a/qint.c b/qint.c
index 447e847..b5ceea3 100644
--- a/qint.c
+++ b/qint.c
@@ -10,14 +10,17 @@
  * the COPYING file in the top-level directory.
  */
 #include "qint.h"
+#include "qstring.h"
 #include "qobject.h"
 #include "qemu-common.h"
 
 static void qint_destroy_obj(QObject *obj);
+static void qint_encode_json(const QObject *obj, QString *str);
 
 static const QType qint_type = {
     .code = QTYPE_QINT,
     .destroy = qint_destroy_obj,
+    .encode_json = qint_encode_json,
 };
 
 /**
@@ -64,3 +67,16 @@ static void qint_destroy_obj(QObject *obj)
     assert(obj != NULL);
     qemu_free(qobject_to_qint(obj));
 }
+
+/**
+ * qint_encode_json(): Encode the integer to JSON on a QString.
+ */
+static void qint_encode_json(const QObject *obj, QString *str)
+{
+    char buf[32];
+    QInt *qint;
+
+    qint = qobject_to_qint((QObject *) obj);
+    sprintf (buf, "%" PRId64, qint->value);
+    qstring_append (str, buf);
+}
diff --git a/qlist.c b/qlist.c
index ba2c66c..4c7e1b2 100644
--- a/qlist.c
+++ b/qlist.c
@@ -10,15 +10,18 @@
  * the COPYING file in the top-level directory.
  */
 #include "qlist.h"
+#include "qstring.h"
 #include "qobject.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
 
 static void qlist_destroy_obj(QObject *obj);
+static void qlist_encode_json(const QObject *obj, QString *str);
 
 static const QType qlist_type = {
     .code = QTYPE_QLIST,
     .destroy = qlist_destroy_obj,
+    .encode_json = qlist_encode_json,
 };
  
 /**
@@ -98,3 +101,28 @@ static void qlist_destroy_obj(QObject *obj)
 
     qemu_free(qlist);
 }
+
+/**
+ * qlist_encode_json(): Encode the list to JSON on a QString.
+ */
+static void qlist_encode_json(const QObject *obj, QString *str)
+{
+    const QList *qlist;
+    QListEntry *entry;
+    int first;
+
+    assert(obj != NULL);
+    qlist = qobject_to_qlist((QObject *) obj);
+
+    first = 1;
+    qstring_append_ch (str, '[');
+    QTAILQ_FOREACH(entry, &qlist->head, next) {
+        if (!first)
+            qstring_append_ch (str, ',');
+        qobject_encode_json (entry->value, str);
+        first = 0;
+    }
+
+    qstring_append_ch (str, ']');
+}
+
diff --git a/qobject.h b/qobject.h
index f5c78b2..d941a73 100644
--- a/qobject.h
+++ b/qobject.h
@@ -52,6 +52,7 @@ struct QList;
 typedef struct QType {
     qtype_code code;
     void (*destroy)(struct QObject *);
+    void (*encode_json)(const struct QObject *, struct QString *);
 } QType;
 
 typedef struct QObject {
@@ -112,4 +113,13 @@ static inline qtype_code qobject_type(const QObject *obj)
     return obj->type->code;
 }
 
+/**
+ * qobject_type(): Return the QObject's type
+ */
+static inline void qobject_encode_json(const QObject *obj, struct QString *str)
+{
+    assert(obj->type != NULL);
+    obj->type->encode_json (obj, str);
+}
+
 #endif /* QOBJECT_H */
diff --git a/qstring.c b/qstring.c
index ab77fba..10c1952 100644
--- a/qstring.c
+++ b/qstring.c
@@ -14,10 +14,12 @@
 #include "qemu-common.h"
 
 static void qstring_destroy_obj(QObject *obj);
+static void qstring_encode_json(const QObject *obj, QString *str);
 
 static const QType qstring_type = {
     .code = QTYPE_QSTRING,
     .destroy = qstring_destroy_obj,
+    .encode_json = qstring_encode_json,
 };
 
 /**
@@ -63,6 +65,22 @@ QString *qstring_from_str(const char *str)
 }
 
 /**
+ * qstring_json_from_qobject_obj(): Encode a QObject as JSON and return
+ * a QString with the result.
+ *
+ * Return strong reference.
+ */
+QString *qstring_json_from_qobject_obj(const QObject *qobject)
+{
+    QString *qstring;
+
+    qstring = qstring_new();
+    qobject_encode_json(qobject, qstring);
+    return qstring;
+}
+
+
+/**
  * qstring_append(): Append a regular C string to a QString
  */
 void qstring_append(QString *qstring, const char *str)
@@ -172,3 +190,17 @@ static void qstring_destroy_obj(QObject *obj)
     qemu_free(qs->string);
     qemu_free(qs);
 }
+
+/**
+ * qstring_encode_json(): Encode the string to JSON on a QString.
+ */
+static void qstring_encode_json(const QObject *obj, QString *str)
+{
+    QString *qstring;
+
+    assert(obj != NULL);
+    qstring = qobject_to_qstring((QObject *) obj);
+    qstring_append_ch (str, '"');
+    qstring_append_escaped (str, qstring_get_str(qstring));
+    qstring_append_ch (str, '"');
+}
diff --git a/qstring.h b/qstring.h
index 6e16d58..efc1d7a 100644
--- a/qstring.h
+++ b/qstring.h
@@ -11,6 +11,11 @@ typedef struct QString {
 
 QString *qstring_new(void);
 QString *qstring_from_str(const char *str);
+QString *qstring_json_from_qobject_obj(const QObject *obj);
+
+#define qstring_json_from_qobject(obj) \
+        qstring_json_from_qobject_obj(QOBJECT(obj))
+
 const char *qstring_get_str(const QString *qstring);
 void qstring_append(QString *qstring, const char *str);
 void qstring_append_escaped(QString *qstring, const char *str);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
                   ` (4 preceding siblings ...)
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 5/7] add json encoder for qobjects Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects Paolo Bonzini
  6 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

And finally, a small testsuite using check as the rest of the QObject
framework.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile     |    1 +
 check-json.c |  123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure    |    2 +-
 3 files changed, 125 insertions(+), 1 deletions(-)
 create mode 100644 check-json.c

diff --git a/Makefile b/Makefile
index 2447d23..2483057 100644
--- a/Makefile
+++ b/Makefile
@@ -210,6 +210,7 @@ qemu-io$(EXESUF):  qemu-io.o qemu-tool.o cmd.o $(block-obj-y)
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
+check-json: check-json.o qint.o qstring.o qdict.o qlist.o qemu-malloc.o
 check-qint: check-qint.o qint.o qstring.o qemu-malloc.o
 check-qstring: check-qstring.o qstring.o qemu-malloc.o
 check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o
diff --git a/check-json.c b/check-json.c
new file mode 100644
index 0000000..9f4cfbe
--- /dev/null
+++ b/check-json.c
@@ -0,0 +1,123 @@
+/*
+ * QObject JSON unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Paolo Bonzini <pbonzini@redhat.com>
+ */
+#include <check.h>
+
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qstring.h"
+#include "qemu-common.h"
+
+#define json_expect(qobj, expected)                             \
+  do {                                                          \
+    QString *result = qstring_json_from_qobject (qobj);         \
+    fail_unless (!strcmp (qstring_get_str (result), expected)); \
+    QDECREF(result);                                            \
+  } while (0)
+
+START_TEST(qint_json_test)
+{
+    QInt *qi;
+
+    qi = qint_from_int(42);
+    json_expect(qi,"42");
+    QDECREF(qi);
+}
+END_TEST
+
+START_TEST(qstr_json_test)
+{
+    const char *str = "\\\"\b\n\r\f\t\v\a\x19X\xc3\x80";
+    QString *qstr;
+
+    qstr = qstring_from_str(str);
+    json_expect(qstr,"\"\\\\\\\"\\b\\n\\r\\f\\t\\u000b\\u0007\\u0019X\xc3\x80\"");
+    QDECREF(qstr);
+}
+END_TEST
+
+START_TEST(qdict_json_test)
+{
+    QDict *qdict;
+
+    qdict = qdict_new();
+    json_expect(qdict,"{}");
+    qdict_put_obj(qdict, "", QOBJECT(qint_from_int(42)));
+    json_expect(qdict,"{\"\":42}");
+    qdict_put_obj(qdict, "\t", QOBJECT(qint_from_int(0)));
+    json_expect(qdict,"{\"\\t\":0,\"\":42}");
+    qdict_put_obj(qdict, "\xc3\x80", QOBJECT(qstring_from_str("foo\n")));
+    json_expect(qdict,"{\"\xc3\x80\":\"foo\\n\",\"\\t\":0,\"\":42}");
+    QDECREF(qdict);
+}
+END_TEST
+
+START_TEST(qlist_json_test)
+{
+    QList *qlist;
+
+    qlist = qlist_new();
+    json_expect(qlist,"[]");
+    qlist_append(qlist, qint_from_int(42));
+    json_expect(qlist,"[42]");
+    qlist_append(qlist, qstring_from_str("bar\t"));
+    json_expect(qlist,"[42,\"bar\\t\"]");
+    QDECREF(qlist);
+}
+END_TEST
+
+START_TEST(nested_json_test)
+{
+    QDict *qdict_in, *qdict_out;
+    QList *qlist;
+
+    qdict_in = qdict_new();
+    qdict_put_obj(qdict_in, "in", QOBJECT(qint_from_int(42)));
+    qlist = qlist_new();
+    qlist_append(qlist, qdict_in);
+    qdict_out = qdict_new();
+    qdict_put_obj(qdict_out, "out", QOBJECT(qlist));
+    json_expect(qdict_out,"{\"out\":[{\"in\":42}]}");
+    QDECREF(qdict_out);
+}
+END_TEST
+
+static Suite *QObject_json_suite(void)
+{
+    Suite *s;
+    TCase *qobject_json_tcase;
+
+    s = suite_create("QObject JSON suite");
+
+    qobject_json_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qobject_json_tcase);
+    tcase_add_test(qobject_json_tcase, qint_json_test);
+    tcase_add_test(qobject_json_tcase, qstr_json_test);
+    tcase_add_test(qobject_json_tcase, qdict_json_test);
+    tcase_add_test(qobject_json_tcase, qlist_json_test);
+    tcase_add_test(qobject_json_tcase, nested_json_test);
+
+    return s;
+}
+
+int main(void)
+{
+        int nf;
+        Suite *s;
+        SRunner *sr;
+
+        s = QObject_json_suite();
+        sr = srunner_create(s);
+
+        srunner_run_all(sr, CK_NORMAL);
+        nf = srunner_ntests_failed(sr);
+        srunner_free(sr);
+
+        return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/configure b/configure
index 7c7804b..3d00f2e 100755
--- a/configure
+++ b/configure
@@ -2024,7 +2024,7 @@ if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
   if [ "$linux" = "yes" ] ; then
       tools="qemu-nbd\$(EXESUF) qemu-io\$(EXESUF) $tools"
     if [ "$check_utests" = "yes" ]; then
-      tools="check-qint check-qstring check-qdict check-qlist $tools"
+      tools="check-qint check-qstring check-qdict check-qlist check-json $tools"
     fi
   elif test "$mingw32" = "yes" ; then
       tools="qemu-io\$(EXESUF) $tools"
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects
  2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
                   ` (5 preceding siblings ...)
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder Paolo Bonzini
@ 2009-10-17  7:55 ` Paolo Bonzini
  6 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17  7:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Luiz Capitulino

This patch adds a function to format a QDict according to a string
that is printf like but specifies how to navigate the QDict.  All
parts are printed as JSON, but this is fine since this will auto-escape
strings and integers print naturally.

More sophisticated flags can be added later, e.g. %#{foo} would
print a string without escaping.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile     |    6 +++---
 check-json.c |   39 +++++++++++++++++++++++++++++++++++++++
 qstring.c    |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 qstring.h    |    3 +++
 4 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 2483057..f98b70c 100644
--- a/Makefile
+++ b/Makefile
@@ -211,10 +211,10 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
 check-json: check-json.o qint.o qstring.o qdict.o qlist.o qemu-malloc.o
-check-qint: check-qint.o qint.o qstring.o qemu-malloc.o
-check-qstring: check-qstring.o qstring.o qemu-malloc.o
+check-qint: check-qint.o qint.o qstring.o qdict.o qemu-malloc.o
+check-qstring: check-qstring.o qint.o qstring.o qdict.o qemu-malloc.o
 check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o
-check-qlist: check-qlist.o qlist.o qint.o qstring.o qemu-malloc.o
+check-qlist: check-qlist.o qlist.o qint.o qstring.o qdict.o qemu-malloc.o
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
diff --git a/check-json.c b/check-json.c
index 9f4cfbe..eaff53b 100644
--- a/check-json.c
+++ b/check-json.c
@@ -21,6 +21,13 @@
     QDECREF(result);                                            \
   } while (0)
 
+#define format_expect(qobj, format, expected)                   \
+  do {                                                          \
+    QString *result = qstring_format (format, qobj);            \
+    fail_unless (!strcmp (qstring_get_str (result), expected)); \
+    QDECREF(result);                                            \
+  } while (0)
+
 START_TEST(qint_json_test)
 {
     QInt *qi;
@@ -88,6 +95,37 @@ START_TEST(nested_json_test)
 }
 END_TEST
 
+START_TEST(format_test)
+{
+    QDict *qdict_in, *qdict_out;
+    QList *qlist;
+
+    format_expect(NULL, "test", "test");
+    format_expect(NULL, "test %%", "test %");
+
+    qdict_in = qdict_new();
+    format_expect(qdict_in, "test %%", "test %");
+    format_expect(qdict_in, "test %{} test", "test {} test");
+    format_expect(qdict_in, "%%%{}%%", "%{}%");
+
+    qdict_put_obj(qdict_in, "in", QOBJECT(qint_from_int(42)));
+    format_expect(qdict_in, "%{}", "{\"in\":42}");
+    format_expect(qdict_in, "test %{in} test", "test 42 test");
+
+    qlist = qlist_new();
+    qlist_append(qlist, qdict_in);
+    QINCREF(qlist);
+
+    qdict_out = qdict_new();
+    qdict_put_obj(qdict_out, "list", QOBJECT(qlist));
+    qdict_put_obj(qdict_out, "in", QOBJECT(qdict_in));
+    format_expect(qdict_out, "%{list}", "[{\"in\":42}]");
+    format_expect(qdict_out, "%{in.in}", "42");
+    format_expect(qdict_out, "%{in.in}%{in.in}", "4242");
+    QDECREF(qdict_out);
+}
+END_TEST
+
 static Suite *QObject_json_suite(void)
 {
     Suite *s;
@@ -102,6 +140,7 @@ static Suite *QObject_json_suite(void)
     tcase_add_test(qobject_json_tcase, qdict_json_test);
     tcase_add_test(qobject_json_tcase, qlist_json_test);
     tcase_add_test(qobject_json_tcase, nested_json_test);
+    tcase_add_test(qobject_json_tcase, format_test);
 
     return s;
 }
diff --git a/qstring.c b/qstring.c
index 10c1952..90d9295 100644
--- a/qstring.c
+++ b/qstring.c
@@ -11,6 +11,7 @@
  */
 #include "qobject.h"
 #include "qstring.h"
+#include "qdict.h"
 #include "qemu-common.h"
 
 static void qstring_destroy_obj(QObject *obj);
@@ -79,6 +80,14 @@ QString *qstring_json_from_qobject_obj(const QObject *qobject)
     return qstring;
 }
 
+QString *qstring_format(const char *format, const QDict *root)
+{
+    QString *qstring;
+
+    qstring = qstring_new();
+    qstring_append_format(qstring, format, root);
+    return qstring;
+}
 
 /**
  * qstring_append(): Append a regular C string to a QString
@@ -137,6 +146,48 @@ void qstring_append_escaped(QString *qstring, const char *str)
     }
 }
 
+void qstring_append_format(QString *qstring, const char *format,
+                           const struct QDict *root)
+{
+    char buf[256], *p;
+    while (format && *format) {
+        const QObject *next = QOBJECT(root);
+
+        if (*format != '%' || *++format == '%') {
+            qstring_append_ch (qstring, *format++);
+            continue;
+        }
+        if (*format++ != '{')
+            abort ();
+
+        next = QOBJECT(root);
+        if (*format == '}') {
+            format++;
+        } else {
+            do {
+                if (qobject_type(next) != QTYPE_QDICT) {
+                    format = strchr (format, '}');
+                    if (!format) {
+                            return;
+                    }
+                    next = NULL;
+                } else {
+                    p = buf;
+                    while (*format != '.' && *format != '}')
+                        *p++ = *format++;
+                    *p = 0;
+                    next = qdict_get(qobject_to_qdict(next), buf);
+                }
+            } while (*format++ != '}');
+        }
+
+        if (next) {
+            qobject_encode_json(next, qstring);
+        }
+    }
+}
+
+
 /**
  * qstring_append_ch(): Append a character to a QString
  */
diff --git a/qstring.h b/qstring.h
index efc1d7a..2d1fec9 100644
--- a/qstring.h
+++ b/qstring.h
@@ -11,6 +11,7 @@ typedef struct QString {
 
 QString *qstring_new(void);
 QString *qstring_from_str(const char *str);
+QString *qstring_format(const char *format, const struct QDict *qdict);
 QString *qstring_json_from_qobject_obj(const QObject *obj);
 
 #define qstring_json_from_qobject(obj) \
@@ -18,6 +19,8 @@ QString *qstring_json_from_qobject_obj(const QObject *obj);
 
 const char *qstring_get_str(const QString *qstring);
 void qstring_append(QString *qstring, const char *str);
+void qstring_append_format(QString *qstring, const char *format,
+                           const struct QDict *qdict);
 void qstring_append_escaped(QString *qstring, const char *str);
 void qstring_append_ch(QString *qstring, char c);
 QString *qobject_to_qstring(const QObject *obj);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h Paolo Bonzini
@ 2009-10-17 13:02   ` Anthony Liguori
  0 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:02 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Luiz Capitulino

Paolo Bonzini wrote:
> This gives more freedom to define prototypes without dragging in
> the whole header files.
>
> Cc: Luiz Capitulino <lcapitulino@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  qobject.h |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/qobject.h b/qobject.h
> index 200644d..f5c78b2 100644
> --- a/qobject.h
> +++ b/qobject.h
> @@ -44,6 +44,10 @@ typedef enum {
>  } qtype_code;
>  
>  struct QObject;
> +struct QInt;
> +struct QString;
> +struct QDict;
> +struct QList;
>   

This seems like a layering violation to me.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] add mutable qstring functions
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 4/7] add mutable qstring functions Paolo Bonzini
@ 2009-10-17 13:03   ` Anthony Liguori
  0 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:03 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Luiz Capitulino

Paolo Bonzini wrote:
> qemu does not have a string buffer object, so I added this capability
> to QString.
>
> Cc: Luiz Capitulino <lcapitulino@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  check-qstring.c |   79 ++++++++++++++++++++++++++++++++++++++++-
>  qstring.c       |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  qstring.h       |    5 +++
>  3 files changed, 186 insertions(+), 3 deletions(-)
>
> diff --git a/check-qstring.c b/check-qstring.c
> index ea4dfd0..842cd7f 100644
> --- a/check-qstring.c
> +++ b/check-qstring.c
> @@ -17,6 +17,23 @@
>   * (with some violations to access 'private' data)
>   */
>  
> +START_TEST(qstring_new_test)
> +{
> +    QString *qstring;
> +
> +    qstring = qstring_new();
> +    fail_unless(qstring != NULL);
> +    fail_unless(qstring->base.refcnt == 1);
> +    fail_unless(qstring->n == 0);
> +    fail_unless(qstring->alloc < 1000);
> +    fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
> +
> +    // destroy doesn't exit yet
> +    qemu_free(qstring->string);
> +    qemu_free(qstring);
> +}
> +END_TEST
> +
>  START_TEST(qstring_from_str_test)
>  {
>      QString *qstring;
> @@ -25,7 +42,9 @@ START_TEST(qstring_from_str_test)
>      qstring = qstring_from_str(str);
>      fail_unless(qstring != NULL);
>      fail_unless(qstring->base.refcnt == 1);
> -    fail_unless(strcmp(str, qstring->string) == 0);
> +    fail_unless(qstring->n == 4);
> +    fail_unless(qstring->alloc >= 4);
> +    fail_unless(memcmp(str, qstring->string, 4) == 0);
>      fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
>  
>      // destroy doesn't exit yet
> @@ -55,6 +74,60 @@ START_TEST(qstring_get_str_test)
>  }
>  END_TEST
>  
> +START_TEST(qstring_append_test)
> +{
> +    QString *qstring;
> +    const char *str = "QEM";
> +    const char *longstr = "QEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMU";
> +
> +    qstring = qstring_from_str(str);
> +    qstring_append(qstring, "U");
> +    fail_unless(qstring->n == 4);
> +    fail_unless(qstring->alloc >= 4);
> +    fail_unless(memcmp(longstr, qstring->string, 4) == 0);
> +
> +    qstring_append(qstring, "Q");
> +    fail_unless(qstring->n == 5);
> +    fail_unless(qstring->alloc >= 5);
> +    fail_unless(memcmp(longstr, qstring->string, 5) == 0);
> +
> +    qstring_append(qstring, longstr + 5);
> +    fail_unless(qstring->n == strlen (longstr));
> +    fail_unless(qstring->alloc >= qstring->n);
> +    fail_unless(memcmp(longstr, qstring->string, qstring->n) == 0);
> +    QDECREF(qstring);
> +}
> +END_TEST
> +
> +START_TEST(qstring_append_ch_test)
> +{
> +    QString *qstring;
> +    const char *str = "QEM";
> +
> +    qstring = qstring_from_str(str);
> +    qstring_append_ch(qstring, 'U');
> +    fail_unless(qstring->n == 4);
> +    fail_unless(qstring->alloc >= 4);
> +    fail_unless(memcmp("QEMU", qstring->string, 4) == 0);
> +    QDECREF(qstring);
> +}
> +END_TEST
> +
> +START_TEST(qstring_append_escaped_test)
> +{
> +    QString *qstring;
> +    const char *str = "\"Q\x0EMU\t";
> +    const char *result = "\\\"Q\\u000eMU\\t";
> +
> +    qstring = qstring_new();
> +    qstring_append_escaped(qstring, str);
> +    fail_unless(qstring->n == strlen (result));
> +    fail_unless(qstring->alloc >= qstring->n);
> +    fail_unless(memcmp(result, qstring->string, strlen (result)) == 0);
> +    QDECREF(qstring);
> +}
> +END_TEST
> +
>  START_TEST(qobject_to_qstring_test)
>  {
>      QString *qstring;
> @@ -75,9 +148,13 @@ static Suite *qstring_suite(void)
>  
>      qstring_public_tcase = tcase_create("Public Interface");
>      suite_add_tcase(s, qstring_public_tcase);
> +    tcase_add_test(qstring_public_tcase, qstring_new_test);
>      tcase_add_test(qstring_public_tcase, qstring_from_str_test);
>      tcase_add_test(qstring_public_tcase, qstring_destroy_test);
>      tcase_add_test(qstring_public_tcase, qstring_get_str_test);
> +    tcase_add_test(qstring_public_tcase, qstring_append_test);
> +    tcase_add_test(qstring_public_tcase, qstring_append_ch_test);
> +    tcase_add_test(qstring_public_tcase, qstring_append_escaped_test);
>      tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
>  
>      return s;
> diff --git a/qstring.c b/qstring.c
> index 6d411da..ab77fba 100644
> --- a/qstring.c
> +++ b/qstring.c
> @@ -21,6 +21,29 @@ static const QType qstring_type = {
>  };
>  
>  /**
> + * Invariant: all strings have an empty byte at the end so that
> + * it is easy to convert them to C strings.
> + */
> +
> +
> +/**
> + * qstring_new(): Create a new empty QString
> + *
> + * Return strong reference.
> + */
> +QString *qstring_new(void)
> +{
> +    QString *qstring;
> +    qstring = qemu_malloc(sizeof(*qstring));
> +    qstring->n = 0;
> +    qstring->alloc = 16;
> +    qstring->string = qemu_malloc(qstring->alloc);
> +    QOBJECT_INIT(qstring, &qstring_type);
> +
> +    return qstring;
> +}
> +
> +/**
>   * qstring_from_str(): Create a new QString from a regular C string
>   *
>   * Return strong reference.
> @@ -28,15 +51,91 @@ static const QType qstring_type = {
>  QString *qstring_from_str(const char *str)
>  {
>      QString *qstring;
> +    size_t n = strlen(str);
>  
>      qstring = qemu_malloc(sizeof(*qstring));
> -    qstring->string = qemu_strdup(str);
> +    qstring->n = n;
> +    qstring->alloc = n + 1;
> +    qstring->string = qemu_memdup(str, qstring->alloc);
>      QOBJECT_INIT(qstring, &qstring_type);
>  
>      return qstring;
>  }
>  
>  /**
> + * qstring_append(): Append a regular C string to a QString
> + */
> +void qstring_append(QString *qstring, const char *str)
> +{
> +    size_t n = strlen(str);
> +    size_t total = qstring->n + n + 1;
> +
> +    if (total > qstring->alloc) {
> +        if (qstring->alloc * 2 < total) {
> +            qstring->alloc = total;
> +        } else {
> +            qstring->alloc *= 2;
> +        }
> +        qstring->string = qemu_realloc (qstring->string, qstring->alloc);
> +    }
> +    memcpy (qstring->string + qstring->n, str, n + 1);
> +    qstring->n += n;
> +}
> +
> +/**
> + * qstring_append(): Append a regular C string to a QString, escaping it
> + * according to JSON syntax.
> + */
> +void qstring_append_escaped(QString *qstring, const char *str)
> +{
> +    for (; *str; str++) {
> +        unsigned char ch = *str;
> +        switch (*str) {
> +        case '\f': ch = 'f'; goto backslash;
> +        case '\n': ch = 'n'; goto backslash;
> +        case '\r': ch = 'r'; goto backslash;
> +        case '\t': ch = 't'; goto backslash;
> +        case '\b': ch = 'b'; goto backslash;
> +
> +        backslash:
> +        case '\\':
> +        case '\"':
> +            qstring_append_ch (qstring, '\\');
> +            break;
> +
> +        default:
> +            if (ch < 0x20) {
> +                    qstring_append_ch (qstring, '\\');
> +                    qstring_append_ch (qstring, 'u');
> +                    qstring_append_ch (qstring, '0');
> +                    qstring_append_ch (qstring, '0');
> +                    qstring_append_ch (qstring, '0' + (ch >> 4));
> +                    ch = (ch & 15) + ((ch & 15) > 9 ? 'a' - 10 : '0');
> +            }
> +            break;
> +        }
> +
> +        qstring_append_ch (qstring, ch);
> +    }
> +}
>
>   

The json parser should do the escaping.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] add json encoder for qobjects
  2009-10-17  7:55 ` [Qemu-devel] [PATCH 5/7] add json encoder for qobjects Paolo Bonzini
@ 2009-10-17 13:03   ` Anthony Liguori
  2009-10-17 13:44     ` Paolo Bonzini
  0 siblings, 1 reply; 13+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:03 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Luiz Capitulino

Paolo Bonzini wrote:
> The JSON encoder is just a virtual method on QObject.
>   

I think it makes more sense as an external entity.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] add json encoder for qobjects
  2009-10-17 13:03   ` Anthony Liguori
@ 2009-10-17 13:44     ` Paolo Bonzini
  2009-10-17 16:20       ` Anthony Liguori
  0 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2009-10-17 13:44 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Luiz Capitulino

On 10/17/2009 03:03 PM, Anthony Liguori wrote:
>
> I think it makes more sense as an external entity.

Maybe... I just thought of it as a toString method that happens to emit 
JSON.

Paolo

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] add json encoder for qobjects
  2009-10-17 13:44     ` Paolo Bonzini
@ 2009-10-17 16:20       ` Anthony Liguori
  0 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2009-10-17 16:20 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Luiz Capitulino

Paolo Bonzini wrote:
> On 10/17/2009 03:03 PM, Anthony Liguori wrote:
>>
>> I think it makes more sense as an external entity.
>
> Maybe... I just thought of it as a toString method that happens to 
> emit JSON.

json is one representation of the monitor protocol.  I think we should 
attempt to design things so that there is a clear separate of 
representation from the implementation.

BTW, the next thing I'd like to do this weekend is write a QObject 
decoded based on the json parser.  So that you can do something like:

  int locked, readonly;
  char *file;

  err = qobject_unmarshal(obj, "{'locked': %i, 'file': %s, 'readonly': 
%i}", &locked, &file, &readonly);

I think this would tremendously simplify the monitor command 
implementations.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2009-10-17 16:20 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-17  7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
2009-10-17  7:55 ` [Qemu-devel] [PATCH 1/7] add qemu_memdup Paolo Bonzini
2009-10-17  7:55 ` [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type Paolo Bonzini
2009-10-17  7:55 ` [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h Paolo Bonzini
2009-10-17 13:02   ` Anthony Liguori
2009-10-17  7:55 ` [Qemu-devel] [PATCH 4/7] add mutable qstring functions Paolo Bonzini
2009-10-17 13:03   ` Anthony Liguori
2009-10-17  7:55 ` [Qemu-devel] [PATCH 5/7] add json encoder for qobjects Paolo Bonzini
2009-10-17 13:03   ` Anthony Liguori
2009-10-17 13:44     ` Paolo Bonzini
2009-10-17 16:20       ` Anthony Liguori
2009-10-17  7:55 ` [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder Paolo Bonzini
2009-10-17  7:55 ` [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).