All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments
@ 2009-11-11 17:28 Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack Anthony Liguori
                   ` (9 more replies)
  0 siblings, 10 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

QDECREF does not properly escape the macro arguments which can lead to
unexpected syntax errors.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 qobject.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/qobject.h b/qobject.h
index 4cc9287..76f669f 100644
--- a/qobject.h
+++ b/qobject.h
@@ -60,7 +60,7 @@ typedef struct QObject {
     QObject base
 
 /* Get the 'base' part of an object */
-#define QOBJECT(obj) (&obj->base)
+#define QOBJECT(obj) (&(obj)->base)
 
 /* High-level interface for qobject_incref() */
 #define QINCREF(obj)      \
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-12 15:33   ` Kevin Wolf
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 03/11] Allow strings to grow in size Anthony Liguori
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

This makes lists no longer invariant. It's a very useful bit of functionality
though.

To deal with the fact that lists are no longer invariant, introduce a deep
copy mechanism for lists.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 qlist.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qlist.h |    4 ++++
 2 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/qlist.c b/qlist.c
index ba2c66c..5fccb7d 100644
--- a/qlist.c
+++ b/qlist.c
@@ -37,6 +37,23 @@ QList *qlist_new(void)
     return qlist;
 }
 
+static void qlist_copy_elem(QObject *obj, void *opaque)
+{
+    QList *dst = opaque;
+
+    qobject_incref(obj);
+    qlist_append_obj(dst, obj);
+}
+
+QList *qlist_copy(QList *src)
+{
+    QList *dst = qlist_new();
+
+    qlist_iter(src, qlist_copy_elem, dst);
+
+    return dst;
+}
+
 /**
  * qlist_append_obj(): Append an QObject into QList
  *
@@ -67,6 +84,45 @@ void qlist_iter(const QList *qlist,
         iter(entry->value, opaque);
 }
 
+QObject *qlist_pop(QList *qlist)
+{
+    QListEntry *entry;
+    QObject *ret;
+
+    if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+        return NULL;
+    }
+
+    entry = QTAILQ_FIRST(&qlist->head);
+    QTAILQ_REMOVE(&qlist->head, entry, next);
+
+    ret = entry->value;
+    qemu_free(entry);
+
+    return ret;
+}
+
+QObject *qlist_peek(QList *qlist)
+{
+    QListEntry *entry;
+    QObject *ret;
+
+    if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+        return NULL;
+    }
+
+    entry = QTAILQ_FIRST(&qlist->head);
+
+    ret = entry->value;
+
+    return ret;
+}
+
+int qlist_empty(const QList *qlist)
+{
+    return QTAILQ_EMPTY(&qlist->head);
+}
+
 /**
  * qobject_to_qlist(): Convert a QObject into a QList
  */
diff --git a/qlist.h b/qlist.h
index 3eb1eb8..afdc446 100644
--- a/qlist.h
+++ b/qlist.h
@@ -30,9 +30,13 @@ typedef struct QList {
         qlist_append_obj(qlist, QOBJECT(obj))
 
 QList *qlist_new(void);
+QList *qlist_copy(QList *src);
 void qlist_append_obj(QList *qlist, QObject *obj);
 void qlist_iter(const QList *qlist,
                 void (*iter)(QObject *obj, void *opaque), void *opaque);
+QObject *qlist_pop(QList *qlist);
+QObject *qlist_peek(QList *qlist);
+int qlist_empty(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
 #endif /* QLIST_H */
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 03/11] Allow strings to grow in size
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 04/11] Add a QFloat datatype Anthony Liguori
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

This lets us use QString for building larger strings

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 qstring.c |   37 ++++++++++++++++++++++++++++++++++++-
 qstring.h |    4 ++++
 2 files changed, 40 insertions(+), 1 deletions(-)

diff --git a/qstring.c b/qstring.c
index 6d411da..441a9e6 100644
--- a/qstring.c
+++ b/qstring.c
@@ -21,6 +21,16 @@ static const QType qstring_type = {
 };
 
 /**
+ * qstring_new(): Create a new empty QString
+ *
+ * Return strong reference.
+ */
+QString *qstring_new(void)
+{
+    return qstring_from_str("");
+}
+
+/**
  * qstring_from_str(): Create a new QString from a regular C string
  *
  * Return strong reference.
@@ -30,12 +40,37 @@ QString *qstring_from_str(const char *str)
     QString *qstring;
 
     qstring = qemu_malloc(sizeof(*qstring));
-    qstring->string = qemu_strdup(str);
+
+    qstring->length = strlen(str);
+    qstring->capacity = qstring->length;
+
+    qstring->string = qemu_malloc(qstring->capacity + 1);
+    memcpy(qstring->string, str, qstring->length);
+    qstring->string[qstring->length] = 0;
+
     QOBJECT_INIT(qstring, &qstring_type);
 
     return qstring;
 }
 
+/* qstring_append(): Append a C string to a QString
+ */
+void qstring_append(QString *qstring, const char *str)
+{
+    size_t len = strlen(str);
+
+    if (qstring->capacity < (qstring->length + len)) {
+        qstring->capacity += len;
+        qstring->capacity *= 2; /* use exponential growth */
+
+        qstring->string = qemu_realloc(qstring->string, qstring->capacity + 1);
+    }
+
+    memcpy(qstring->string + qstring->length, str, len);
+    qstring->length += len;
+    qstring->string[qstring->length] = 0;
+}
+
 /**
  * qobject_to_qstring(): Convert a QObject to a QString
  */
diff --git a/qstring.h b/qstring.h
index e012cb7..65905d4 100644
--- a/qstring.h
+++ b/qstring.h
@@ -6,10 +6,14 @@
 typedef struct QString {
     QObject_HEAD;
     char *string;
+    size_t length;
+    size_t capacity;
 } 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);
 QString *qobject_to_qstring(const QObject *obj);
 
 #endif /* QSTRING_H */
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 04/11] Add a QFloat datatype
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 03/11] Allow strings to grow in size Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 05/11] Add unit test for QFloat Anthony Liguori
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile  |    3 +-
 qfloat.c  |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qfloat.h  |   29 +++++++++++++++++++++++
 qobject.h |    1 +
 4 files changed, 108 insertions(+), 1 deletions(-)
 create mode 100644 qfloat.c
 create mode 100644 qfloat.h

diff --git a/Makefile b/Makefile
index 30f1c9d..8d94fda 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,8 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
 obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
-obj-y += qint.o qstring.o qdict.o qlist.o qemu-config.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o
+obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
 obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
diff --git a/qfloat.c b/qfloat.c
new file mode 100644
index 0000000..05215f5
--- /dev/null
+++ b/qfloat.c
@@ -0,0 +1,76 @@
+/*
+ * QFloat Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qfloat.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static void qfloat_destroy_obj(QObject *obj);
+
+static const QType qfloat_type = {
+    .code = QTYPE_QFLOAT,
+    .destroy = qfloat_destroy_obj,
+};
+
+/**
+ * qfloat_from_int(): Create a new QFloat from a float
+ *
+ * Return strong reference.
+ */
+QFloat *qfloat_from_double(double value)
+{
+    QFloat *qf;
+
+    qf = qemu_malloc(sizeof(*qf));
+    qf->value = value;
+    QOBJECT_INIT(qf, &qfloat_type);
+
+    return qf;
+}
+
+/**
+ * qfloat_get_double(): Get the stored float
+ */
+double qfloat_get_double(const QFloat *qf)
+{
+    return qf->value;
+}
+
+/**
+ * qobject_to_qfloat(): Convert a QObject into a QFloat
+ */
+QFloat *qobject_to_qfloat(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QFLOAT)
+        return NULL;
+
+    return container_of(obj, QFloat, base);
+}
+
+/**
+ * qfloat_destroy_obj(): Free all memory allocated by a
+ * QFloat object
+ */
+static void qfloat_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    qemu_free(qobject_to_qfloat(obj));
+}
diff --git a/qfloat.h b/qfloat.h
new file mode 100644
index 0000000..9d67876
--- /dev/null
+++ b/qfloat.h
@@ -0,0 +1,29 @@
+/*
+ * QFloat Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QFLOAT_H
+#define QFLOAT_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QFloat {
+    QObject_HEAD;
+    double value;
+} QFloat;
+
+QFloat *qfloat_from_double(double value);
+double qfloat_get_double(const QFloat *qi);
+QFloat *qobject_to_qfloat(const QObject *obj);
+
+#endif /* QFLOAT_H */
diff --git a/qobject.h b/qobject.h
index 76f669f..67b03d0 100644
--- a/qobject.h
+++ b/qobject.h
@@ -41,6 +41,7 @@ typedef enum {
     QTYPE_QSTRING,
     QTYPE_QDICT,
     QTYPE_QLIST,
+    QTYPE_QFLOAT,
 } qtype_code;
 
 struct QObject;
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 05/11] Add unit test for QFloat
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (2 preceding siblings ...)
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 04/11] Add a QFloat datatype Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 06/11] Add a QBool type Anthony Liguori
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile       |    1 +
 check-qfloat.c |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure      |    1 +
 3 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 check-qfloat.c

