[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Re: [PATCH RESEND V8 6/7] libxl: Introduce JSON parsing stuff.
On Wed, 2011-09-21 at 13:59 +0100, Anthony PERARD wrote: > We use the yajl parser, but we need to make a tree from the parse result > to use it outside the parser. > > So this patch include json_object struct that is used to hold the JSON > data. > > Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> I didn't review this again but I recall being happy with it last time round so: Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx> > --- > README | 1 + > tools/libxl/Makefile | 5 +- > tools/libxl/libxl_internal.h | 100 ++++++++ > tools/libxl/libxl_json.c | 560 > ++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 665 insertions(+), 1 deletions(-) > create mode 100644 tools/libxl/libxl_json.c > > diff --git a/README b/README > index ff154b2..c9bf699 100644 > --- a/README > +++ b/README > @@ -47,6 +47,7 @@ provided by your OS distributor: > * Development install of openssl (e.g., openssl-dev) > * Development install of x11 (e.g. xorg-x11-dev) > * Development install of uuid (e.g. uuid-dev) > + * Development install of yajl (e.g. libyajl-dev) > * bridge-utils package (/sbin/brctl) > * iproute package (/sbin/ip) > * hotplug or udev > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > index 1f6b418..e50874e 100644 > --- a/tools/libxl/Makefile > +++ b/tools/libxl/Makefile > @@ -32,9 +32,12 @@ endif > LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o > LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o > > +LIBXL_LIBS += -lyajl > + > LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \ > libxl_dom.o libxl_exec.o libxl_xshelp.o > libxl_device.o \ > - libxl_internal.o libxl_utils.o libxl_uuid.o > $(LIBXL_OBJS-y) > + libxl_internal.o libxl_utils.o libxl_uuid.o > libxl_json.o \ > + $(LIBXL_OBJS-y) > LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o > > $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) > $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index d873243..f495e86 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -387,4 +387,104 @@ _hidden int libxl__e820_alloc(libxl_ctx *ctx, uint32_t > domid, libxl_domain_confi > #define STRINGIFY(x) #x > #define TOSTRING(x) STRINGIFY(x) > > +/* from libxl_json */ > +#include <yajl/yajl_gen.h> > + > +_hidden yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char > *str); > + > +typedef enum { > + JSON_ERROR, > + JSON_NULL, > + JSON_TRUE, > + JSON_FALSE, > + JSON_INTEGER, > + JSON_DOUBLE, > + JSON_STRING, > + JSON_MAP, > + JSON_ARRAY, > + JSON_ANY > +} libxl__json_node_type; > + > +typedef struct libxl__json_object { > + libxl__json_node_type type; > + union { > + long i; > + double d; > + char *string; > + /* List of libxl__json_object */ > + flexarray_t *array; > + /* List of libxl__json_map_node */ > + flexarray_t *map; > + } u; > + struct libxl__json_object *parent; > +} libxl__json_object; > + > +typedef struct { > + char *map_key; > + libxl__json_object *obj; > +} libxl__json_map_node; > + > +typedef struct libxl__yajl_ctx libxl__yajl_ctx; > + > +static inline bool libxl__json_object_is_string(const libxl__json_object *o) > +{ > + return o != NULL && o->type == JSON_STRING; > +} > +static inline bool libxl__json_object_is_integer(const libxl__json_object *o) > +{ > + return o != NULL && o->type == JSON_INTEGER; > +} > +static inline bool libxl__json_object_is_map(const libxl__json_object *o) > +{ > + return o != NULL && o->type == JSON_MAP; > +} > +static inline bool libxl__json_object_is_array(const libxl__json_object *o) > +{ > + return o != NULL && o->type == JSON_ARRAY; > +} > + > +static inline > +const char *libxl__json_object_get_string(const libxl__json_object *o) > +{ > + if (libxl__json_object_is_string(o)) > + return o->u.string; > + else > + return NULL; > +} > +static inline > +flexarray_t *libxl__json_object_get_map(const libxl__json_object *o) > +{ > + if (libxl__json_object_is_map(o)) > + return o->u.map; > + else > + return NULL; > +} > +static inline > +flexarray_t *libxl__json_object_get_array(const libxl__json_object *o) > +{ > + if (libxl__json_object_is_array(o)) > + return o->u.array; > + else > + return NULL; > +} > +static inline long libxl__json_object_get_integer(const libxl__json_object > *o) > +{ > + if (libxl__json_object_is_integer(o)) > + return o->u.i; > + else > + return -1; > +} > + > +_hidden libxl__json_object *libxl__json_array_get(const libxl__json_object > *o, > + int i); > +_hidden > +libxl__json_map_node *libxl__json_map_node_get(const libxl__json_object *o, > + int i); > +_hidden const libxl__json_object *libxl__json_map_get(const char *key, > + const libxl__json_object *o, > + libxl__json_node_type > expected_type); > +_hidden void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj); > + > +_hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s); > + > #endif > diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c > new file mode 100644 > index 0000000..e771925 > --- /dev/null > +++ b/tools/libxl/libxl_json.c > @@ -0,0 +1,560 @@ > +/* > + * Copyright (C) 2011 Citrix Ltd. > + * > + * This program 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; version 2.1 only. with the special > + * exception on linking described in file LICENSE. > + * > + * This program 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. > + */ > + > +#include <assert.h> > +#include <string.h> > + > +#include <yajl/yajl_parse.h> > +#include <yajl/yajl_gen.h> > + > +#include "libxl_internal.h" > + > +/* #define DEBUG_ANSWER */ > + > +struct libxl__yajl_ctx { > + libxl__gc *gc; > + yajl_handle hand; > + libxl__json_object *head; > + libxl__json_object *current; > +#ifdef DEBUG_ANSWER > + yajl_gen g; > +#endif > +}; > + > +#ifdef DEBUG_ANSWER > +# define DEBUG_GEN_ALLOC(ctx) \ > + if ((ctx)->g == NULL) { \ > + yajl_gen_config conf = { 1, " " }; \ > + (ctx)->g = yajl_gen_alloc(&conf, NULL); \ > + } > +# define DEBUG_GEN_FREE(ctx) \ > + if ((ctx)->g) yajl_gen_free((ctx)->g) > +# define DEBUG_GEN(ctx, type) yajl_gen_##type(ctx->g) > +# define DEBUG_GEN_VALUE(ctx, type, value) yajl_gen_##type(ctx->g, value) > +# define DEBUG_GEN_STRING(ctx, str, n) yajl_gen_string(ctx->g, str, n) > +# define DEBUG_GEN_REPORT(yajl_ctx) \ > + do { \ > + const unsigned char *buf = NULL; \ > + unsigned int len = 0; \ > + yajl_gen_get_buf((yajl_ctx)->g, &buf, &len); \ > + LIBXL__LOG(libxl__gc_owner((yajl_ctx)->gc), \ > + LIBXL__LOG_DEBUG, "response:\n%s", buf); \ > + yajl_gen_free((yajl_ctx)->g); \ > + (yajl_ctx)->g = NULL; \ > + } while (0) > +#else > +# define DEBUG_GEN_ALLOC(ctx) ((void)0) > +# define DEBUG_GEN_FREE(ctx) ((void)0) > +# define DEBUG_GEN(ctx, type) ((void)0) > +# define DEBUG_GEN_VALUE(ctx, type, value) ((void)0) > +# define DEBUG_GEN_STRING(ctx, value, lenght) ((void)0) > +# define DEBUG_GEN_REPORT(ctx) ((void)0) > +#endif > + > +/* > + * YAJL Helper > + */ > + > +yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str) > +{ > + return yajl_gen_string(hand, (const unsigned char *)str, strlen(str)); > +} > + > + > +/* > + * libxl__json_object helper functions > + */ > + > +static libxl__json_object *json_object_alloc(libxl__gc *gc, > + libxl__json_node_type type) > +{ > + libxl__json_object *obj; > + > + obj = calloc(1, sizeof (libxl__json_object)); > + if (obj == NULL) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "Failed to allocate a libxl__json_object"); > + return NULL; > + } > + > + obj->type = type; > + > + if (type == JSON_MAP || type == JSON_ARRAY) { > + flexarray_t *array = flexarray_make(1, 1); > + if (array == NULL) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "Failed to allocate a flexarray"); > + free(obj); > + return NULL; > + } > + if (type == JSON_MAP) > + obj->u.map = array; > + else > + obj->u.array = array; > + } > + > + return obj; > +} > + > +static int json_object_append_to(libxl__gc *gc, > + libxl__json_object *obj, > + libxl__json_object *dst) > +{ > + assert(dst != NULL); > + > + switch (dst->type) { > + case JSON_MAP: { > + libxl__json_map_node *last; > + > + if (dst->u.map->count == 0) { > + LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "Try to add a value to an empty map (with no key)"); > + return -1; > + } > + flexarray_get(dst->u.map, dst->u.map->count - 1, (void**)&last); > + last->obj = obj; > + break; > + } > + case JSON_ARRAY: > + if (flexarray_append(dst->u.array, obj) == 2) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "Failed to grow a flexarray"); > + return -1; > + } > + break; > + default: > + LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "Try append an object is not a map/array (%i)\n", > + dst->type); > + return -1; > + } > + > + obj->parent = dst; > + return 0; > +} > + > +void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj) > +{ > + int index = 0; > + > + if (obj == NULL) > + return; > + switch (obj->type) { > + case JSON_STRING: > + free(obj->u.string); > + break; > + case JSON_MAP: { > + libxl__json_map_node *node = NULL; > + > + for (index = 0; index < obj->u.map->count; index++) { > + if (flexarray_get(obj->u.map, index, (void**)&node) != 0) > + break; > + libxl__json_object_free(gc, node->obj); > + free(node->map_key); > + free(node); > + node = NULL; > + } > + flexarray_free(obj->u.map); > + break; > + } > + case JSON_ARRAY: { > + libxl__json_object *node = NULL; > + break; > + > + for (index = 0; index < obj->u.array->count; index++) { > + if (flexarray_get(obj->u.array, index, (void**)&node) != 0) > + break; > + libxl__json_object_free(gc, node); > + node = NULL; > + } > + flexarray_free(obj->u.array); > + break; > + } > + default: > + break; > + } > + free(obj); > +} > + > +libxl__json_object *libxl__json_array_get(const libxl__json_object *o, int i) > +{ > + flexarray_t *array = NULL; > + libxl__json_object *obj = NULL; > + > + if ((array = libxl__json_object_get_array(o)) == NULL) { > + return NULL; > + } > + > + if (i >= array->count) > + return NULL; > + > + if (flexarray_get(array, i, (void**)&obj) != 0) > + return NULL; > + > + return obj; > +} > + > +libxl__json_map_node *libxl__json_map_node_get(const libxl__json_object *o, > + int i) > +{ > + flexarray_t *array = NULL; > + libxl__json_map_node *obj = NULL; > + > + if ((array = libxl__json_object_get_map(o)) == NULL) { > + return NULL; > + } > + > + if (i >= array->count) > + return NULL; > + > + if (flexarray_get(array, i, (void**)&obj) != 0) > + return NULL; > + > + return obj; > +} > + > +const libxl__json_object *libxl__json_map_get(const char *key, > + const libxl__json_object *o, > + libxl__json_node_type > expected_type) > +{ > + flexarray_t *maps = NULL; > + int index = 0; > + > + if (libxl__json_object_is_map(o)) { > + libxl__json_map_node *node = NULL; > + > + maps = o->u.map; > + for (index = 0; index < maps->count; index++) { > + if (flexarray_get(maps, index, (void**)&node) != 0) > + return NULL; > + if (strcmp(key, node->map_key) == 0) { > + if (expected_type == JSON_ANY > + || (node->obj && node->obj->type == expected_type)) { > + return node->obj; > + } else { > + return NULL; > + } > + } > + } > + } > + return NULL; > +} > + > + > +/* > + * JSON callbacks > + */ > + > +static int json_callback_null(void *opaque) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj; > + > + DEBUG_GEN(ctx, null); > + > + if ((obj = json_object_alloc(ctx->gc, JSON_NULL)) == NULL) > + return 0; > + > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_boolean(void *opaque, int boolean) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj; > + > + DEBUG_GEN_VALUE(ctx, bool, boolean); > + > + if ((obj = json_object_alloc(ctx->gc, > + boolean ? JSON_TRUE : JSON_FALSE)) == NULL) > + return 0; > + > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_integer(void *opaque, long value) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj; > + > + DEBUG_GEN_VALUE(ctx, integer, value); > + > + if ((obj = json_object_alloc(ctx->gc, JSON_INTEGER)) == NULL) > + return 0; > + obj->u.i = value; > + > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_double(void *opaque, double value) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj; > + > + DEBUG_GEN_VALUE(ctx, double, value); > + > + if ((obj = json_object_alloc(ctx->gc, JSON_DOUBLE)) == NULL) > + return 0; > + obj->u.d = value; > + > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_string(void *opaque, const unsigned char *str, > + unsigned int len) > +{ > + libxl__yajl_ctx *ctx = opaque; > + char *t = NULL; > + libxl__json_object *obj = NULL; > + > + t = malloc(len + 1); > + if (t == NULL) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "Failed to allocate"); > + return 0; > + } > + > + DEBUG_GEN_STRING(ctx, str, len); > + > + strncpy(t, (const char *) str, len); > + t[len] = 0; > + > + if ((obj = json_object_alloc(ctx->gc, JSON_STRING)) == NULL) { > + free(t); > + return 0; > + } > + obj->u.string = t; > + > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_map_key(void *opaque, const unsigned char *str, > + unsigned int len) > +{ > + libxl__yajl_ctx *ctx = opaque; > + char *t = NULL; > + libxl__json_object *obj = ctx->current; > + > + t = malloc(len + 1); > + if (t == NULL) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "Failed to allocate"); > + return 0; > + } > + > + DEBUG_GEN_STRING(ctx, str, len); > + > + strncpy(t, (const char *) str, len); > + t[len] = 0; > + > + if (libxl__json_object_is_map(obj)) { > + libxl__json_map_node *node = malloc(sizeof (libxl__json_map_node)); > + if (node == NULL) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "Failed to allocate"); > + return 0; > + } > + > + node->map_key = t; > + node->obj = NULL; > + > + if (flexarray_append(obj->u.map, node) == 2) { > + LIBXL__LOG_ERRNO(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "Failed to grow a flexarray"); > + return 0; > + } > + } else { > + LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "Current json object is not a map"); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_start_map(void *opaque) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj = NULL; > + > + DEBUG_GEN(ctx, map_open); > + > + if ((obj = json_object_alloc(ctx->gc, JSON_MAP)) == NULL) > + return 0; > + > + if (ctx->current) { > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + } > + > + ctx->current = obj; > + if (ctx->head == NULL) { > + ctx->head = obj; > + } > + > + return 1; > +} > + > +static int json_callback_end_map(void *opaque) > +{ > + libxl__yajl_ctx *ctx = opaque; > + > + DEBUG_GEN(ctx, map_close); > + > + if (ctx->current) { > + ctx->current = ctx->current->parent; > + } else { > + LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "No current libxl__json_object, cannot use his parent."); > + return 0; > + } > + > + return 1; > +} > + > +static int json_callback_start_array(void *opaque) > +{ > + libxl__yajl_ctx *ctx = opaque; > + libxl__json_object *obj = NULL; > + > + DEBUG_GEN(ctx, array_open); > + > + if ((obj = json_object_alloc(ctx->gc, JSON_ARRAY)) == NULL) > + return 0; > + > + if (ctx->current) { > + if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) { > + libxl__json_object_free(ctx->gc, obj); > + return 0; > + } > + } > + > + ctx->current = obj; > + if (ctx->head == NULL) { > + ctx->head = obj; > + } > + > + return 1; > +} > + > +static int json_callback_end_array(void *opaque) > +{ > + libxl__yajl_ctx *ctx = opaque; > + > + DEBUG_GEN(ctx, array_close); > + > + if (ctx->current) { > + ctx->current = ctx->current->parent; > + } else { > + LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, > + "No current libxl__json_object, cannot use his parent."); > + return 0; > + } > + > + return 1; > +} > + > +static yajl_callbacks callbacks = { > + json_callback_null, > + json_callback_boolean, > + json_callback_integer, > + json_callback_double, > + NULL, > + json_callback_string, > + json_callback_start_map, > + json_callback_map_key, > + json_callback_end_map, > + json_callback_start_array, > + json_callback_end_array > +}; > + > +static void yajl_ctx_free(libxl__yajl_ctx *yajl_ctx) > +{ > + if (yajl_ctx->hand) { > + yajl_free(yajl_ctx->hand); > + yajl_ctx->hand = NULL; > + } > + DEBUG_GEN_FREE(yajl_ctx); > +} > + > +libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s) > +{ > + yajl_status status; > + libxl__yajl_ctx yajl_ctx; > + > + memset(&yajl_ctx, 0, sizeof (yajl_ctx)); > + yajl_ctx.gc = gc; > + > + DEBUG_GEN_ALLOC(&yajl_ctx); > + > + if (yajl_ctx.hand == NULL) { > + yajl_parser_config cfg = { > + .allowComments = 1, > + .checkUTF8 = 1, > + }; > + yajl_ctx.hand = yajl_alloc(&callbacks, &cfg, NULL, &yajl_ctx); > + } > + status = yajl_parse(yajl_ctx.hand, (const unsigned char *)s, strlen(s)); > + status = yajl_parse_complete(yajl_ctx.hand); > + > + if (status == yajl_status_ok) { > + libxl__json_object *o = yajl_ctx.head; > + > + DEBUG_GEN_REPORT(&yajl_ctx); > + > + yajl_ctx.head = NULL; > + > + yajl_ctx_free(&yajl_ctx); > + return o; > + } else { > + unsigned char *str = yajl_get_error(yajl_ctx.hand, 1, > + (const unsigned char *)s, > + strlen(s)); > + > + LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, > + "yajl error: %s", str); > + yajl_free_error(yajl_ctx.hand, str); > + > + libxl__json_object_free(gc, yajl_ctx.head); > + yajl_ctx_free(&yajl_ctx); > + return NULL; > + } > +} > -- > Anthony PERARD > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |