All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.