diff --git a/Makefile b/Makefile
index 8d94fda..5662f9a 100644
--- a/Makefile
+++ b/Makefile
@@ -227,6 +227,7 @@ check-qint: check-qint.o qint.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-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
diff --git a/check-qfloat.c b/check-qfloat.c
new file mode 100644
index 0000000..3758700
--- /dev/null
+++ b/check-qfloat.c
@@ -0,0 +1,81 @@
+/*
+ * QFloat unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <check.h>
+
+#include "qfloat.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qfloat_from_double_test)
+{
+    QFloat *qf;
+    const double value = -42.23423;
+
+    qf = qfloat_from_double(value);
+    fail_unless(qf != NULL);
+    fail_unless(qf->value == value);
+    fail_unless(qf->base.refcnt == 1);
+    fail_unless(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
+
+    // destroy doesn't exit yet
+    qemu_free(qf);
+}
+END_TEST
+
+START_TEST(qfloat_destroy_test)
+{
+    QFloat *qf = qfloat_from_double(0.0);
+    QDECREF(qf);
+}
+END_TEST
+
+static Suite *qfloat_suite(void)
+{
+    Suite *s;
+    TCase *qfloat_public_tcase;
+
+    s = suite_create("QFloat test-suite");
+
+    qfloat_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qfloat_public_tcase);
+    tcase_add_test(qfloat_public_tcase, qfloat_from_double_test);
+    tcase_add_test(qfloat_public_tcase, qfloat_destroy_test);
+
+    return s;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s;
+    SRunner *sr;
+
+    s = qfloat_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 fb66246..55be0fb 100755
--- a/configure
+++ b/configure
@@ -2092,6 +2092,7 @@ if test `expr "$target_list" : ".*softmmu.*"` != 0 ; 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-qfloat $tools"
     fi
   elif test "$mingw32" = "yes" ; then
       tools="qemu-io\$(EXESUF) $tools"
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 06/11] Add a QBool type
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (3 preceding siblings ...)
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 05/11] Add unit test for QFloat Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 07/11] Add a lexer for JSON Anthony Liguori
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile  |    2 +-
 qbool.c   |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qbool.h   |   29 +++++++++++++++++++++++
 qobject.h |    1 +
 4 files changed, 107 insertions(+), 1 deletions(-)
 create mode 100644 qbool.c
 create mode 100644 qbool.h

diff --git a/Makefile b/Makefile
index 5662f9a..116cd70 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
 obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
-obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/qbool.c b/qbool.c
new file mode 100644
index 0000000..5ab734c
--- /dev/null
+++ b/qbool.c
@@ -0,0 +1,76 @@
+/*
+ * QBool Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qbool.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static void qbool_destroy_obj(QObject *obj);
+
+static const QType qbool_type = {
+    .code = QTYPE_QBOOL,
+    .destroy = qbool_destroy_obj,
+};
+
+/**
+ * qbool_from_int(): Create a new QBool from an int
+ *
+ * Return strong reference.
+ */
+QBool *qbool_from_int(int value)
+{
+    QBool *qb;
+
+    qb = qemu_malloc(sizeof(*qb));
+    qb->value = value;
+    QOBJECT_INIT(qb, &qbool_type);
+
+    return qb;
+}
+
+/**
+ * qbool_get_int(): Get the stored int
+ */
+int qbool_get_int(const QBool *qb)
+{
+    return qb->value;
+}
+
+/**
+ * qobject_to_qbool(): Convert a QObject into a QBool
+ */
+QBool *qobject_to_qbool(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QBOOL)
+        return NULL;
+
+    return container_of(obj, QBool, base);
+}
+
+/**
+ * qbool_destroy_obj(): Free all memory allocated by a
+ * QBool object
+ */
+static void qbool_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    qemu_free(qobject_to_qbool(obj));
+}
diff --git a/qbool.h b/qbool.h
new file mode 100644
index 0000000..fe66fcd
--- /dev/null
+++ b/qbool.h
@@ -0,0 +1,29 @@
+/*
+ * QBool Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QBOOL_H
+#define QBOOL_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QBool {
+    QObject_HEAD;
+    int value;
+} QBool;
+
+QBool *qbool_from_int(int value);
+int qbool_get_int(const QBool *qb);
+QBool *qobject_to_qbool(const QObject *obj);
+
+#endif /* QBOOL_H */
diff --git a/qobject.h b/qobject.h
index 67b03d0..2270ec1 100644
--- a/qobject.h
+++ b/qobject.h
@@ -42,6 +42,7 @@ typedef enum {
     QTYPE_QDICT,
     QTYPE_QLIST,
     QTYPE_QFLOAT,
+    QTYPE_QBOOL,
 } qtype_code;
 
 struct QObject;
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 07/11] Add a lexer for JSON
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (4 preceding siblings ...)
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 06/11] Add a QBool type Anthony Liguori
@ 2009-11-11 17:28 ` Anthony Liguori
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 08/11] Add a JSON message boundary identifier Anthony Liguori
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

Our JSON parser is a three stage parser.  The first stage tokenizes the stream
into a set of lexical tokens.  Since the lexical grammar is regular, we can
use a finite state machine to model it.  The state machine will emit tokens
as they are identified.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile     |    2 +-
 json-lexer.c |  327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 json-lexer.h |   50 +++++++++
 3 files changed, 378 insertions(+), 1 deletions(-)
 create mode 100644 json-lexer.c
 create mode 100644 json-lexer.h

diff --git a/Makefile b/Makefile
index 116cd70..e5ab879 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
 obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
-obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
 obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/json-lexer.c b/json-lexer.c
new file mode 100644
index 0000000..53697c5
--- /dev/null
+++ b/json-lexer.c
@@ -0,0 +1,327 @@
+/*
+ * JSON lexer
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qstring.h"
+#include "qlist.h"
+#include "qdict.h"
+#include "qint.h"
+#include "qemu-common.h"
+#include "json-lexer.h"
+
+/*
+ * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
+ * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
+ * 0|([1-9][0-9]*(.[0-9]+)?([eE]([-+])?[0-9]+))
+ * [{}\[\],:]
+ * [a-z]+
+ *
+ */
+
+enum json_lexer_state {
+    ERROR = 0,
+    IN_DONE_STRING,
+    IN_DQ_UCODE3,
+    IN_DQ_UCODE2,
+    IN_DQ_UCODE1,
+    IN_DQ_UCODE0,
+    IN_DQ_STRING_ESCAPE,
+    IN_DQ_STRING,
+    IN_SQ_UCODE3,
+    IN_SQ_UCODE2,
+    IN_SQ_UCODE1,
+    IN_SQ_UCODE0,
+    IN_SQ_STRING_ESCAPE,
+    IN_SQ_STRING,
+    IN_ZERO,
+    IN_DIGITS,
+    IN_DIGIT,
+    IN_EXP_E,
+    IN_MANTISSA,
+    IN_MANTISSA_DIGITS,
+    IN_NONZERO_NUMBER,
+    IN_NEG_NONZERO_NUMBER,
+    IN_KEYWORD,
+    IN_ESCAPE,
+    IN_ESCAPE_L,
+    IN_ESCAPE_LL,
+    IN_ESCAPE_DONE,
+    IN_WHITESPACE,
+    IN_OPERATOR_DONE,
+    IN_START,
+};
+
+#define TERMINAL(state) [0 ... 0x7F] = (state)
+
+static const uint8_t json_lexer[][256] =  {
+    [IN_DONE_STRING] = {
+        TERMINAL(JSON_STRING),
+    },
+
+    /* double quote string */
+    [IN_DQ_UCODE3] = {
+        ['0' ... '9'] = IN_DQ_STRING,
+        ['a' ... 'f'] = IN_DQ_STRING,
+        ['A' ... 'F'] = IN_DQ_STRING,
+    },
+    [IN_DQ_UCODE2] = {
+        ['0' ... '9'] = IN_DQ_UCODE3,
+        ['a' ... 'f'] = IN_DQ_UCODE3,
+        ['A' ... 'F'] = IN_DQ_UCODE3,
+    },
+    [IN_DQ_UCODE1] = {
+        ['0' ... '9'] = IN_DQ_UCODE2,
+        ['a' ... 'f'] = IN_DQ_UCODE2,
+        ['A' ... 'F'] = IN_DQ_UCODE2,
+    },
+    [IN_DQ_UCODE0] = {
+        ['0' ... '9'] = IN_DQ_UCODE1,
+        ['a' ... 'f'] = IN_DQ_UCODE1,
+        ['A' ... 'F'] = IN_DQ_UCODE1,
+    },
+    [IN_DQ_STRING_ESCAPE] = {
+        ['b'] = IN_DQ_STRING,
+        ['f'] =  IN_DQ_STRING,
+        ['n'] =  IN_DQ_STRING,
+        ['r'] =  IN_DQ_STRING,
+        ['t'] =  IN_DQ_STRING,
+        ['\''] = IN_DQ_STRING,
+        ['\"'] = IN_DQ_STRING,
+        ['u'] = IN_DQ_UCODE0,
+    },
+    [IN_DQ_STRING] = {
+        [1 ... 0xFF] = IN_DQ_STRING,
+        ['\\'] = IN_DQ_STRING_ESCAPE,
+        ['"'] = IN_DONE_STRING,
+    },
+
+    /* single quote string */
+    [IN_SQ_UCODE3] = {
+        ['0' ... '9'] = IN_SQ_STRING,
+        ['a' ... 'f'] = IN_SQ_STRING,
+        ['A' ... 'F'] = IN_SQ_STRING,
+    },
+    [IN_SQ_UCODE2] = {
+        ['0' ... '9'] = IN_SQ_UCODE3,
+        ['a' ... 'f'] = IN_SQ_UCODE3,
+        ['A' ... 'F'] = IN_SQ_UCODE3,
+    },
+    [IN_SQ_UCODE1] = {
+        ['0' ... '9'] = IN_SQ_UCODE2,
+        ['a' ... 'f'] = IN_SQ_UCODE2,
+        ['A' ... 'F'] = IN_SQ_UCODE2,
+    },
+    [IN_SQ_UCODE0] = {
+        ['0' ... '9'] = IN_SQ_UCODE1,
+        ['a' ... 'f'] = IN_SQ_UCODE1,
+        ['A' ... 'F'] = IN_SQ_UCODE1,
+    },
+    [IN_SQ_STRING_ESCAPE] = {
+        ['b'] = IN_SQ_STRING,
+        ['f'] =  IN_SQ_STRING,
+        ['n'] =  IN_SQ_STRING,
+        ['r'] =  IN_SQ_STRING,
+        ['t'] =  IN_SQ_STRING,
+        ['\''] = IN_SQ_STRING,
+        ['\"'] = IN_SQ_STRING,
+        ['u'] = IN_SQ_UCODE0,
+    },
+    [IN_SQ_STRING] = {
+        [1 ... 0xFF] = IN_SQ_STRING,
+        ['\\'] = IN_SQ_STRING_ESCAPE,
+        ['\''] = IN_DONE_STRING,
+    },
+
+    /* Zero */
+    [IN_ZERO] = {
+        TERMINAL(JSON_INTEGER),
+        ['0' ... '9'] = ERROR,
+        ['.'] = IN_MANTISSA,
+    },
+
+    /* Float */
+    [IN_DIGITS] = {
+        TERMINAL(JSON_FLOAT),
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_DIGIT] = {
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_EXP_E] = {
+        ['-'] = IN_DIGIT,
+        ['+'] = IN_DIGIT,
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_MANTISSA_DIGITS] = {
+        TERMINAL(JSON_FLOAT),
+        ['0' ... '9'] = IN_MANTISSA_DIGITS,
+        ['e'] = IN_EXP_E,
+        ['E'] = IN_EXP_E,
+    },
+
+    [IN_MANTISSA] = {
+        ['0' ... '9'] = IN_MANTISSA_DIGITS,
+    },
+
+    /* Number */
+    [IN_NONZERO_NUMBER] = {
+        TERMINAL(JSON_INTEGER),
+        ['0' ... '9'] = IN_NONZERO_NUMBER,
+        ['e'] = IN_EXP_E,
+        ['E'] = IN_EXP_E,
+        ['.'] = IN_MANTISSA,
+    },
+
+    [IN_NEG_NONZERO_NUMBER] = {
+        ['0'] = IN_ZERO,
+        ['1' ... '9'] = IN_NONZERO_NUMBER,
+    },
+
+    /* keywords */
+    [IN_KEYWORD] = {
+        TERMINAL(JSON_KEYWORD),
+        ['a' ... 'z'] = IN_KEYWORD,
+    },
+
+    /* whitespace */
+    [IN_WHITESPACE] = {
+        TERMINAL(JSON_SKIP),
+        [' '] = IN_WHITESPACE,
+        ['\t'] = IN_WHITESPACE,
+        ['\r'] = IN_WHITESPACE,
+        ['\n'] = IN_WHITESPACE,
+    },        
+
+    /* operator */
+    [IN_OPERATOR_DONE] = {
+        TERMINAL(JSON_OPERATOR),
+    },
+
+    /* escape */
+    [IN_ESCAPE_DONE] = {
+        TERMINAL(JSON_ESCAPE),
+    },
+
+    [IN_ESCAPE_LL] = {
+        ['d'] = IN_ESCAPE_DONE,
+    },
+
+    [IN_ESCAPE_L] = {
+        ['d'] = IN_ESCAPE_DONE,
+        ['l'] = IN_ESCAPE_LL,
+    },
+
+    [IN_ESCAPE] = {
+        ['d'] = IN_ESCAPE_DONE,
+        ['i'] = IN_ESCAPE_DONE,
+        ['p'] = IN_ESCAPE_DONE,
+        ['s'] = IN_ESCAPE_DONE,
+        ['f'] = IN_ESCAPE_DONE,
+        ['l'] = IN_ESCAPE_L,
+    },
+
+    /* top level rule */
+    [IN_START] = {
+        ['"'] = IN_DQ_STRING,
+        ['\''] = IN_SQ_STRING,
+        ['0'] = IN_ZERO,
+        ['1' ... '9'] = IN_NONZERO_NUMBER,
+        ['-'] = IN_NEG_NONZERO_NUMBER,
+        ['{'] = IN_OPERATOR_DONE,
+        ['}'] = IN_OPERATOR_DONE,
+        ['['] = IN_OPERATOR_DONE,
+        [']'] = IN_OPERATOR_DONE,
+        [','] = IN_OPERATOR_DONE,
+        [':'] = IN_OPERATOR_DONE,
+        ['a' ... 'z'] = IN_KEYWORD,
+        ['%'] = IN_ESCAPE,
+        [' '] = IN_WHITESPACE,
+        ['\t'] = IN_WHITESPACE,
+        ['\r'] = IN_WHITESPACE,
+        ['\n'] = IN_WHITESPACE,
+    },
+};
+
+void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
+{
+    lexer->emit = func;
+    lexer->state = IN_START;
+    lexer->token = qstring_new();
+}
+
+static int json_lexer_feed_char(JSONLexer *lexer, char ch)
+{
+    char buf[2];
+
+    lexer->x++;
+    if (ch == '\n') {
+        lexer->x = 0;
+        lexer->y++;
+    }
+
+    lexer->state = json_lexer[lexer->state][(uint8_t)ch];
+
+    switch (lexer->state) {
+    case JSON_OPERATOR:
+    case JSON_ESCAPE:
+    case JSON_INTEGER:
+    case JSON_FLOAT:
+    case JSON_KEYWORD:
+    case JSON_STRING:
+        lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
+    case JSON_SKIP:
+        lexer->state = json_lexer[IN_START][(uint8_t)ch];
+        QDECREF(lexer->token);
+        lexer->token = qstring_new();
+        break;
+    case ERROR:
+        return -EINVAL;
+    default:
+        break;
+    }
+
+    buf[0] = ch;
+    buf[1] = 0;
+
+    qstring_append(lexer->token, buf);
+
+    return 0;
+}
+
+int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
+{
+    size_t i;
+
+    for (i = 0; i < size; i++) {
+        int err;
+
+        err = json_lexer_feed_char(lexer, buffer[i]);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int json_lexer_flush(JSONLexer *lexer)
+{
+    return json_lexer_feed_char(lexer, 0);
+}
+
+void json_lexer_destroy(JSONLexer *lexer)
+{
+    QDECREF(lexer->token);
+}
diff --git a/json-lexer.h b/json-lexer.h
new file mode 100644
index 0000000..3b50c46
--- /dev/null
+++ b/json-lexer.h
@@ -0,0 +1,50 @@
+/*
+ * JSON lexer
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_LEXER_H
+#define QEMU_JSON_LEXER_H
+
+#include "qstring.h"
+#include "qlist.h"
+
+typedef enum json_token_type {
+    JSON_OPERATOR = 100,
+    JSON_INTEGER,
+    JSON_FLOAT,
+    JSON_KEYWORD,
+    JSON_STRING,
+    JSON_ESCAPE,
+    JSON_SKIP,
+} JSONTokenType;
+
+typedef struct JSONLexer JSONLexer;
+
+typedef void (JSONLexerEmitter)(JSONLexer *, QString *, JSONTokenType, int x, int y);
+
+struct JSONLexer
+{
+    JSONLexerEmitter *emit;
+    int state;
+    QString *token;
+    int x, y;
+};
+
+void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func);
+
+int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size);
+
+int json_lexer_flush(JSONLexer *lexer);
+
+void json_lexer_destroy(JSONLexer *lexer);
+
+#endif
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 08/11] Add a JSON message boundary identifier
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (5 preceding siblings ...)
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 07/11] Add a lexer for JSON Anthony Liguori
@ 2009-11-11 17:29 ` Anthony Liguori
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 09/11] Add a JSON parser Anthony Liguori
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

