* [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).