* [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-18 21:36 ` Luiz Capitulino
2009-10-17 13:36 ` [Qemu-devel] [PATCH 02/11] Add support for qfloat Anthony Liguori
` (10 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
This allows qstring to be used for dynamic string construction.
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] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor
2009-10-17 13:36 ` [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor Anthony Liguori
@ 2009-10-18 21:36 ` Luiz Capitulino
2009-10-23 19:33 ` Jamie Lokier
0 siblings, 1 reply; 28+ messages in thread
From: Luiz Capitulino @ 2009-10-18 21:36 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Sat, 17 Oct 2009 08:36:01 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> This allows qstring to be used for dynamic string construction.
>
> 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;
Couldn't this be:
qstring->string = qemu_strdup(str);
qstring->length = qstring->capacity = strlen(str);
> +
> QOBJECT_INIT(qstring, &qstring_type);
>
> return qstring;
> }
>
> +/* qstring_append(): Append a C string to a QString
> + */
Forgot the 'little roof' in the comment style. :-)
> +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);
> + }
Why do we need to double it? Wouldn't be enough to only keep track
of the current string length and add 'len' to it? We could drop
'capacity' then.
> +
> + memcpy(qstring->string + qstring->length, str, len);
> + qstring->length += len;
> + qstring->string[qstring->length] = 0;
I would use strcat().
> +}
> +
> /**
> * 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 */
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor
2009-10-18 21:36 ` Luiz Capitulino
@ 2009-10-23 19:33 ` Jamie Lokier
0 siblings, 0 replies; 28+ messages in thread
From: Jamie Lokier @ 2009-10-23 19:33 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: Anthony Liguori, qemu-devel
Luiz Capitulino wrote:
> > 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;
>
> Couldn't this be:
>
> qstring->string = qemu_strdup(str);
> qstring->length = qstring->capacity = strlen(str);
Probably to have one call to strlen() instead of two (one inside
qemu_strdup()).
> > +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);
> > + }
>
> Why do we need to double it? Wouldn't be enough to only keep track
> of the current string length and add 'len' to it? We could drop
> 'capacity' then.
You need exponential growth if large stringes are to be grown in O(n)
time where n is the number of characters, appended in small pieces.
Think about the time spent copying bytes every time qemu_realloc() is called.
If you just add 'len' each time, think about appending 1 byte 10^4
times. It will copy approximately 10^8/2 bytes, which is a lot just to
make a string 10^4 bytes long.
But += len; *= 2 is not necessary. *= 2 is enough, provided the
result is large enough.
> > + memcpy(qstring->string + qstring->length, str, len);
> > + qstring->length += len;
> > + qstring->string[qstring->length] = 0;
>
> I would use strcat().
Again, that's an extra call to strlen(), traversing the string twice instead of once.
Doesn't make much different for small strings, only large ones.
-- Jamie
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-18 22:21 ` Luiz Capitulino
2009-10-17 13:36 ` [Qemu-devel] [PATCH 03/11] Add a test case " Anthony Liguori
` (9 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
qfloat is a qobject wrapper for double precision floating points
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 e78a3d0..9294638 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,8 @@ obj-y += net.o net-queue.o
obj-y += qemu-char.o aio.o net-checksum.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_WIN32) += tap-win32.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 4cc9287..da03a5e 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] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-17 13:36 ` [Qemu-devel] [PATCH 02/11] Add support for qfloat Anthony Liguori
@ 2009-10-18 22:21 ` Luiz Capitulino
2009-10-19 14:18 ` Anthony Liguori
0 siblings, 1 reply; 28+ messages in thread
From: Luiz Capitulino @ 2009-10-18 22:21 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Sat, 17 Oct 2009 08:36:02 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> qfloat is a qobject wrapper for double precision floating points
>
> 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 e78a3d0..9294638 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -125,7 +125,8 @@ obj-y += net.o net-queue.o
> obj-y += qemu-char.o aio.o net-checksum.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_WIN32) += tap-win32.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.
> + *
> + */
I see you're double licensing it to respect my initial choice, but you
can leave only LGPL for this new code.
I will send patches changing the ones written by me.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-18 22:21 ` Luiz Capitulino
@ 2009-10-19 14:18 ` Anthony Liguori
2009-10-22 8:49 ` Amit Shah
0 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-19 14:18 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel
Luiz Capitulino wrote:
> On Sat, 17 Oct 2009 08:36:02 -0500
> Anthony Liguori <aliguori@us.ibm.com> wrote:
>
>
>> qfloat is a qobject wrapper for double precision floating points
>>
>> 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 e78a3d0..9294638 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -125,7 +125,8 @@ obj-y += net.o net-queue.o
>> obj-y += qemu-char.o aio.o net-checksum.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_WIN32) += tap-win32.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.
>> + *
>> + */
>>
>
> I see you're double licensing it to respect my initial choice, but you
> can leave only LGPL for this new code.
>
> I will send patches changing the ones written by me.
>
Great, I'm hoping we can make the whole thing LGPL 2.1+ so that we can
allow libraries like libvirt to use it.
Regards,
Anthony Liguori
--
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-19 14:18 ` Anthony Liguori
@ 2009-10-22 8:49 ` Amit Shah
2009-10-22 14:01 ` Anthony Liguori
0 siblings, 1 reply; 28+ messages in thread
From: Amit Shah @ 2009-10-22 8:49 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Luiz Capitulino
On (Mon) Oct 19 2009 [09:18:19], Anthony Liguori wrote:
>>> + * 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.
>>> + *
>>> + */
>>>
>>
>> I see you're double licensing it to respect my initial choice, but you
>> can leave only LGPL for this new code.
>>
>> I will send patches changing the ones written by me.
>>
> Great, I'm hoping we can make the whole thing LGPL 2.1+ so that we can
> allow libraries like libvirt to use it.
Why 'or later'? Let's just stick to a version that we know and accept.
If you end up later liking version 3, you can change the text then.
Amit
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-22 8:49 ` Amit Shah
@ 2009-10-22 14:01 ` Anthony Liguori
2009-10-22 14:05 ` Amit Shah
2009-10-23 19:25 ` Jamie Lokier
0 siblings, 2 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-22 14:01 UTC (permalink / raw)
To: Amit Shah; +Cc: qemu-devel, Luiz Capitulino
Amit Shah wrote:
> On (Mon) Oct 19 2009 [09:18:19], Anthony Liguori wrote:
>
>>>> + * 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.
>>>> + *
>>>> + */
>>>>
>>>>
>>> I see you're double licensing it to respect my initial choice, but you
>>> can leave only LGPL for this new code.
>>>
>>> I will send patches changing the ones written by me.
>>>
>>>
>> Great, I'm hoping we can make the whole thing LGPL 2.1+ so that we can
>> allow libraries like libvirt to use it.
>>
>
> Why 'or later'? Let's just stick to a version that we know and accept.
> If you end up later liking version 3, you can change the text then.
>
It really doesn't matter in the context of LGPL so I don't mind if we do
2.1 only.
--
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-22 14:01 ` Anthony Liguori
@ 2009-10-22 14:05 ` Amit Shah
2009-10-23 19:25 ` Jamie Lokier
1 sibling, 0 replies; 28+ messages in thread
From: Amit Shah @ 2009-10-22 14:05 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Luiz Capitulino
On (Thu) Oct 22 2009 [09:01:48], Anthony Liguori wrote:
> Amit Shah wrote:
>> On (Mon) Oct 19 2009 [09:18:19], Anthony Liguori wrote:
>>
>>>>> + * 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.
>>>>> + *
>>>>> + */
>>>>>
>>>> I see you're double licensing it to respect my initial choice, but you
>>>> can leave only LGPL for this new code.
>>>>
>>>> I will send patches changing the ones written by me.
>>>>
>>> Great, I'm hoping we can make the whole thing LGPL 2.1+ so that we
>>> can allow libraries like libvirt to use it.
>>>
>>
>> Why 'or later'? Let's just stick to a version that we know and accept.
>> If you end up later liking version 3, you can change the text then.
>>
>
> It really doesn't matter in the context of LGPL so I don't mind if we do
> 2.1 only.
Yeah; better a known evil than an unknown one :-)
Amit
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-22 14:01 ` Anthony Liguori
2009-10-22 14:05 ` Amit Shah
@ 2009-10-23 19:25 ` Jamie Lokier
2009-10-23 19:36 ` Daniel P. Berrange
1 sibling, 1 reply; 28+ messages in thread
From: Jamie Lokier @ 2009-10-23 19:25 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Amit Shah, qemu-devel, Luiz Capitulino
Anthony Liguori wrote:
> It really doesn't matter in the context of LGPL so I don't mind if we do
> 2.1 only.
Is LGPL 2.1 compatible with LGPL 3 or GPL 3?
It would be a shame if it's compatible enough to use in libvirt but
can't be used in a GPL 3 project.
I think the recent JSON + QObject stuff is nice enough it may be
useful in other projects that have nothing to do with QEMU.
-- Jamie
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] Add support for qfloat
2009-10-23 19:25 ` Jamie Lokier
@ 2009-10-23 19:36 ` Daniel P. Berrange
0 siblings, 0 replies; 28+ messages in thread
From: Daniel P. Berrange @ 2009-10-23 19:36 UTC (permalink / raw)
To: Jamie Lokier; +Cc: Amit Shah, Anthony Liguori, qemu-devel, Luiz Capitulino
On Fri, Oct 23, 2009 at 08:25:49PM +0100, Jamie Lokier wrote:
> Anthony Liguori wrote:
> > It really doesn't matter in the context of LGPL so I don't mind if we do
> > 2.1 only.
>
> Is LGPL 2.1 compatible with LGPL 3 or GPL 3?
>
> It would be a shame if it's compatible enough to use in libvirt but
> can't be used in a GPL 3 project.
"LGPL 2.1 only" is not suitable for libvirt actually. Our license is
explicitly using "LGPL v2.1 or later" so that we can be compatible
with apps using (L)GPL3 too. So yeah I'd really recommend using 2.1+
too
Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 03/11] Add a test case for qfloat
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 01/11] Add append method to qstring and empty constructor Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 02/11] Add support for qfloat Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 14:00 ` Edgar E. Iglesias
2009-10-17 13:36 ` [Qemu-devel] [PATCH 04/11] Add json->qobject parser Anthony Liguori
` (8 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile | 2 +
check-qfloat.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure | 2 +-
3 files changed, 84 insertions(+), 1 deletions(-)
create mode 100644 check-qfloat.c
diff --git a/Makefile b/Makefile
index 9294638..aedb6c7 100644
--- a/Makefile
+++ b/Makefile
@@ -216,6 +216,8 @@ 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 ca6d45c..3e6f980 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-qfloat $tools"
fi
elif test "$mingw32" = "yes" ; then
tools="qemu-io\$(EXESUF) $tools"
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] Add a test case for qfloat
2009-10-17 13:36 ` [Qemu-devel] [PATCH 03/11] Add a test case " Anthony Liguori
@ 2009-10-17 14:00 ` Edgar E. Iglesias
2009-10-17 16:21 ` Anthony Liguori
0 siblings, 1 reply; 28+ messages in thread
From: Edgar E. Iglesias @ 2009-10-17 14:00 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Sat, Oct 17, 2009 at 08:36:03AM -0500, Anthony Liguori wrote:
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
> Makefile | 2 +
> check-qfloat.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Hello Anthony,
Shouldn't we put these tests under tests/something/ ?
Cheers
> configure | 2 +-
> 3 files changed, 84 insertions(+), 1 deletions(-)
> create mode 100644 check-qfloat.c
>
> diff --git a/Makefile b/Makefile
> index 9294638..aedb6c7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -216,6 +216,8 @@ 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 ca6d45c..3e6f980 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-qfloat $tools"
> fi
> elif test "$mingw32" = "yes" ; then
> tools="qemu-io\$(EXESUF) $tools"
> --
> 1.6.2.5
>
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] Add a test case for qfloat
2009-10-17 14:00 ` Edgar E. Iglesias
@ 2009-10-17 16:21 ` Anthony Liguori
0 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 16:21 UTC (permalink / raw)
To: Edgar E. Iglesias; +Cc: Anthony Liguori, qemu-devel
Edgar E. Iglesias wrote:
> On Sat, Oct 17, 2009 at 08:36:03AM -0500, Anthony Liguori wrote:
>
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> ---
>> Makefile | 2 +
>> check-qfloat.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>
>
>
> Hello Anthony,
>
> Shouldn't we put these tests under tests/something/ ?
>
Indeed, I think that would clean up things a bit too as the
configure/Makefile integration is a bit awkward. I'll take a look.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 04/11] Add json->qobject parser
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (2 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 03/11] Add a test case " Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-23 17:45 ` Luiz Capitulino
2009-10-17 13:36 ` [Qemu-devel] [PATCH 05/11] Add unit test for json parser Anthony Liguori
` (7 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
This implements a json parser that generates qobjects. The intention is that
this all can be eventually moved to a shared library to form the basis of the
QMP client API. Unfortunately, qobject is currently GPL licensed so hopefully
Luiz will switch it to LGPL.
The parser is a pretty straight forward recursive decent parser. It's based
on the grammar available at json.org. The only thing it doesn't implement
is support for the 'null' keyword. We have to decide how we want to implement
it.
It also introduces an extension to json--the ability to support strings quoted
with a single quote (similar to python). This makes writing dictionaries
considerably nicer in C.
This module also introduces a varargs parsing function that allows a printf-like
format to be used with the parsing function.
Finally, the parser returns the amount of input consumed. This is to make it
possible to determine the message boundaries in a stream of input.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile | 2 +-
qjson.c | 695 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qjson.h | 23 ++
3 files changed, 719 insertions(+), 1 deletions(-)
create mode 100644 qjson.c
create mode 100644 qjson.h
diff --git a/Makefile b/Makefile
index aedb6c7..1a99f66 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@ obj-y += net.o net-queue.o
obj-y += qemu-char.o aio.o net-checksum.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 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..64cecc6
--- /dev/null
+++ b/qjson.c
@@ -0,0 +1,695 @@
+/*
+ * QJSON 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.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qjson.h"
+
+typedef struct JSONParserContext
+{
+ const char *data;
+ int lineno;
+} JSONParserContext;
+
+#define BUG_ON(cond) assert(!(cond))
+
+/**
+ * TODO
+ *
+ * 3) determine if we need to support null
+ * 4) more vardac tests
+ */
+
+static QObject *parse_value(JSONParserContext *ctxt, const char *string, size_t *length, va_list *ap);
+
+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;
+}
+
+static void parse_error(JSONParserContext *ctxt, const char *at, const char *msg)
+{
+ const char *linestart = at;
+ const char *lineend = at;
+ char linebuf[80];
+ size_t len, pos;
+
+ while (linestart != ctxt->data && *(linestart - 1) != '\n') {
+ linestart--;
+ }
+
+ while (*lineend && *lineend != '\n') {
+ lineend++;
+ }
+
+ len = MIN(79, lineend - linestart);
+ memcpy(linebuf, linestart, len);
+ linebuf[len] = 0;
+
+ pos = at - linestart;
+
+ fprintf(stderr, "parse error: %s\n", msg);
+
+ if (pos <= len) {
+ fprintf(stderr, " %s\n", linebuf);
+ for (pos++; pos; pos--) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "^\n");
+ }
+
+}
+
+static size_t parse_skip(JSONParserContext *ctxt, const char *data)
+{
+ const char *ptr = data;
+
+ while (*ptr == ' ' || *ptr == '\r' || *ptr == '\n' ||
+ *ptr == '\t') {
+ if (*ptr == '\n') {
+ ctxt->lineno++;
+ }
+ ptr++;
+ }
+
+ return (ptr - data);
+}
+
+/**
+ * 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 *parse_string(JSONParserContext *ctxt,
+ const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ QString *str = NULL;
+ int double_quote = 1;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ /* handle string format */
+ if (ap) {
+ if (*ptr != '%') {
+ goto out;
+ }
+ ptr++;
+
+ if (*ptr != 's') {
+ goto out;
+ }
+ ptr++;
+
+ *length = (ptr - data);
+ return qstring_from_str(va_arg(*ap, const char *));
+ }
+
+ if (*ptr != '"' && *ptr != '\'') {
+ goto out;
+ }
+ 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, ptr,
+ "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, ptr, "invalid escape sequence in string");
+ goto out;
+ }
+ } else {
+ char dummy[2];
+
+ dummy[0] = *ptr++;
+ dummy[1] = 0;
+
+ qstring_append(str, dummy);
+ }
+ }
+
+ if ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\'')) {
+ parse_error(ctxt, ptr, "unterminated string literal");
+ goto out;
+ }
+ ptr++;
+
+ *length = (ptr - data);
+
+ return str;
+
+out:
+ QDECREF(str);
+ return NULL;
+}
+
+/**
+ * parse_number(): Parse a json number and return a QObject
+ *
+ * number
+ * int
+ * int frac
+ * int exp
+ * int frac exp
+ * int
+ * digit
+ * digit1-9 digits
+ * - digit
+ * - digit1-9 digits
+ * frac
+ * . digits
+ * exp
+ * e digits
+ * digits
+ * digit
+ * digit digits
+ * e
+ * e
+ * e+
+ * e-
+ * E
+ * E+
+ * E-
+ */
+static QObject *parse_number(JSONParserContext *ctxt,
+ const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ const char *number_start;
+ QInt *number = NULL;
+ int64_t value;
+ int factor = 1;
+ int non_integer = 0;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ number_start = ptr;
+
+ /* handle string format */
+ if (ap && *ptr == '%') {
+ int64_t value;
+
+ ptr++;
+
+ if (*ptr == 'd') {
+ /* int */
+ ptr++;
+ value = va_arg(*ap, int);
+ } else if (*ptr == 'l') {
+ ptr++;
+ if (*ptr == 'd') {
+ /* long */
+ ptr++;
+ value = va_arg(*ap, long);
+ } else if (*ptr == 'l') {
+ ptr++;
+ if (*ptr == 'd') {
+ ptr++;
+ value = va_arg(*ap, long long);
+ } else {
+ parse_error(ctxt, ptr, "invalid escape sequence");
+ goto out;
+ }
+ } else {
+ parse_error(ctxt, ptr, "invalid escape sequence");
+ goto out;
+ }
+ } else if (*ptr == 'f') {
+ double val;
+ ptr++;
+ *length = (ptr - data);
+ val = va_arg(*ap, double);
+ return QOBJECT(qfloat_from_double(val));
+ } else {
+ goto out;
+ }
+
+ *length = (ptr - data);
+ return QOBJECT(qint_from_int(value));
+ }
+
+ if (*ptr == '-') {
+ factor = -1;
+ ptr++;
+ }
+
+ if (*ptr == '0') {
+ value = 0;
+ ptr++;
+ } else if (*ptr >= '1' && *ptr <= '9') {
+ value = *ptr - '0';
+ ptr++;
+
+ while (*ptr >= '0' && *ptr <= '9') {
+ value *= 10;
+ value += *ptr - '0';
+ ptr++;
+ }
+
+ value *= factor;
+ } else {
+ goto out;
+ }
+
+ if (*ptr == '.') {
+ ptr++;
+
+ non_integer = 1;
+
+ if (!qemu_isdigit(*ptr)) {
+ parse_error(ctxt, ptr, "expecting mantissa");
+ goto out;
+ }
+ ptr++;
+
+ while (qemu_isdigit(*ptr)) {
+ ptr++;
+ }
+ }
+
+ if (*ptr == 'e' || *ptr == 'E') {
+ ptr++;
+
+ non_integer = 1;
+
+ if (*ptr == '-' || *ptr == '+') {
+ ptr++;
+ }
+
+ if (!qemu_isdigit(*ptr)) {
+ parse_error(ctxt, ptr, "expecting exponent");
+ goto out;
+ }
+ ptr++;
+
+ while (qemu_isdigit(*ptr)) {
+ ptr++;
+ }
+ }
+
+ *length = ptr - data;
+
+ if (non_integer) {
+ char buffer[129];
+
+ if ((ptr - number_start) > 128) {
+ parse_error(ctxt, ptr, "floating point too larger");
+ goto out;
+ }
+
+ memcpy(buffer, number_start, (ptr - number_start));
+ buffer[ptr - number_start] = 0;
+
+ /* floats are hard to parse so punt to libc */
+ return QOBJECT(qfloat_from_double(strtod(buffer, NULL)));
+ } else {
+ return QOBJECT(qint_from_int(value));
+ }
+
+out:
+ QDECREF(number);
+ return NULL;
+}
+
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ QString *key;
+ QObject *value;
+ size_t len = 0;
+
+ key = parse_string(ctxt, ptr, &len, ap);
+ if (key == NULL) {
+ parse_error(ctxt, ptr, "Dict key requires string");
+ goto out;
+ }
+ ptr += len;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (*ptr != ':') {
+ QDECREF(key);
+ parse_error(ctxt, ptr, "Missing separator in dict");
+ goto out;
+ }
+ ptr++;
+
+ value = parse_value(ctxt, ptr, &len, ap);
+ if (value == NULL) {
+ QDECREF(key);
+ parse_error(ctxt, ptr, "Missing value in dict");
+ goto out;
+ }
+ ptr += len;
+
+ qdict_put_obj(dict, qstring_get_str(key), value);
+ QDECREF(key);
+
+ *length = ptr - data;
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static QObject *parse_object(JSONParserContext *ctxt, const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ QDict *dict = NULL;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (*ptr != '{') {
+ goto out;
+ }
+ ptr++;
+
+ dict = qdict_new();
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (*ptr && *ptr != '}') {
+ size_t len = 0;
+
+ if (parse_pair(ctxt, dict, ptr, &len, ap) == -1) {
+ goto out;
+ }
+
+ ptr += len;
+ }
+
+ ptr += parse_skip(ctxt, ptr);
+
+ while (*ptr && *ptr != '}') {
+ size_t len = 0;
+
+ if (*ptr != ',') {
+ parse_error(ctxt, ptr, "expected separator in dict");
+ goto out;
+ }
+ ptr++;
+
+ if (parse_pair(ctxt, dict, ptr, &len, ap) == -1) {
+ goto out;
+ }
+ ptr += len;
+
+ ptr += parse_skip(ctxt, ptr);
+ }
+
+ if (*ptr != '}') {
+ parse_error(ctxt, ptr, "unterminated dict");
+ goto out;
+ }
+ ptr++;
+
+ *length = ptr - data;
+
+ return QOBJECT(dict);
+
+out:
+ QDECREF(dict);
+ return NULL;
+}
+
+static QObject *parse_array(JSONParserContext *ctxt, const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ QList *list = NULL;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (*ptr != '[') {
+ goto out;
+ }
+ ptr++;
+
+ list = qlist_new();
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (*ptr && *ptr != ']') {
+ size_t len = 0;
+ QObject *obj;
+
+ obj = parse_value(ctxt, ptr, &len, ap);
+ if (obj == NULL) {
+ parse_error(ctxt, ptr, "expecting value");
+ goto out;
+ }
+ ptr += len;
+
+ qlist_append_obj(list, obj);
+ }
+
+ ptr += parse_skip(ctxt, ptr);
+
+ while (*ptr && *ptr != ']') {
+ size_t len = 0;
+ QObject *obj;
+
+ if (*ptr != ',') {
+ parse_error(ctxt, ptr, "expected separator in list");
+ goto out;
+ }
+ ptr++;
+
+ obj = parse_value(ctxt, ptr, &len, ap);
+ if (obj == NULL) {
+ parse_error(ctxt, ptr, "expecting value");
+ goto out;
+ }
+ ptr += len;
+
+ qlist_append_obj(list, obj);
+
+ ptr += parse_skip(ctxt, ptr);
+ }
+
+ if (*ptr != ']') {
+ parse_error(ctxt, ptr, "unterminated array");
+ goto out;
+ }
+ ptr++;
+
+ *length = ptr - data;
+
+ return QOBJECT(list);
+
+out:
+ QDECREF(list);
+ return NULL;
+}
+
+static QObject *parse_keyword(JSONParserContext *ctxt, const char *data, size_t *length)
+{
+ const char *ptr = data;
+ QString *str;
+ QObject *obj = NULL;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ str = qstring_new();
+
+ while (*ptr >= 'a' && *ptr <= 'z') {
+ char buf[2];
+
+ buf[0] = *ptr;
+ buf[1] = 0;
+ ptr++;
+
+ qstring_append(str, buf);
+ }
+
+ if (strcmp(qstring_get_str(str), "true") == 0) {
+ obj = QOBJECT(qint_from_int(1));
+ } else if (strcmp(qstring_get_str(str), "false") == 0) {
+ obj = QOBJECT(qint_from_int(0));
+ }
+
+ if (obj) {
+ *length = ptr - data;
+ }
+
+ QDECREF(str);
+
+ return obj;
+}
+
+static QObject *parse_value(JSONParserContext *ctxt, const char *string, size_t *length, va_list *ap)
+{
+ QObject *obj;
+
+ obj = QOBJECT(parse_string(ctxt, string, length, ap));
+ if (obj == NULL) {
+ obj = parse_number(ctxt, string, length, ap);
+ }
+ if (obj == NULL) {
+ obj = parse_object(ctxt, string, length, ap);
+ }
+ if (obj == NULL) {
+ obj = parse_array(ctxt, string, length, ap);
+ }
+ if (obj == NULL) {
+ obj = parse_keyword(ctxt, string, length);
+ }
+
+ return obj;
+}
+
+static QObject *parse_json(const char *string, size_t *length, va_list *ap)
+{
+ JSONParserContext ctxt = {};
+ size_t dummy_length = 0;
+
+ if (length == NULL) {
+ length = &dummy_length;
+ }
+
+ ctxt.data = string;
+ ctxt.lineno = 0;
+
+ return parse_value(&ctxt, string, length, ap);
+}
+
+QObject *qobject_from_json(const char *string, size_t *length)
+{
+ return parse_json(string, length, NULL);
+}
+
+QObject *qobject_from_jsonf(const char *string, size_t *length, ...)
+{
+ QObject *obj;
+ va_list ap;
+
+ va_start(ap, length);
+ obj = parse_json(string, length,&ap);
+ va_end(ap);
+
+ return obj;
+}
diff --git a/qjson.h b/qjson.h
new file mode 100644
index 0000000..0c94954
--- /dev/null
+++ b/qjson.h
@@ -0,0 +1,23 @@
+/*
+ * QJSON 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 QJSON_H
+#define QJSON_H
+
+#include "qobject.h"
+
+QObject *qobject_from_json(const char *string, size_t *length);
+QObject *qobject_from_jsonf(const char *string, size_t *length, ...)
+ __attribute__((__format__ (__printf__, 1, 3)));
+
+#endif /* QJSON_H */
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 05/11] Add unit test for json parser
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (3 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 04/11] Add json->qobject parser Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 06/11] qobject: add QBool type Anthony Liguori
` (6 subsequent siblings)
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
I've attempted to make this a very thorough unit test for the json parser. It
covers every rule and tries to test the corner cases of each rule.
There's some interesting things in this test case like a literal qobject
type. It may be worth extract that into common code.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile | 2 +-
check-qjson.c | 586 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure | 2 +-
3 files changed, 588 insertions(+), 2 deletions(-)
create mode 100644 check-qjson.c
diff --git a/Makefile b/Makefile
index 1a99f66..8b80150 100644
--- a/Makefile
+++ b/Makefile
@@ -217,7 +217,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 qjson.o qstring.o qint.o qdict.o qlist.o qfloat.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..0f661b9
--- /dev/null
+++ b/check-qjson.c
@@ -0,0 +1,586 @@
+/*
+ * 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 "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_jsonf("%s", &length, test_cases[i].decoded);
+
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+ fail_unless(length == 2);
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_jsonf("%d", &length, value);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(length == 2);
+
+ qint = qobject_to_qint(obj);
+ fail_unless(qint_get_int(qint) == value);
+
+ QDECREF(qint);
+
+ obj = qobject_from_jsonf("%" PRId64, &length, value64);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(length == 1 + strlen(PRId64));
+
+ qint = qobject_to_qint(obj);
+ fail_unless(qint_get_int(qint) == value64);
+
+ QDECREF(qint);
+
+ obj = qobject_from_jsonf("%f", &length, valuef);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+ fail_unless(length == 2);
+
+ qfloat = qobject_to_qfloat(obj);
+ fail_unless(qfloat_get_double(qfloat) == valuef);
+
+ QDECREF(qfloat);
+}
+END_TEST
+
+START_TEST(keyword_literal)
+{
+ QObject *obj;
+ QInt *qint;
+ size_t length = 0;
+
+ obj = qobject_from_json("true", &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(length == 4);
+
+ qint = qobject_to_qint(obj);
+ fail_unless(qint_get_int(qint) != 0);
+
+ QDECREF(qint);
+
+ obj = qobject_from_json("false", &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(length == 5);
+
+ qint = qobject_to_qint(obj);
+ fail_unless(qint_get_int(qint) == 0);
+
+ QDECREF(qint);
+}
+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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QDICT);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QLIST);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ 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;
+ size_t length = 0;
+
+ obj = qobject_from_json(test_cases[i].encoded, &length);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QLIST);
+ fail_unless(length == strlen(test_cases[i].encoded));
+
+ fail_unless(compare_litqobj_to_qobj(&test_cases[i].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;
+
+ 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);
+
+ 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);
+
+ 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 3e6f980..24caaac 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 check-qfloat $tools"
+ tools="check-qint check-qstring check-qdict check-qlist 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] 28+ messages in thread
* [Qemu-devel] [PATCH 06/11] qobject: add QBool type
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (4 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 05/11] Add unit test for json parser Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-18 21:50 ` Luiz Capitulino
2009-10-17 13:36 ` [Qemu-devel] [PATCH 07/11] qjson: Use QBool for true/false keywords Anthony Liguori
` (5 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
We currently model as json bool as an int. This works fine on the server side
but it means we cannot send back proper bools to the client. Introducing a
proper QBool type fixes that.
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 8b80150..095d2ce 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@ obj-y += net.o net-queue.o
obj-y += qemu-char.o aio.o net-checksum.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 qjson.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qjson.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 da03a5e..167b607 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] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 06/11] qobject: add QBool type
2009-10-17 13:36 ` [Qemu-devel] [PATCH 06/11] qobject: add QBool type Anthony Liguori
@ 2009-10-18 21:50 ` Luiz Capitulino
2009-10-19 14:17 ` Anthony Liguori
0 siblings, 1 reply; 28+ messages in thread
From: Luiz Capitulino @ 2009-10-18 21:50 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Sat, 17 Oct 2009 08:36:06 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> We currently model as json bool as an int. This works fine on the server side
> but it means we cannot send back proper bools to the client. Introducing a
> proper QBool type fixes that.
As we talked earlier today, I think it would be simpler to have QTrue,
QFalse and QNull as static objects.
We could define that static objects get reference counting disabled, I don't
see issues in doing that and we get a very simple model.
The big patch bellow does it, only compiled tested though.
If you don't agree with this model, we'll have to allocate QNull objects.
Actually I would suggest a destroy() method which always resets the
refcount to 1, but then it will have the concurrency problems on threaded
applications you've mentioned.
diff --git a/Makefile b/Makefile
index e78a3d0..1f985cf 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@ obj-y += net.o net-queue.o
obj-y += qemu-char.o aio.o net-checksum.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 qmisc.o qemu-config.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qmisc.c b/qmisc.c
new file mode 100644
index 0000000..38a87dd
--- /dev/null
+++ b/qmisc.c
@@ -0,0 +1,31 @@
+#include "qmisc.h"
+
+/*
+ * QBool
+ */
+
+static const QType qbool_type = {
+ .code = QTYPE_QBOOL,
+};
+
+const QBool QTrue = {
+ QOBJECT_INIT_STATIC(&qbool_type),
+ .value = 1
+};
+
+const QBool QFalse = {
+ QOBJECT_INIT_STATIC(&qbool_type),
+ .value = 0
+};
+
+/*
+ * QNull
+ */
+
+static const QType qnull_type = {
+ .code = QTYPE_QNULL,
+};
+
+const qnull QNull = {
+ QOBJECT_INIT_STATIC(&qnull_type),
+};
diff --git a/qmisc.h b/qmisc.h
new file mode 100644
index 0000000..dd9d5a9
--- /dev/null
+++ b/qmisc.h
@@ -0,0 +1,38 @@
+#ifndef QMISC_H
+#define QMISC_H
+
+#include "qobject.h"
+
+/*
+ * QBool
+ */
+
+typedef struct QBool {
+ QObject_HEAD;
+ int value;
+} QBool;
+
+extern const QBool QTrue;
+extern const QBool QFalse;
+
+static inline int qbool_is_true(const QBool *qbool)
+{
+ return qbool->value;
+}
+
+static inline int qbool_is_false(const QBool *qbool)
+{
+ return !qbool->value;
+}
+
+/*
+ * QNull
+ */
+
+typedef struct qnull {
+ QObject_HEAD;
+} qnull;
+
+extern const qnull QNull;
+
+#endif /* QMISC_H */
diff --git a/qobject.h b/qobject.h
index 4cc9287..81e4d94 100644
--- a/qobject.h
+++ b/qobject.h
@@ -41,6 +41,8 @@ typedef enum {
QTYPE_QSTRING,
QTYPE_QDICT,
QTYPE_QLIST,
+ QTYPE_QBOOL,
+ QTYPE_QNULL,
} qtype_code;
struct QObject;
@@ -75,12 +77,15 @@ typedef struct QObject {
obj->base.refcnt = 1; \
obj->base.type = qtype_type
+#define QOBJECT_INIT_STATIC(qtype_type) \
+ .base.type = qtype_type
+
/**
* qobject_incref(): Increment QObject's reference count
*/
static inline void qobject_incref(QObject *obj)
{
- if (obj)
+ if (obj && obj->type->destroy)
obj->refcnt++;
}
@@ -90,9 +95,7 @@ static inline void qobject_incref(QObject *obj)
*/
static inline void qobject_decref(QObject *obj)
{
- if (obj && --obj->refcnt == 0) {
- assert(obj->type != NULL);
- assert(obj->type->destroy != NULL);
+ if (obj && obj->type->destroy && --obj->refcnt == 0) {
obj->type->destroy(obj);
}
}
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 06/11] qobject: add QBool type
2009-10-18 21:50 ` Luiz Capitulino
@ 2009-10-19 14:17 ` Anthony Liguori
2009-10-19 14:21 ` Luiz Capitulino
0 siblings, 1 reply; 28+ messages in thread
From: Anthony Liguori @ 2009-10-19 14:17 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel
Luiz Capitulino wrote:
> On Sat, 17 Oct 2009 08:36:06 -0500
> Anthony Liguori <aliguori@us.ibm.com> wrote:
>
>
>> We currently model as json bool as an int. This works fine on the server side
>> but it means we cannot send back proper bools to the client. Introducing a
>> proper QBool type fixes that.
>>
>
> As we talked earlier today, I think it would be simpler to have QTrue,
> QFalse and QNull as static objects.
>
> We could define that static objects get reference counting disabled, I don't
> see issues in doing that and we get a very simple model.
>
> The big patch bellow does it, only compiled tested though.
>
> If you don't agree with this model, we'll have to allocate QNull objects.
> Actually I would suggest a destroy() method which always resets the
> refcount to 1, but then it will have the concurrency problems on threaded
> applications you've mentioned.
>
A lot of object systems have dealt with this in various ways. The
trouble with reference counting is usually thread safety. CLR goes to
great lengths to make their objects reference counting thread safe and
it comes at a cost. Python doesn't do anything explicit and it's one of
the reasons that they're stuck with a big lock.
Since I'd like to expose QObject to client libraries, having a single
static instance would be pretty unfortunate as it would imply a weird
locking semantics. Disabling reference counts for QNull/QBool seems
unfortunate because it suggests that different semantics for certain
objects.
I think this is a premature optimization. I don't think we need to try
and save the memory here.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 06/11] qobject: add QBool type
2009-10-19 14:17 ` Anthony Liguori
@ 2009-10-19 14:21 ` Luiz Capitulino
0 siblings, 0 replies; 28+ messages in thread
From: Luiz Capitulino @ 2009-10-19 14:21 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Mon, 19 Oct 2009 09:17:38 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> Luiz Capitulino wrote:
> > On Sat, 17 Oct 2009 08:36:06 -0500
> > Anthony Liguori <aliguori@us.ibm.com> wrote:
> >
> >
> >> We currently model as json bool as an int. This works fine on the server side
> >> but it means we cannot send back proper bools to the client. Introducing a
> >> proper QBool type fixes that.
> >>
> >
> > As we talked earlier today, I think it would be simpler to have QTrue,
> > QFalse and QNull as static objects.
> >
> > We could define that static objects get reference counting disabled, I don't
> > see issues in doing that and we get a very simple model.
> >
> > The big patch bellow does it, only compiled tested though.
> >
> > If you don't agree with this model, we'll have to allocate QNull objects.
> > Actually I would suggest a destroy() method which always resets the
> > refcount to 1, but then it will have the concurrency problems on threaded
> > applications you've mentioned.
> >
>
> A lot of object systems have dealt with this in various ways. The
> trouble with reference counting is usually thread safety. CLR goes to
> great lengths to make their objects reference counting thread safe and
> it comes at a cost. Python doesn't do anything explicit and it's one of
> the reasons that they're stuck with a big lock.
>
> Since I'd like to expose QObject to client libraries, having a single
> static instance would be pretty unfortunate as it would imply a weird
> locking semantics. Disabling reference counts for QNull/QBool seems
> unfortunate because it suggests that different semantics for certain
> objects.
>
> I think this is a premature optimization. I don't think we need to try
> and save the memory here.
You can add QNull in your series then.
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 07/11] qjson: Use QBool for true/false keywords
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (5 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 06/11] qobject: add QBool type Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 08/11] qjson: add %i for parsing bools Anthony Liguori
` (4 subsequent siblings)
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
Instead of parsing true/false as QInt, parse them as QBool and update the
test suite accordingly.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile | 2 +-
check-qjson.c | 19 ++++++++++---------
qjson.c | 5 +++--
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/Makefile b/Makefile
index 095d2ce..fe6c9bf 100644
--- a/Makefile
+++ b/Makefile
@@ -217,7 +217,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 qjson.o qstring.o qint.o qdict.o qlist.o qfloat.o qemu-malloc.o
+check-qjson: check-qjson.o qjson.o qstring.o qint.o qdict.o qlist.o qfloat.o qbool.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
index 0f661b9..32aa33c 100644
--- a/check-qjson.c
+++ b/check-qjson.c
@@ -15,6 +15,7 @@
#include "qdict.h"
#include "qlist.h"
#include "qfloat.h"
+#include "qbool.h"
#include "qjson.h"
#include "qemu-common.h"
@@ -259,28 +260,28 @@ END_TEST
START_TEST(keyword_literal)
{
QObject *obj;
- QInt *qint;
+ QBool *qbool;
size_t length = 0;
obj = qobject_from_json("true", &length);
fail_unless(obj != NULL);
- fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(qobject_type(obj) == QTYPE_QBOOL);
fail_unless(length == 4);
- qint = qobject_to_qint(obj);
- fail_unless(qint_get_int(qint) != 0);
+ qbool = qobject_to_qbool(obj);
+ fail_unless(qbool_get_int(qbool) != 0);
- QDECREF(qint);
+ QDECREF(qbool);
obj = qobject_from_json("false", &length);
fail_unless(obj != NULL);
- fail_unless(qobject_type(obj) == QTYPE_QINT);
+ fail_unless(qobject_type(obj) == QTYPE_QBOOL);
fail_unless(length == 5);
- qint = qobject_to_qint(obj);
- fail_unless(qint_get_int(qint) == 0);
+ qbool = qobject_to_qbool(obj);
+ fail_unless(qbool_get_int(qbool) == 0);
- QDECREF(qint);
+ QDECREF(qbool);
}
END_TEST
diff --git a/qjson.c b/qjson.c
index 64cecc6..ce2c942 100644
--- a/qjson.c
+++ b/qjson.c
@@ -17,6 +17,7 @@
#include "qdict.h"
#include "qlist.h"
#include "qfloat.h"
+#include "qbool.h"
#include "qjson.h"
typedef struct JSONParserContext
@@ -627,9 +628,9 @@ static QObject *parse_keyword(JSONParserContext *ctxt, const char *data, size_t
}
if (strcmp(qstring_get_str(str), "true") == 0) {
- obj = QOBJECT(qint_from_int(1));
+ obj = QOBJECT(qbool_from_int(1));
} else if (strcmp(qstring_get_str(str), "false") == 0) {
- obj = QOBJECT(qint_from_int(0));
+ obj = QOBJECT(qbool_from_int(0));
}
if (obj) {
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 08/11] qjson: add %i for parsing bools
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (6 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 07/11] qjson: Use QBool for true/false keywords Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 09/11] qjson: add unit test for varargs bool parsing Anthony Liguori
` (3 subsequent siblings)
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
Not a wonderful choice in conversion characters but nothing else seems better.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
qjson.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/qjson.c b/qjson.c
index ce2c942..9279bfb 100644
--- a/qjson.c
+++ b/qjson.c
@@ -339,6 +339,12 @@ static QObject *parse_number(JSONParserContext *ctxt,
parse_error(ctxt, ptr, "invalid escape sequence");
goto out;
}
+ } else if (*ptr == 'i') {
+ int val;
+ ptr++;
+ *length = ptr - data;
+ val = va_arg(*ap, int);
+ return QOBJECT(qbool_from_int(val));
} else if (*ptr == 'f') {
double val;
ptr++;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 09/11] qjson: add unit test for varargs bool parsing
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (7 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 08/11] qjson: add %i for parsing bools Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 10/11] qjson: add vararg format for embedded qobjects Anthony Liguori
` (2 subsequent siblings)
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
check-qjson.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/check-qjson.c b/check-qjson.c
index 32aa33c..8760941 100644
--- a/check-qjson.c
+++ b/check-qjson.c
@@ -9,6 +9,7 @@
*
*/
#include <check.h>
+#include <stdbool.h>
#include "qstring.h"
#include "qint.h"
@@ -282,6 +283,26 @@ START_TEST(keyword_literal)
fail_unless(qbool_get_int(qbool) == 0);
QDECREF(qbool);
+
+ obj = qobject_from_jsonf("%i", &length, false);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+ fail_unless(length == 2);
+
+ qbool = qobject_to_qbool(obj);
+ fail_unless(qbool_get_int(qbool) == 0);
+
+ QDECREF(qbool);
+
+ obj = qobject_from_jsonf("%i", &length, true);
+ fail_unless(obj != NULL);
+ fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+ fail_unless(length == 2);
+
+ qbool = qobject_to_qbool(obj);
+ fail_unless(qbool_get_int(qbool) != 0);
+
+ QDECREF(qbool);
}
END_TEST
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 10/11] qjson: add vararg format for embedded qobjects
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (8 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 09/11] qjson: add unit test for varargs bool parsing Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-17 13:36 ` [Qemu-devel] [PATCH 11/11] qjson: add unit test to check %p format Anthony Liguori
2009-10-18 21:34 ` [Qemu-devel] [PATCH 0/11] json parser (v2) Luiz Capitulino
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
%p lets you specify an already constructed qobject. It takes a weak reference.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
qjson.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/qjson.c b/qjson.c
index 9279bfb..7bedaf3 100644
--- a/qjson.c
+++ b/qjson.c
@@ -648,6 +648,28 @@ static QObject *parse_keyword(JSONParserContext *ctxt, const char *data, size_t
return obj;
}
+static QObject *parse_qobject(JSONParserContext *ctxt, const char *data, size_t *length, va_list *ap)
+{
+ const char *ptr = data;
+ QObject *obj = NULL;
+
+ ptr += parse_skip(ctxt, ptr);
+
+ if (ap && *ptr == '%') {
+ ptr++;
+ if (*ptr == 'p') {
+ ptr++;
+
+ obj = va_arg(*ap, QObject *);
+ qobject_incref(obj);
+ *length = (ptr - data);
+ return obj;
+ }
+ }
+
+ return NULL;
+}
+
static QObject *parse_value(JSONParserContext *ctxt, const char *string, size_t *length, va_list *ap)
{
QObject *obj;
@@ -665,6 +687,9 @@ static QObject *parse_value(JSONParserContext *ctxt, const char *string, size_t
if (obj == NULL) {
obj = parse_keyword(ctxt, string, length);
}
+ if (obj == NULL) {
+ obj = parse_qobject(ctxt, string, length, ap);
+ }
return obj;
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 11/11] qjson: add unit test to check %p format
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (9 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 10/11] qjson: add vararg format for embedded qobjects Anthony Liguori
@ 2009-10-17 13:36 ` Anthony Liguori
2009-10-18 21:34 ` [Qemu-devel] [PATCH 0/11] json parser (v2) Luiz Capitulino
11 siblings, 0 replies; 28+ messages in thread
From: Anthony Liguori @ 2009-10-17 13:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
check-qjson.c | 33 ++++++++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 1 deletions(-)
diff --git a/check-qjson.c b/check-qjson.c
index 8760941..9be1448 100644
--- a/check-qjson.c
+++ b/check-qjson.c
@@ -551,11 +551,38 @@ START_TEST(simple_whitespace)
}
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]", NULL);
+ fail_unless(embedded_obj != NULL);
+
+ obj = qobject_from_jsonf("[%d, 2, %p]", NULL, 1, embedded_obj);
+ fail_unless(obj != NULL);
+
+ qobject_decref(embedded_obj);
+
+ 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;
+ TCase *dicts, *lists, *whitespace, *varargs;
string_literals = tcase_create("String Literals");
tcase_add_test(string_literals, simple_string);
@@ -580,6 +607,9 @@ static Suite *qjson_suite(void)
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);
@@ -587,6 +617,7 @@ static Suite *qjson_suite(void)
suite_add_tcase(suite, dicts);
suite_add_tcase(suite, lists);
suite_add_tcase(suite, whitespace);
+ suite_add_tcase(suite, varargs);
return suite;
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 0/11] json parser (v2)
2009-10-17 13:36 [Qemu-devel] [PATCH 0/11] json parser (v2) Anthony Liguori
` (10 preceding siblings ...)
2009-10-17 13:36 ` [Qemu-devel] [PATCH 11/11] qjson: add unit test to check %p format Anthony Liguori
@ 2009-10-18 21:34 ` Luiz Capitulino
11 siblings, 0 replies; 28+ messages in thread
From: Luiz Capitulino @ 2009-10-18 21:34 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Sat, 17 Oct 2009 08:36:00 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> I fat-fingered the git send-email command the first time so here's the second
> iteration.
Got it now..
> This series introduces a json parsing framework. The parser is a recursive
> decent parser and implements the full json spec except for the null keyword. We
> need to decide how we want to model null in order to support this.
>
> In addition, we implement an extension to allow single quote strings. This
> is very useful for defining dictionaries in C.
>
> The parser has a full test suite and introduces a boolean and float type.
Very nice, this is obviously way beyond the simple approach I was following,
I have some minor comments and will reply some patches. Will also run some
tests later today, but I don't think I'll find any issue (given that you have
written unit-tests!).
What's you merge plan for your own patches? :)
^ permalink raw reply [flat|nested] 28+ messages in thread