The second stage of our JSON parser is a simple state machine that identifies
individual JSON values by counting the levels of nesting of tokens.  It does
not perform grammar validation.  We use this to emit a full JSON value to the
parser.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile        |    1 +
 json-streamer.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 json-streamer.h |   39 ++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 0 deletions(-)
 create mode 100644 json-streamer.c
 create mode 100644 json-streamer.h

diff --git a/Makefile b/Makefile
index e5ab879..a2aab60 100644
--- a/Makefile
+++ b/Makefile
@@ -136,6 +136,7 @@ obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
 obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
+obj-y += json-streamer.o
 obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/json-streamer.c b/json-streamer.c
new file mode 100644
index 0000000..610ffea
--- /dev/null
+++ b/json-streamer.c
@@ -0,0 +1,88 @@
+/*
+ * JSON streaming support
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qlist.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qemu-common.h"
+#include "json-lexer.h"
+#include "json-streamer.h"
+
+static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
+{
+    JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
+    QDict *dict;
+
+    if (type == JSON_OPERATOR) {
+        switch (qstring_get_str(token)[0]) {
+        case '{':
+            parser->brace_count++;
+            break;
+        case '}':
+            parser->brace_count--;
+            break;
+        case '[':
+            parser->bracket_count++;
+            break;
+        case ']':
+            parser->bracket_count--;
+            break;
+        default:
+            break;
+        }
+    }
+
+    dict = qdict_new();
+    qdict_put_obj(dict, "type", QOBJECT(qint_from_int(type)));
+    QINCREF(token);
+    qdict_put_obj(dict, "token", QOBJECT(token));
+    qdict_put_obj(dict, "x", QOBJECT(qint_from_int(x)));
+    qdict_put_obj(dict, "y", QOBJECT(qint_from_int(y)));
+
+    qlist_append(parser->tokens, dict);
+
+    if (parser->brace_count == 0 &&
+        parser->bracket_count == 0) {
+        parser->emit(parser, parser->tokens);
+        QDECREF(parser->tokens);
+        parser->tokens = qlist_new();
+    }
+}
+
+void json_message_parser_init(JSONMessageParser *parser,
+                              void (*func)(JSONMessageParser *, QList *))
+{
+    parser->emit = func;
+    parser->brace_count = 0;
+    parser->bracket_count = 0;
+    parser->tokens = qlist_new();
+
+    json_lexer_init(&parser->lexer, json_message_process_token);
+}
+
+int json_message_parser_feed(JSONMessageParser *parser,
+                             const char *buffer, size_t size)
+{
+    return json_lexer_feed(&parser->lexer, buffer, size);
+}
+
+int json_message_parser_flush(JSONMessageParser *parser)
+{
+    return json_lexer_flush(&parser->lexer);
+}
+
+void json_message_parser_destroy(JSONMessageParser *parser)
+{
+    json_lexer_destroy(&parser->lexer);
+    QDECREF(parser->tokens);
+}
diff --git a/json-streamer.h b/json-streamer.h
new file mode 100644
index 0000000..09f3bd7
--- /dev/null
+++ b/json-streamer.h
@@ -0,0 +1,39 @@
+/*
+ * JSON streaming support
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_STREAMER_H
+#define QEMU_JSON_STREAMER_H
+
+#include "qlist.h"
+#include "json-lexer.h"
+
+typedef struct JSONMessageParser
+{
+    void (*emit)(struct JSONMessageParser *parser, QList *tokens);
+    JSONLexer lexer;
+    int brace_count;
+    int bracket_count;
+    QList *tokens;
+} JSONMessageParser;
+
+void json_message_parser_init(JSONMessageParser *parser,
+                              void (*func)(JSONMessageParser *, QList *));
+
+int json_message_parser_feed(JSONMessageParser *parser,
+                             const char *buffer, size_t size);
+
+int json_message_parser_flush(JSONMessageParser *parser);
+
+void json_message_parser_destroy(JSONMessageParser *parser);
+
+#endif
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 09/11] Add a JSON parser
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (6 preceding siblings ...)
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 08/11] Add a JSON message boundary identifier Anthony Liguori
@ 2009-11-11 17:29 ` Anthony Liguori
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 10/11] Add a QObject JSON wrapper Anthony Liguori
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 11/11] Add a unit test for JSON support Anthony Liguori
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

This is the third and final stage of the JSON parser.  It parses lexical tokens
performing grammar validation and creating the final QObject representation.  It
uses a recursive decent parser.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile      |    2 +-
 json-parser.c |  560 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 json-parser.h |   22 +++
 3 files changed, 583 insertions(+), 1 deletions(-)
 create mode 100644 json-parser.c
 create mode 100644 json-parser.h

diff --git a/Makefile b/Makefile
index a2aab60..6d68a1f 100644
--- a/Makefile
+++ b/Makefile
@@ -136,7 +136,7 @@ obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
 obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
-obj-y += json-streamer.o
+obj-y += json-streamer.o json-parser.o
 obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/json-parser.c b/json-parser.c
new file mode 100644
index 0000000..a0c0dca
--- /dev/null
+++ b/json-parser.c
@@ -0,0 +1,560 @@
+/*
+ * JSON Parser 
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <stdbool.h>
+
+#include "qemu-common.h"
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "json-parser.h"
+#include "json-lexer.h"
+
+typedef struct JSONParserContext
+{
+} JSONParserContext;
+
+#define BUG_ON(cond) assert(!(cond))
+
+/**
+ * TODO
+ *
+ * 0) make errors meaningful again
+ * 1) add geometry information to tokens
+ * 3) should we return a parsed size?
+ * 4) deal with premature EOI
+ */
+
+static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap);
+
+/**
+ * Token manipulators
+ *
+ * tokens are dictionaries that contain a type, a string value, and geometry information
+ * about a token identified by the lexer.  These are routines that make working with
+ * these objects a bit easier.
+ */
+static const char *token_get_value(QObject *obj)
+{
+    return qdict_get_str(qobject_to_qdict(obj), "token");
+}
+
+static JSONTokenType token_get_type(QObject *obj)
+{
+    return qdict_get_int(qobject_to_qdict(obj), "type");
+}
+
+static int token_is_operator(QObject *obj, char op)
+{
+    const char *val;
+
+    if (token_get_type(obj) != JSON_OPERATOR) {
+        return 0;
+    }
+
+    val = token_get_value(obj);
+
+    return (val[0] == op) && (val[1] == 0);
+}
+
+static int token_is_keyword(QObject *obj, const char *value)
+{
+    if (token_get_type(obj) != JSON_KEYWORD) {
+        return 0;
+    }
+
+    return strcmp(token_get_value(obj), value) == 0;
+}
+
+static int token_is_escape(QObject *obj, const char *value)
+{
+    if (token_get_type(obj) != JSON_ESCAPE) {
+        return 0;
+    }
+
+    return (strcmp(token_get_value(obj), value) == 0);
+}
+
+/**
+ * Error handler
+ */
+static void parse_error(JSONParserContext *ctxt, QObject *token, const char *msg, ...)
+{
+    fprintf(stderr, "parse error: %s\n", msg);
+}
+
+/**
+ * String helpers
+ *
+ * These helpers are used to unescape strings.
+ */
+static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length)
+{
+    if (wchar <= 0x007F) {
+        BUG_ON(buffer_length < 2);
+
+        buffer[0] = wchar & 0x7F;
+        buffer[1] = 0;
+    } else if (wchar <= 0x07FF) {
+        BUG_ON(buffer_length < 3);
+
+        buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F);
+        buffer[1] = 0x80 | (wchar & 0x3F);
+        buffer[2] = 0;
+    } else {
+        BUG_ON(buffer_length < 4);
+
+        buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F);
+        buffer[1] = 0x80 | ((wchar >> 6) & 0x3F);
+        buffer[2] = 0x80 | (wchar & 0x3F);
+        buffer[3] = 0;
+    }
+}
+
+static int hex2decimal(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return (ch - '0');
+    } else if (ch >= 'a' && ch <= 'f') {
+        return 10 + (ch - 'a');
+    } else if (ch >= 'A' && ch <= 'F') {
+        return 10 + (ch - 'A');
+    }
+
+    return -1;
+}
+
+/**
+ * parse_string(): Parse a json string and return a QObject
+ *
+ *  string
+ *      ""
+ *      " chars "
+ *  chars
+ *      char
+ *      char chars
+ *  char
+ *      any-Unicode-character-
+ *          except-"-or-\-or-
+ *          control-character
+ *      \"
+ *      \\
+ *      \/
+ *      \b
+ *      \f
+ *      \n
+ *      \r
+ *      \t
+ *      \u four-hex-digits 
+ */
+static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
+{
+    const char *ptr = token_get_value(token);
+    QString *str;
+    int double_quote = 1;
+
+    if (*ptr == '"') {
+        double_quote = 1;
+    } else {
+        double_quote = 0;
+    }
+    ptr++;
+
+    str = qstring_new();
+    while (*ptr && 
+           ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\''))) {
+        if (*ptr == '\\') {
+            ptr++;
+
+            switch (*ptr) {
+            case '"':
+                qstring_append(str, "\"");
+                ptr++;
+                break;
+            case '\'':
+                qstring_append(str, "'");
+                ptr++;
+                break;
+            case '\\':
+                qstring_append(str, "\\");
+                ptr++;
+                break;
+            case '/':
+                qstring_append(str, "/");
+                ptr++;
+                break;
+            case 'b':
+                qstring_append(str, "\b");
+                ptr++;
+                break;
+            case 'n':
+                qstring_append(str, "\n");
+                ptr++;
+                break;
+            case 'r':
+                qstring_append(str, "\r");
+                ptr++;
+                break;
+            case 't':
+                qstring_append(str, "\t");
+                ptr++;
+                break;
+            case 'u': {
+                uint16_t unicode_char = 0;
+                char utf8_char[4];
+                int i = 0;
+
+                ptr++;
+
+                for (i = 0; i < 4; i++) {
+                    if (qemu_isxdigit(*ptr)) {
+                        unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4);
+                    } else {
+                        parse_error(ctxt, token,
+                                    "invalid hex escape sequence in string");
+                        goto out;
+                    }
+                    ptr++;
+                }
+
+                wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char));
+                qstring_append(str, utf8_char);
+            }   break;
+            default:
+                parse_error(ctxt, token, "invalid escape sequence in string");
+                goto out;
+            }
+        } else {
+            char dummy[2];
+
+            dummy[0] = *ptr++;
+            dummy[1] = 0;
+
+            qstring_append(str, dummy);
+        }
+    }
+
+    ptr++;
+
+    return str;
+
+out:
+    QDECREF(str);
+    return NULL;
+}
+
+/**
+ * Parsing rules
+ */
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
+{
+    QObject *key, *token = NULL, *value, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    peek = qlist_peek(working);
+    key = parse_value(ctxt, &working, ap);
+    if (qobject_type(key) != QTYPE_QSTRING) {
+        parse_error(ctxt, peek, "key is not a string in object");
+        goto out;
+    }
+
+    token = qlist_pop(working);
+    if (!token_is_operator(token, ':')) {
+        parse_error(ctxt, token, "missing : in object pair");
+        goto out;
+    }
+
+    value = parse_value(ctxt, &working, ap);
+    if (value == NULL) {
+        parse_error(ctxt, token, "Missing value in dict");
+        goto out;
+    }
+
+    qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value);
+
+    qobject_decref(token);
+    qobject_decref(key);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return 0;
+
+out:
+    qobject_decref(token);
+    qobject_decref(key);
+    QDECREF(working);
+
+    return -1;
+}
+
+static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QDict *dict = NULL;
+    QObject *token, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (!token_is_operator(token, '{')) {
+        goto out;
+    }
+    qobject_decref(token);
+    token = NULL;
+
+    dict = qdict_new();
+
+    peek = qlist_peek(working);
+    if (!token_is_operator(peek, '}')) {
+        if (parse_pair(ctxt, dict, &working, ap) == -1) {
+            goto out;
+        }
+
+        token = qlist_pop(working);
+        while (!token_is_operator(token, '}')) {
+            if (!token_is_operator(token, ',')) {
+                parse_error(ctxt, token, "expected separator in dict");
+                goto out;
+            }
+            qobject_decref(token);
+            token = NULL;
+
+            if (parse_pair(ctxt, dict, &working, ap) == -1) {
+                goto out;
+            }
+
+            token = qlist_pop(working);
+        }
+        qobject_decref(token);
+        token = NULL;
+    }
+
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return QOBJECT(dict);
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+    QDECREF(dict);
+    return NULL;
+}
+
+static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QList *list = NULL;
+    QObject *token, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (!token_is_operator(token, '[')) {
+        goto out;
+    }
+    qobject_decref(token);
+    token = NULL;
+
+    list = qlist_new();
+
+    peek = qlist_peek(working);
+    if (!token_is_operator(peek, ']')) {
+        QObject *obj;
+
+        obj = parse_value(ctxt, &working, ap);
+        if (obj == NULL) {
+            parse_error(ctxt, token, "expecting value");
+            goto out;
+        }
+
+        qlist_append_obj(list, obj);
+
+        token = qlist_pop(working);
+        while (!token_is_operator(token, ']')) {
+            if (!token_is_operator(token, ',')) {
+                parse_error(ctxt, token, "expected separator in list");
+                goto out;
+            }
+
+            qobject_decref(token);
+            token = NULL;
+
+            obj = parse_value(ctxt, &working, ap);
+            if (obj == NULL) {
+                parse_error(ctxt, token, "expecting value");
+                goto out;
+            }
+
+            qlist_append_obj(list, obj);
+
+            token = qlist_pop(working);
+        }
+
+        qobject_decref(token);
+        token = NULL;
+    }
+
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return QOBJECT(list);
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+    QDECREF(list);
+    return NULL;
+}
+
+static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
+{
+    QObject *token, *ret;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+
+    if (token_get_type(token) != JSON_KEYWORD) {
+        goto out;
+    }
+
+    if (token_is_keyword(token, "true")) {
+        ret = QOBJECT(qbool_from_int(true));
+    } else if (token_is_keyword(token, "false")) {
+        ret = QOBJECT(qbool_from_int(false));
+    } else {
+        parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token));
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return ret;
+
+out: 
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QObject *token = NULL, *obj;
+    QList *working = qlist_copy(*tokens);
+
+    if (ap == NULL) {
+        goto out;
+    }
+
+    token = qlist_pop(working);
+
+    if (token_is_escape(token, "%p")) {
+        obj = va_arg(*ap, QObject *);
+    } else if (token_is_escape(token, "%i")) {
+        obj = QOBJECT(qbool_from_int(va_arg(*ap, int)));
+    } else if (token_is_escape(token, "%d")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
+    } else if (token_is_escape(token, "%ld")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
+    } else if (token_is_escape(token, "%lld")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
+    } else if (token_is_escape(token, "%s")) {
+        obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
+    } else if (token_is_escape(token, "%f")) {
+        obj = QOBJECT(qfloat_from_double(va_arg(*ap, double)));
+    } else {
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return obj;
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
+{
+    QObject *token, *obj;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    switch (token_get_type(token)) {
+    case JSON_STRING:
+        obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
+        break;
+    case JSON_INTEGER:
+        obj = QOBJECT(qint_from_int(strtoll(token_get_value(token), NULL, 10)));
+        break;
+    case JSON_FLOAT:
+        /* FIXME dependent on locale */
+        obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL)));
+        break;
+    default:
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return obj;
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QObject *obj;
+
+    obj = parse_object(ctxt, tokens, ap);
+    if (obj == NULL) {
+        obj = parse_array(ctxt, tokens, ap);
+    }
+    if (obj == NULL) {
+        obj = parse_escape(ctxt, tokens, ap);
+    }
+    if (obj == NULL) {
+        obj = parse_keyword(ctxt, tokens);
+    } 
+    if (obj == NULL) {
+        obj = parse_literal(ctxt, tokens);
+    }
+
+    return obj;
+}
+
+QObject *json_parser_parse(QList *tokens, va_list *ap)
+{
+    JSONParserContext ctxt = {};
+    QList *working = qlist_copy(tokens);
+    QObject *result;
+
+    result = parse_value(&ctxt, &working, ap);
+
+    QDECREF(working);
+
+    return result;
+}
diff --git a/json-parser.h b/json-parser.h
new file mode 100644
index 0000000..97f43f6
--- /dev/null
+++ b/json-parser.h
@@ -0,0 +1,22 @@
+/*
+ * JSON Parser 
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_PARSER_H
+#define QEMU_JSON_PARSER_H
+
+#include "qemu-common.h"
+#include "qlist.h"
+
+QObject *json_parser_parse(QList *tokens, va_list *ap);
+
+#endif
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 10/11] Add a QObject JSON wrapper
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (7 preceding siblings ...)
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 09/11] Add a JSON parser Anthony Liguori
@ 2009-11-11 17:29 ` Anthony Liguori
  2009-11-11 18:12   ` [Qemu-devel] " Luiz Capitulino
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 11/11] Add a unit test for JSON support Anthony Liguori
  9 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

This provides a QObject interface for creating QObjects from a JSON expression.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile |    2 +-
 qjson.c  |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qjson.h  |   23 +++++++++++++++++++++++
 3 files changed, 84 insertions(+), 1 deletions(-)
 create mode 100644 qjson.c
 create mode 100644 qjson.h

diff --git a/Makefile b/Makefile
index 6d68a1f..3818c51 100644
--- a/Makefile
+++ b/Makefile
@@ -136,7 +136,7 @@ obj-y += qemu-char.o aio.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
 obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
-obj-y += json-streamer.o json-parser.o
+obj-y += json-streamer.o json-parser.o qjson.o
 obj-y += qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/qjson.c b/qjson.c
new file mode 100644
index 0000000..45207f2
--- /dev/null
+++ b/qjson.c
@@ -0,0 +1,60 @@
+/*
+ * QObject JSON integration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "json-lexer.h"
+#include "json-parser.h"
+#include "json-streamer.h"
+#include "qjson.h"
+
+typedef struct JSONParsingState
+{
+    JSONMessageParser parser;
+    va_list *ap;
+    QObject *result;
+} JSONParsingState;
+
+static void parse_json(JSONMessageParser *parser, QList *tokens)
+{
+    JSONParsingState *s = container_of(parser, JSONParsingState, parser);
+    s->result = json_parser_parse(tokens, s->ap);
+}
+
+QObject *qobject_from_json(const char *string)
+{
+    JSONParsingState state = {};
+
+    json_message_parser_init(&state.parser, parse_json);
+    json_message_parser_feed(&state.parser, string, strlen(string));
+    json_message_parser_flush(&state.parser);
+    json_message_parser_destroy(&state.parser);
+
+    return state.result;
+}
+
+QObject *qobject_from_jsonf(const char *string, ...)
+{
+    JSONParsingState state = {};
+    va_list ap;
+
+    va_start(ap, string);
+    state.ap = &ap;
+
+    json_message_parser_init(&state.parser, parse_json);
+    json_message_parser_feed(&state.parser, string, strlen(string));
+    json_message_parser_flush(&state.parser);
+    json_message_parser_destroy(&state.parser);
+
+    va_end(ap);
+
+    return state.result;
+}
diff --git a/qjson.h b/qjson.h
new file mode 100644
index 0000000..38be643
--- /dev/null
+++ b/qjson.h
@@ -0,0 +1,23 @@
+/*
+ * QObject JSON integration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QJSON_H
+#define QJSON_H
+
+#include "qobject.h"
+
+QObject *qobject_from_json(const char *string);
+QObject *qobject_from_jsonf(const char *string, ...)
+    __attribute__((__format__ (__printf__, 1, 2)));
+
+#endif /* QJSON_H */
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH 11/11] Add a unit test for JSON support
  2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
                   ` (8 preceding siblings ...)
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 10/11] Add a QObject JSON wrapper Anthony Liguori
@ 2009-11-11 17:29 ` Anthony Liguori
  9 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 17:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori, Luiz Capitulino

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile      |    1 +
 check-qjson.c |  608 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure     |    2 +-
 3 files changed, 610 insertions(+), 1 deletions(-)
 create mode 100644 check-qjson.c

