On Thu, Nov 26, 2009 at 06:27:19PM +0000, Daniel P. Berrange wrote: > This introduces simple API for handling JSON data. There is > an internal data structure 'virJSONValuePtr' which stores a > arbitrary nested JSON value (number, string, array, object, > nul, etc). There are APIs for constructing/querying objects > and APIs for parsing/formatting string formatted JSON data. > > This uses the YAJL library for parsing/formatting from > > http://lloyd.github.com/yajl/ > * src/util/json.h, src/util/json.c: Data structures and APIs > for representing JSON data, and parsing/formatting it > * configure.in: Add check for yajl library > * libvirt.spec.in: Add build requires for yajl > * src/Makefile.am: Add json.c/h > * src/libvirt_private.syms: Export JSON symbols to drivers hum ... that becomes an external library, one more dependancy on the other hand we don't have to track bug fixes.... how widely used is yajl ? > --- > configure.in | 55 +++ > libvirt.spec.in | 14 + > po/POTFILES.in | 1 + > src/Makefile.am | 8 +- > src/libvirt_private.syms | 47 ++ > src/util/json.c | 1043 ++++++++++++++++++++++++++++++++++++++++++++++ > src/util/json.h | 131 ++++++ I see that we are encapsulating it and exposing a completely distinct API, that's fine then, we can switch or embbed our own if needed later. > 7 files changed, 1296 insertions(+), 3 deletions(-) > create mode 100644 src/util/json.c > create mode 100644 src/util/json.h > > diff --git a/configure.in b/configure.in > index f735bba..41f50fc 100644 > --- a/configure.in > +++ b/configure.in > @@ -645,6 +645,56 @@ AC_SUBST([SASL_CFLAGS]) > AC_SUBST([SASL_LIBS]) > > > +dnl YAJL JSON library http://lloyd.github.com/yajl/ > +AC_ARG_WITH([yajl], > + [ --with-yajl use YAJL for JSON parsing/formatting], > + [], > + [with_yajl=check]) > + > +YAJL_CFLAGS= > +YAJL_LIBS= > +if test "x$with_yajl" != "xno"; then > + if test "x$with_yajl" != "xyes" -a "x$with_yajl" != "xcheck"; then > + YAJL_CFLAGS="-I$with_yajl/include" > + YAJL_LIBS="-L$with_yajl/lib" > + fi > + fail=0 > + old_cppflags="$CPPFLAGS" > + old_ldflags="$LDFLAGS" > + CPPFLAGS="$CPPFLAGS $YAJL_CFLAGS" > + LDFLAGS="$LDFLAGS $YAJL_LIBS" > + AC_CHECK_HEADER([yajl/yajl_common.h],[],[ > + if test "x$with_yajl" != "xcheck" ; then > + with_yajl=no > + else > + fail=1 > + fi]) > + if test "x$with_yajl" != "xno" ; then > + AC_CHECK_LIB([yajl], [yajl_parse],[ > + YAJL_LIBS="$YAJL_LIBS -lyajl" > + with_yajl=yes > + ],[ > + if test "x$with_yajl" = "xcheck" ; then > + with_yajl=no > + else > + fail=1 > + fi > + ]) > + fi > + test $fail = 1 && > + AC_MSG_ERROR([You must install the YAJL development package in order to compile libvirt]) > + CPPFLAGS="$old_cppflags" > + LDFLAGS="$old_ldflags" > + if test "x$with_yajl" = "xyes" ; then > + AC_DEFINE_UNQUOTED([HAVE_YAJL], 1, > + [whether YAJL is available for JSON parsing/formatting]) > + fi > +fi > +AM_CONDITIONAL([HAVE_YAJL], [test "x$with_yajl" = "xyes"]) > +AC_SUBST([YAJL_CFLAGS]) > +AC_SUBST([YAJL_LIBS]) > + > + > dnl PolicyKit library > POLKIT_CFLAGS= > POLKIT_LIBS= > @@ -1859,6 +1909,11 @@ AC_MSG_NOTICE([ sasl: $SASL_CFLAGS $SASL_LIBS]) > else > AC_MSG_NOTICE([ sasl: no]) > fi > +if test "$with_yajl" != "no" ; then > +AC_MSG_NOTICE([ yajl: $YAJL_CFLAGS $YAJL_LIBS]) > +else > +AC_MSG_NOTICE([ yajl: no]) > +fi > if test "$with_avahi" = "yes" ; then > AC_MSG_NOTICE([ avahi: $AVAHI_CFLAGS $AVAHI_LIBS]) > else > diff --git a/libvirt.spec.in b/libvirt.spec.in > index dba14df..408ad05 100644 > --- a/libvirt.spec.in > +++ b/libvirt.spec.in > @@ -60,6 +60,7 @@ > %define with_netcf 0%{!?_without_netcf:0} > %define with_udev 0%{!?_without_udev:0} > %define with_hal 0%{!?_without_hal:0} > +%define with_yajl 0%{!?_without_yajl:0} > > # Non-server/HV driver defaults which are always enabled > %define with_python 0%{!?_without_python:1} > @@ -141,6 +142,11 @@ > %define with_hal 0%{!?_without_hal:%{server_drivers}} > %endif > > +# Enable yajl library for JSON mode with QEMU > +%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6 > +%define with_yajl 0%{!?_without_yajl:%{server_drivers}} > +%endif > + yajl is not in F12, did someone add it to rawhide already ? > # Force QEMU to run as non-root > %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 > %define qemu_user qemu > @@ -257,6 +263,9 @@ BuildRequires: hal-devel > BuildRequires: libudev-devel >= 145 > BuildRequires: libpciaccess-devel >= 0.10.9 > %endif > +%if %{with_yajl} > +BuildRequires: yajl-devel > +%endif > %if %{with_avahi} > BuildRequires: avahi-devel > %endif > @@ -495,6 +504,10 @@ of recent versions of Linux (and other OSes). > %define _without_udev --without-udev > %endif > > +%if ! %{with_yajl} > +%define _without_yajl --without-yajl > +%endif > + > %configure %{?_without_xen} \ > %{?_without_qemu} \ > %{?_without_openvz} \ > @@ -522,6 +535,7 @@ of recent versions of Linux (and other OSes). > %{?_without_selinux} \ > %{?_without_hal} \ > %{?_without_udev} \ > + %{?_without_yajl} \ > --with-qemu-user=%{qemu_user} \ > --with-qemu-group=%{qemu_group} \ > --with-init-script=redhat \ > diff --git a/po/POTFILES.in b/po/POTFILES.in > index 116aa87..9864259 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -50,6 +50,7 @@ src/uml/uml_driver.c > src/util/bridge.c > src/util/conf.c > src/util/iptables.c > +src/util/json.c > src/util/logging.c > src/util/pci.c > src/util/processinfo.c > diff --git a/src/Makefile.am b/src/Makefile.am > index 9a3c9c8..b0775a8 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -52,6 +52,7 @@ UTIL_SOURCES = \ > util/hash.c util/hash.h \ > util/iptables.c util/iptables.h \ > util/ebtables.c util/ebtables.h \ > + util/json.c util/json.h \ > util/logging.c util/logging.h \ > util/memory.c util/memory.h \ > util/pci.c util/pci.h \ > @@ -283,8 +284,8 @@ noinst_LTLIBRARIES = libvirt_util.la > libvirt_la_LIBADD = libvirt_util.la > libvirt_util_la_SOURCES = \ > $(UTIL_SOURCES) > -libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) > -libvirt_util_la_LDFLAGS = $(CAPNG_LIBS) > +libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) > +libvirt_util_la_LDFLAGS = $(CAPNG_LIBS) $(YAJL_LIBS) > > > noinst_LTLIBRARIES += libvirt_conf.la > @@ -828,12 +829,13 @@ libvirt_lxc_SOURCES = \ > $(NODE_INFO_SOURCES) \ > $(ENCRYPTION_CONF_SOURCES) \ > $(DOMAIN_CONF_SOURCES) > -libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) > +libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS) > libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la > libvirt_lxc_CFLAGS = \ > $(LIBPARTED_CFLAGS) \ > $(NUMACTL_CFLAGS) \ > $(CAPNG_CFLAGS) \ > + $(YAJL_CFLAGS) \ > -I@top_srcdir@/src/conf > endif > endif > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index e880c2e..ee7f3ed 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -269,6 +269,53 @@ virRegisterDeviceMonitor; > virRegisterSecretDriver; > > > +# json.h > +virJSONValueFree; > +virJSONValueNewString; > +virJSONValueNewStringLen; > +virJSONValueNewNumberInt; > +virJSONValueNewNumberUint; > +virJSONValueNewNumberLong; > +virJSONValueNewNumberUlong; > +virJSONValueNewNumberDouble; > +virJSONValueNewBoolean; > +virJSONValueNewNull; > +virJSONValueNewArray; > +virJSONValueNewObject; > +virJSONValueObjectAppend; > +virJSONValueObjectAppendString; > +virJSONValueObjectAppendNumberInt; > +virJSONValueObjectAppendNumberUint; > +virJSONValueObjectAppendNumberLong; > +virJSONValueObjectAppendNumberUlong; > +virJSONValueObjectAppendNumberDouble; > +virJSONValueObjectAppendBoolean; > +virJSONValueObjectAppendNull; > +virJSONValueArrayAppend; > +virJSONValueObjectHasKey; > +virJSONValueObjectGet; > +virJSONValueArraySize; > +virJSONValueArrayGet; > +virJSONValueGetString; > +virJSONValueGetNumberInt; > +virJSONValueGetNumberUint; > +virJSONValueGetNumberLong; > +virJSONValueGetNumberUlong; > +virJSONValueGetNumberDouble; > +virJSONValueGetBoolean; > +virJSONValueIsNull; > +virJSONValueObjectGetString; > +virJSONValueObjectGetNumberInt; > +virJSONValueObjectGetNumberUint; > +virJSONValueObjectGetNumberLong; > +virJSONValueObjectGetNumberUlong; > +virJSONValueObjectGetNumberDouble; > +virJSONValueObjectGetBoolean; > +virJSONValueObjectIsNull; > +virJSONValueFromString; > +virJSONValueToString; > + > + > # logging.h > virLogMessage; > virLogGetNbFilters; > diff --git a/src/util/json.c b/src/util/json.c > new file mode 100644 > index 0000000..f359b95 > --- /dev/null > +++ b/src/util/json.c > @@ -0,0 +1,1043 @@ > +/* > + * json.h: JSON object parsing/formatting json.c > + * Copyright (C) 2008 Daniel P. Berrange > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + * > + */ > + > + > +#include <config.h> > + > +#include "json.h" > +#include "memory.h" > +#include "virterror_internal.h" > +#include "logging.h" > +#include "util.h" > + > +#include <yajl/yajl_gen.h> > +#include <yajl/yajl_parse.h> > + > +/* XXX fixme */ > +#define VIR_FROM_THIS VIR_FROM_NONE hum, I would defined a new domain after all we have one for XML parsing, but not urgent. > +#define ReportError(conn, code, fmt...) \ > + virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \ > + __FUNCTION__, __LINE__, fmt) > + > + [...] > +static virJSONValuePtr virJSONValueNewNumber(const char *data) > +{ > + virJSONValuePtr val; > + > + if (VIR_ALLOC(val) < 0) > + return NULL; > + > + val->type = VIR_JSON_TYPE_NUMBER; > + if (!(val->data.number = strdup(data))) { > + VIR_FREE(val); > + return NULL; > + } so we keep numbers as their string value ... surprizing but maybe that's the most flexible for our use. > + return val; > +} [...] > + > +#if HAVE_YAJL > +static int virJSONParserInsertValue(virJSONParserPtr parser, > + virJSONValuePtr value) okay so that's the YAJL specific part [...] > +static const yajl_callbacks parserCallbacks = { > + virJSONParserHandleNull, > + virJSONParserHandleBoolean, > + NULL, > + NULL, > + virJSONParserHandleNumber, > + virJSONParserHandleString, > + virJSONParserHandleStartMap, > + virJSONParserHandleMapKey, > + virJSONParserHandleEndMap, > + virJSONParserHandleStartArray, > + virJSONParserHandleEndArray > +}; and a driver block for it > + > +/* XXX add an incremental streaming parser - yajl trivially supports it */ what would be the point ? I doubt there is a memory problem, it's more the incremental aspect I suppose. [...] > + > +#else > +virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED) > +{ > + ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", > + _("No JSON parser implementation is available")); > + return NULL; > +} > +char *virJSONValueToString(virJSONValuePtr object) > +{ > + ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", > + _("No JSON parser implementation is available")); > + return NULL; > +} and the fallback ACK, it' weird there ain't any JSON C API yet in F12, there is one for nearly all high level language but noone seems to have imposed a good C one. so now we are betting on yajl, maybe another one will prevail but since we have a good decoupling, fine by me, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@xxxxxxxxxxxx | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list