diff --git a/Makefile b/Makefile
index 3818c51..4b678e6 100644
--- a/Makefile
+++ b/Makefile
@@ -229,6 +229,7 @@ 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-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
diff --git a/check-qjson.c b/check-qjson.c
new file mode 100644
index 0000000..f763de6
--- /dev/null
+++ b/check-qjson.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <check.h>
+#include <stdbool.h>
+
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "qjson.h"
+
+#include "qemu-common.h"
+
+START_TEST(escaped_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+    } test_cases[] = {
+        { "\"\\\"\"", "\"" },
+        { "\"hello world \\\"embedded string\\\"\"",
+          "hello world \"embedded string\"" },
+        { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
+        { "\"single byte utf-8 \\u0020\"", "single byte utf-8  " },
+        { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
+        { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+    } test_cases[] = {
+        { "\"hello world\"", "hello world" },
+        { "\"the quick brown fox jumped over the fence\"",
+          "the quick brown fox jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(single_quote_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+    } test_cases[] = {
+        { "'hello world'", "hello world" },
+        { "'the quick brown fox \\' jumped over the fence'",
+          "the quick brown fox ' jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(vararg_string)
+{
+    int i;
+    struct {
+        const char *decoded;
+    } test_cases[] = {
+        { "hello world" },
+        { "the quick brown fox jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].decoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_jsonf("%s", test_cases[i].decoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_number)
+{
+    int i;
+    struct {
+        const char *encoded;
+        int64_t decoded;
+    } test_cases[] = {
+        { "0", 0 },
+        { "1234", 1234 },
+        { "1", 1 },
+        { "-32", -32 },
+        { "-0", 0 },
+        { },
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QInt *qint;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+        qint = qobject_to_qint(obj);
+        fail_unless(qint_get_int(qint) == test_cases[i].decoded);
+
+        QDECREF(qint);
+    }
+}
+END_TEST
+
+START_TEST(float_number)
+{
+    int i;
+    struct {
+        const char *encoded;
+        double decoded;
+    } test_cases[] = {
+        { "32.43", 32.43 },
+        { "0.222", 0.222 },
+        { "-32.12313", -32.12313 },
+        { "-32.20e-10", -32.20e-10 },
+        { },
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QFloat *qfloat;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+
+        qfloat = qobject_to_qfloat(obj);
+        fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
+
+        QDECREF(qfloat);
+    }
+}
+END_TEST
+
+START_TEST(vararg_number)
+{
+    QObject *obj;
+    QInt *qint;
+    QFloat *qfloat;
+    int value = 0x2342;
+    int64_t value64 = 0x2342342343LL;
+    double valuef = 2.323423423;
+
+    obj = qobject_from_jsonf("%d", value);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+    qint = qobject_to_qint(obj);
+    fail_unless(qint_get_int(qint) == value);
+
+    QDECREF(qint);
+
+    obj = qobject_from_jsonf("%" PRId64, value64);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+    qint = qobject_to_qint(obj);
+    fail_unless(qint_get_int(qint) == value64);
+
+    QDECREF(qint);
+
+    obj = qobject_from_jsonf("%f", valuef);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+
+    qfloat = qobject_to_qfloat(obj);
+    fail_unless(qfloat_get_double(qfloat) == valuef);
+
+    QDECREF(qfloat);
+}
+END_TEST
+
+START_TEST(keyword_literal)
+{
+    QObject *obj;
+    QBool *qbool;
+
+    obj = qobject_from_json("true");
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) != 0);
+
+    QDECREF(qbool);
+
+    obj = qobject_from_json("false");
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) == 0);
+
+    QDECREF(qbool);
+
+    obj = qobject_from_jsonf("%i", false);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) == 0);
+
+    QDECREF(qbool);
+    
+    obj = qobject_from_jsonf("%i", true);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) != 0);
+
+    QDECREF(qbool);
+}
+END_TEST
+
+typedef struct LiteralQDictEntry LiteralQDictEntry;
+typedef struct LiteralQObject LiteralQObject;
+
+struct LiteralQObject
+{
+    int type;
+    union {
+        int64_t qint;
+        const char *qstr;
+        LiteralQDictEntry *qdict;
+        LiteralQObject *qlist;
+    } value;
+};
+
+struct LiteralQDictEntry
+{
+    const char *key;
+    LiteralQObject value;
+};
+
+#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
+#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
+#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
+#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
+
+typedef struct QListCompareHelper
+{
+    int index;
+    LiteralQObject *objs;
+    int result;
+} QListCompareHelper;
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
+
+static void compare_helper(QObject *obj, void *opaque)
+{
+    QListCompareHelper *helper = opaque;
+
+    if (helper->result == 0) {
+        return;
+    }
+
+    if (helper->objs[helper->index].type == QTYPE_NONE) {
+        helper->result = 0;
+        return;
+    }
+
+    helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
+}
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
+{
+    if (lhs->type != qobject_type(rhs)) {
+        return 0;
+    }
+
+    switch (lhs->type) {
+    case QTYPE_QINT:
+        return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
+    case QTYPE_QSTRING:
+        return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
+    case QTYPE_QDICT: {
+        int i;
+
+        for (i = 0; lhs->value.qdict[i].key; i++) {
+            QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
+
+            if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
+                return 0;
+            }
+        }
+
+        return 1;
+    }
+    case QTYPE_QLIST: {
+        QListCompareHelper helper;
+
+        helper.index = 0;
+        helper.objs = lhs->value.qlist;
+        helper.result = 1;
+        
+        qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
+
+        return helper.result;
+    }
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+START_TEST(simple_dict)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = "{\"foo\":42,\"bar\":\"hello world\"}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { "foo", QLIT_QINT(42) },
+                        { "bar", QLIT_QSTR("hello world") },
+                        { }
+                    })),
+        }, {
+            .encoded = "{}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { }
+                    })),
+        }, {
+            .encoded = "{\"foo\":43}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { "foo", QLIT_QINT(43) },
+                        { }
+                    })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QDICT);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        qobject_decref(obj);
+    }
+}
+END_TEST
+
+START_TEST(simple_list)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = "[43,42]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = "[43]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        { }
+                    })),
+        },
+        {
+            .encoded = "[]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        { }
+                    })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        qobject_decref(obj);
+    }
+}
+END_TEST
+
+START_TEST(simple_whitespace)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = " [ 43 , 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QDICT(((LiteralQDictEntry[]){
+                                    { "h", QLIT_QSTR("b") },
+                                    { }})),
+                        QLIT_QLIST(((LiteralQObject[]){
+                                    { }})),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QDICT(((LiteralQDictEntry[]){
+                                    { "h", QLIT_QSTR("b") },
+                                    { "a", QLIT_QINT(32) },
+                                    { }})),
+                        QLIT_QLIST(((LiteralQObject[]){
+                                    { }})),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        qobject_decref(obj);
+    }
+}
+END_TEST
+
+START_TEST(simple_varargs)
+{
+    QObject *embedded_obj;
+    QObject *obj;
+    LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
+            QLIT_QINT(1),
+            QLIT_QINT(2),
+            QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(32),
+                        QLIT_QINT(42),
+                        {}})),
+            {}}));
+
+    embedded_obj = qobject_from_json("[32, 42]");
+    fail_unless(embedded_obj != NULL);
+
+    obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
+    fail_unless(obj != NULL);
+
+    fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
+
+    qobject_decref(obj);
+}
+END_TEST
+
+static Suite *qjson_suite(void)
+{
+    Suite *suite;
+    TCase *string_literals, *number_literals, *keyword_literals;
+    TCase *dicts, *lists, *whitespace, *varargs;
+
+    string_literals = tcase_create("String Literals");
+    tcase_add_test(string_literals, simple_string);
+    tcase_add_test(string_literals, escaped_string);
+    tcase_add_test(string_literals, single_quote_string);
+    tcase_add_test(string_literals, vararg_string);
+
+    number_literals = tcase_create("Number Literals");
+    tcase_add_test(number_literals, simple_number);
+    tcase_add_test(number_literals, float_number);
+    tcase_add_test(number_literals, vararg_number);
+
+    keyword_literals = tcase_create("Keywords");
+    tcase_add_test(keyword_literals, keyword_literal);
+    dicts = tcase_create("Objects");
+    tcase_add_test(dicts, simple_dict);
+    lists = tcase_create("Lists");
+    tcase_add_test(lists, simple_list);
+
+    whitespace = tcase_create("Whitespace");
+    tcase_add_test(whitespace, simple_whitespace);
+
+    varargs = tcase_create("Varargs");
+    tcase_add_test(varargs, simple_varargs);
+
+    suite = suite_create("QJSON test-suite");
+    suite_add_tcase(suite, string_literals);
+    suite_add_tcase(suite, number_literals);
+    suite_add_tcase(suite, keyword_literals);
+    suite_add_tcase(suite, dicts);
+    suite_add_tcase(suite, lists);
+    suite_add_tcase(suite, whitespace);
+    suite_add_tcase(suite, varargs);
+
+    return suite;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s;
+    SRunner *sr;
+
+    s = qjson_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 55be0fb..20bd39c 100755
--- a/configure
+++ b/configure
@@ -2092,7 +2092,7 @@ if test `expr "$target_list" : ".*softmmu.*"` != 0 ; 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-qfloat $tools"
+      tools="check-qfloat check-qjson $tools"
     fi
   elif test "$mingw32" = "yes" ; then
       tools="qemu-io\$(EXESUF) $tools"
-- 
1.6.2.5

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

* [Qemu-devel] Re: [PATCH 10/11] Add a QObject JSON wrapper
  2009-11-11 17:29 ` [Qemu-devel] [PATCH 10/11] Add a QObject JSON wrapper Anthony Liguori
@ 2009-11-11 18:12   ` Luiz Capitulino
  2009-11-11 19:39     ` Anthony Liguori
  0 siblings, 1 reply; 21+ messages in thread
From: Luiz Capitulino @ 2009-11-11 18:12 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

On Wed, 11 Nov 2009 11:29:02 -0600
Anthony Liguori <aliguori@us.ibm.com> wrote:

> This provides a QObject interface for creating QObjects from a JSON expression.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
>  Makefile |    2 +-
>  qjson.c  |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  qjson.h  |   23 +++++++++++++++++++++++
>  3 files changed, 84 insertions(+), 1 deletions(-)
>  create mode 100644 qjson.c
>  create mode 100644 qjson.h
> 
> diff --git a/Makefile b/Makefile
> index 6d68a1f..3818c51 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -136,7 +136,7 @@ obj-y += qemu-char.o aio.o savevm.o
>  obj-y += msmouse.o ps2.o
>  obj-y += qdev.o qdev-properties.o
>  obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
> -obj-y += json-streamer.o json-parser.o
> +obj-y += json-streamer.o json-parser.o qjson.o
>  obj-y += qemu-config.o
>  
>  obj-$(CONFIG_BRLAPI) += baum.o
> diff --git a/qjson.c b/qjson.c
> new file mode 100644
> index 0000000..45207f2
> --- /dev/null
> +++ b/qjson.c
> @@ -0,0 +1,60 @@
> +/*
> + * QObject JSON integration
> + *
> + * Copyright IBM, Corp. 2009
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "json-lexer.h"
> +#include "json-parser.h"
> +#include "json-streamer.h"
> +#include "qjson.h"
> +
> +typedef struct JSONParsingState
> +{
> +    JSONMessageParser parser;
> +    va_list *ap;
> +    QObject *result;
> +} JSONParsingState;
> +
> +static void parse_json(JSONMessageParser *parser, QList *tokens)
> +{
> +    JSONParsingState *s = container_of(parser, JSONParsingState, parser);
> +    s->result = json_parser_parse(tokens, s->ap);
> +}
> +
> +QObject *qobject_from_json(const char *string)
> +{
> +    JSONParsingState state = {};
> +
> +    json_message_parser_init(&state.parser, parse_json);
> +    json_message_parser_feed(&state.parser, string, strlen(string));
> +    json_message_parser_flush(&state.parser);
> +    json_message_parser_destroy(&state.parser);
> +
> +    return state.result;
> +}
> +
> +QObject *qobject_from_jsonf(const char *string, ...)
> +{
> +    JSONParsingState state = {};
> +    va_list ap;
> +
> +    va_start(ap, string);
> +    state.ap = &ap;
> +
> +    json_message_parser_init(&state.parser, parse_json);
> +    json_message_parser_feed(&state.parser, string, strlen(string));
> +    json_message_parser_flush(&state.parser);
> +    json_message_parser_destroy(&state.parser);
> +
> +    va_end(ap);
> +
> +    return state.result;

 I think we should abort() on error, assuming the only way to fail
is a bad syntax.

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

* Re: [Qemu-devel] Re: [PATCH 10/11] Add a QObject JSON wrapper
  2009-11-11 18:12   ` [Qemu-devel] " Luiz Capitulino
@ 2009-11-11 19:39     ` Anthony Liguori
  2009-11-11 19:58       ` Luiz Capitulino
  0 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2009-11-11 19:39 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Anthony Liguori, qemu-devel

Luiz Capitulino wrote:
>  I think we should abort() on error, assuming the only way to fail
> is a bad syntax.
>   

We'll be using qobject_from_jsonf() to parse incoming QMP traffic.   We 
definitely don't want to abort when we receive invalid input on the QMP 
port.   Best to just close the session and let the user connect again.

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] Re: [PATCH 10/11] Add a QObject JSON wrapper
  2009-11-11 19:39     ` Anthony Liguori
@ 2009-11-11 19:58       ` Luiz Capitulino
  0 siblings, 0 replies; 21+ messages in thread
From: Luiz Capitulino @ 2009-11-11 19:58 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony Liguori, qemu-devel

On Wed, 11 Nov 2009 13:39:29 -0600
Anthony Liguori <anthony@codemonkey.ws> wrote:

> Luiz Capitulino wrote:
> >  I think we should abort() on error, assuming the only way to fail
> > is a bad syntax.
> >   
> 
> We'll be using qobject_from_jsonf() to parse incoming QMP traffic.   We 
> definitely don't want to abort when we receive invalid input on the QMP 
> port.   Best to just close the session and let the user connect again.

 Sure, I just wouldn't like to add a check on every handler call to
qobject_from_jsonf().

 What about a new wrapper?

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-11 17:28 ` [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack Anthony Liguori
@ 2009-11-12 15:33   ` Kevin Wolf
  2009-11-12 16:46     ` Anthony Liguori
  0 siblings, 1 reply; 21+ messages in thread
From: Kevin Wolf @ 2009-11-12 15:33 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Luiz Capitulino

Am 11.11.2009 18:28, schrieb Anthony Liguori:
> This makes lists no longer invariant. It's a very useful bit of functionality
> though.
> 
> To deal with the fact that lists are no longer invariant, introduce a deep
> copy mechanism for lists.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
>  qlist.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  qlist.h |    4 ++++
>  2 files changed, 60 insertions(+), 0 deletions(-)

So far all functions in qlist.c have a header comment. Any reason to
change this?

Kevin

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 15:33   ` Kevin Wolf
@ 2009-11-12 16:46     ` Anthony Liguori
  2009-11-12 16:56       ` Kevin Wolf
  0 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2009-11-12 16:46 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Liguori, qemu-devel, Luiz Capitulino

Kevin Wolf wrote:
> Am 11.11.2009 18:28, schrieb Anthony Liguori:
>   
>> This makes lists no longer invariant. It's a very useful bit of functionality
>> though.
>>
>> To deal with the fact that lists are no longer invariant, introduce a deep
>> copy mechanism for lists.
>>
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> ---
>>  qlist.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  qlist.h |    4 ++++
>>  2 files changed, 60 insertions(+), 0 deletions(-)
>>     
>
> So far all functions in qlist.c have a header comment. Any reason to
> change this?
>   

But nothing else in qemu does.

I don't find this commenting style particularly helpful since they 
really don't tell you anything you can't infer from the function name.  
I'm not opposed to people adding these types of comments but I don't 
think it's a good idea to attempt to enforce it in just this one place 
(not that I think it should be enforced everywhere).

Regards,

Anthony Liguori
> Kevin
>
>
>   

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 16:46     ` Anthony Liguori
@ 2009-11-12 16:56       ` Kevin Wolf
  2009-11-12 17:13         ` Anthony Liguori
  2009-11-12 17:17         ` Ian Molton
  0 siblings, 2 replies; 21+ messages in thread
From: Kevin Wolf @ 2009-11-12 16:56 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony Liguori, qemu-devel, Luiz Capitulino

Am 12.11.2009 17:46, schrieb Anthony Liguori:
> Kevin Wolf wrote:
>> Am 11.11.2009 18:28, schrieb Anthony Liguori:
>>   
>>> This makes lists no longer invariant. It's a very useful bit of functionality
>>> though.
>>>
>>> To deal with the fact that lists are no longer invariant, introduce a deep
>>> copy mechanism for lists.
>>>
>>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>>> ---
>>>  qlist.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  qlist.h |    4 ++++
>>>  2 files changed, 60 insertions(+), 0 deletions(-)
>>>     
>>
>> So far all functions in qlist.c have a header comment. Any reason to
>> change this?
>>   
> 
> But nothing else in qemu does.

Unfortunately. There are places where such comments could be a good
specification on what an interface is actually meant to work like
(particularly in error cases). Currently you often can't tell if the
implementation or the caller of a function is buggy.

Not sure if they are really useful for the simple qlist.c functions (but
even there the function name does not tell me what it's doing with NULL
parameters), but it might be helpful to have a general discussion about
it. I think in general qemu is poorly commented.

Kevin

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 16:56       ` Kevin Wolf
@ 2009-11-12 17:13         ` Anthony Liguori
  2009-11-12 17:20           ` Luiz Capitulino
  2009-11-13  8:51           ` Kevin Wolf
  2009-11-12 17:17         ` Ian Molton
  1 sibling, 2 replies; 21+ messages in thread
From: Anthony Liguori @ 2009-11-12 17:13 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Liguori, qemu-devel, Luiz Capitulino

Kevin Wolf wrote:
> Unfortunately. There are places where such comments could be a good
> specification on what an interface is actually meant to work like
> (particularly in error cases). Currently you often can't tell if the
> implementation or the caller of a function is buggy.
>
> Not sure if they are really useful for the simple qlist.c functions (but
> even there the function name does not tell me what it's doing with NULL
> parameters), but it might be helpful to have a general discussion about
> it. I think in general qemu is poorly commented.
>   

I agree, but I don't think the solution is forcing boiler plate 
commenting styles.  I think what we could improve on is asking people to 
comment bits of code during review.

> Kevin
>   
-- 
Regards,

Anthony Liguori

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 16:56       ` Kevin Wolf
  2009-11-12 17:13         ` Anthony Liguori
@ 2009-11-12 17:17         ` Ian Molton
  1 sibling, 0 replies; 21+ messages in thread
From: Ian Molton @ 2009-11-12 17:17 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Liguori, qemu-devel, Luiz Capitulino

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Kevin Wolf wrote:
> I think in general qemu is poorly commented.

I think thats a bit of an understatement. in particular I'm finding the
options code to be a nightmare. Hopefully I'll be fixing some of that in
my upcomming submissions.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQIcBAEBAgAGBQJK/EMMAAoJEFIjE1w7L6YH2BgP/17YUHz92sD001Q8VxETeTJS
RhKONA6tX4vmnKfUTkM9VrqV3Qv7lyhhGN2IdJulUpKEKRmoykMuPKopkaYKuCJ4
9WzxQOimAHQbZ9NrPYulafygCx4opiuzFenuCoiabzdN6qhT7zdBmhqIMH188f/G
W8Bc4c0eiPD0wWwaomr4VMh+BaJ2lZDElPNNz7FxoUAdoedoNs0Iyj8VxlBGzNSz
6IoIqCBLgTzMbSKLIeKZ3eKGK3AZDIPpWbA7qlsB2K2zUQW9nlNVgs8BbOihSTng
NN2+9e0/QQvYGa/xYaGc/gmXf9WZwhMncvhPyuwB6alsMNzNF6X3jfvqC6ZDkzq5
NVNI6ItN1cVvbJqTPLGQ6EHspO9Du8GssbQnPiM3wCTmsB9aAV65LOWyBxigAdz1
7gQvXxt2+pDduqahOdw3vc2DllhtkASSH1JIPM90Hc/H6qHCBdkQO3okqZr/rOm5
OiQwONQ84k5Pp6GRcuWPbl+Dnrs47P4N7wQ876CooqGxhn8z4JIk6jKpIPqsDWVn
rxWVF41Hbxr/92BVrxBqmAJlIaqUMnUhTfpiYPVdaKMcrRIDWXpDXQOlNrztdk3a
INcv4NhJ604ab5UpLO3WbLIJK4CTnRXldly++3DHM60im6fO1kCsq5sKe56V7lNi
WossoFOnMg5Xb9RBxWxo
=iEnN
-----END PGP SIGNATURE-----

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 17:13         ` Anthony Liguori
@ 2009-11-12 17:20           ` Luiz Capitulino
  2009-11-13  8:51           ` Kevin Wolf
  1 sibling, 0 replies; 21+ messages in thread
From: Luiz Capitulino @ 2009-11-12 17:20 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Kevin Wolf, Anthony Liguori, qemu-devel

On Thu, 12 Nov 2009 11:13:45 -0600
Anthony Liguori <aliguori@linux.vnet.ibm.com> wrote:

> Kevin Wolf wrote:
> > Unfortunately. There are places where such comments could be a good
> > specification on what an interface is actually meant to work like
> > (particularly in error cases). Currently you often can't tell if the
> > implementation or the caller of a function is buggy.
> >
> > Not sure if they are really useful for the simple qlist.c functions (but
> > even there the function name does not tell me what it's doing with NULL
> > parameters), but it might be helpful to have a general discussion about
> > it. I think in general qemu is poorly commented.
> >   
> 
> I agree, but I don't think the solution is forcing boiler plate 
> commenting styles.  I think what we could improve on is asking people to 
> comment bits of code during review.

 I've started adding comments like that because this is an API which
is probably going to be part of a library, as such it has to be properly
documented and very likely to be generated automatically by tools like
doxygen.

 If we do this we should be consistent and document everything which
is public, even simple cases.

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

* Re: [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack
  2009-11-12 17:13         ` Anthony Liguori
  2009-11-12 17:20           ` Luiz Capitulino
@ 2009-11-13  8:51           ` Kevin Wolf
  1 sibling, 0 replies; 21+ messages in thread
From: Kevin Wolf @ 2009-11-13  8:51 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony Liguori, qemu-devel, Luiz Capitulino

Am 12.11.2009 18:13, schrieb Anthony Liguori:
> Kevin Wolf wrote:
>> Unfortunately. There are places where such comments could be a good
>> specification on what an interface is actually meant to work like
>> (particularly in error cases). Currently you often can't tell if the
>> implementation or the caller of a function is buggy.
>>
>> Not sure if they are really useful for the simple qlist.c functions (but
>> even there the function name does not tell me what it's doing with NULL
>> parameters), but it might be helpful to have a general discussion about
>> it. I think in general qemu is poorly commented.
>>   
> 
> I agree, but I don't think the solution is forcing boiler plate 
> commenting styles.  I think what we could improve on is asking people to 
> comment bits of code during review.

Be sure that I'll be asking for comments in qcow2 patches. I did in the
past and I'll continue to do so. ;-)

I agree that boiler plates are not going to help per se. But I think
what actually does play a role in commenting is what surrounding code
looks like and it's also habits. And it's probably not wrong to say that
we're currently in a habit of not documenting anything. If boiler plates
in some places are the price to get into a habit of documenting things,
I think considering to accept that price wouldn't be completely
unreasonable.

Another thing is that we could ask more often to move explanations from
mails into the code. The explanation often exists and sometimes we're
lucky enough that it ends up at least in the commit log, but there are
cases where it's in PATCH 0/n or buried in the corresponding mail thread.

Kevin

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

end of thread, other threads:[~2009-11-13  8:53 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-11 17:28 [Qemu-devel] [PATCH 01/11] Properly escape QDECREF macro arguments Anthony Liguori
2009-11-11 17:28 ` [Qemu-devel] [PATCH 02/11] Add operations to qlist to allow it to be used as a stack Anthony Liguori
2009-11-12 15:33   ` Kevin Wolf
2009-11-12 16:46     ` Anthony Liguori
2009-11-12 16:56       ` Kevin Wolf
2009-11-12 17:13         ` Anthony Liguori
2009-11-12 17:20           ` Luiz Capitulino
2009-11-13  8:51           ` Kevin Wolf
2009-11-12 17:17         ` Ian Molton
2009-11-11 17:28 ` [Qemu-devel] [PATCH 03/11] Allow strings to grow in size Anthony Liguori
2009-11-11 17:28 ` [Qemu-devel] [PATCH 04/11] Add a QFloat datatype Anthony Liguori
2009-11-11 17:28 ` [Qemu-devel] [PATCH 05/11] Add unit test for QFloat Anthony Liguori
2009-11-11 17:28 ` [Qemu-devel] [PATCH 06/11] Add a QBool type Anthony Liguori
2009-11-11 17:28 ` [Qemu-devel] [PATCH 07/11] Add a lexer for JSON Anthony Liguori
2009-11-11 17:29 ` [Qemu-devel] [PATCH 08/11] Add a JSON message boundary identifier Anthony Liguori
2009-11-11 17:29 ` [Qemu-devel] [PATCH 09/11] Add a JSON parser Anthony Liguori
2009-11-11 17:29 ` [Qemu-devel] [PATCH 10/11] Add a QObject JSON wrapper Anthony Liguori
2009-11-11 18:12   ` [Qemu-devel] " Luiz Capitulino
2009-11-11 19:39     ` Anthony Liguori
2009-11-11 19:58       ` Luiz Capitulino
2009-11-11 17:29 ` [Qemu-devel] [PATCH 11/11] Add a unit test for JSON support Anthony Liguori

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.