# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxx>
# Date 1317312134 -3600
# Node ID 030e844fccebcc3984c5792559c0cbd5424d277a
# Parent fb42038b1f5cd4f72c5cfff6e5f8ffa46f2fa0b2
libxl: IDL: autogenerate functions to produce JSON from libxl data structures.
Two functions are provided. TYPE_gen_json exposes an interface which is
compatible with the YAGL generator infrastructure. TYPE_to_string uses this to
produce a pretty printed string.
The TYPE_gen_json functions are defined in a new header libxl_json.h which is
not exposed via libxl.h due to the use of YAGL datatypes to avoid poluting the
namespace us libxl users which don't use the library themselves. If a libxl
user is interested in integrating at the YAGL level then it should #include
this file itself.
Also update testidl to generate a random version of each IDL datastructure and
convert it to JSON. Unfortunately this requires a libxl_ctx and therefore the
test must be run on a Xen system now.
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/Makefile
--- a/tools/libxl/Makefile Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/Makefile Thu Sep 29 17:02:14 2011 +0100
@@ -84,14 +84,17 @@ _libxl_paths.h: genpath
libxl_paths.c: _libxl_paths.h
libxl.h: _libxl_types.h
+libxl_json.h: _libxl_types_json.h
libxl_internal.h: _libxl_types_internal.h
+libxl_internal_json.h: _libxl_types_internal_json.h
$(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h
$(LIBXL_OBJS): libxl_internal.h
-_libxl_type%.h _libxl_type%.c: libxl_type%.idl gentypes.py libxltypes.py
- $(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h __libxl_type$*.c
+_libxl_type%.h _libxl_type%_json.h _libxl_type%.c: libxl_type%.idl gentypes.py
libxltypes.py
+ $(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h
__libxl_type$*_json.h __libxl_type$*.c
$(call move-if-changed,__libxl_type$*.h,_libxl_type$*.h)
+ $(call move-if-changed,__libxl_type$*_json.h,_libxl_type$*_json.h)
$(call move-if-changed,__libxl_type$*.c,_libxl_type$*.c)
libxenlight.so: libxenlight.so.$(MAJOR)
@@ -140,7 +143,7 @@ install: all
ln -sf libxlutil.so.$(XLUMAJOR).$(XLUMINOR)
$(DESTDIR)$(LIBDIR)/libxlutil.so.$(XLUMAJOR)
ln -sf libxlutil.so.$(XLUMAJOR) $(DESTDIR)$(LIBDIR)/libxlutil.so
$(INSTALL_DATA) libxlutil.a $(DESTDIR)$(LIBDIR)
- $(INSTALL_DATA) libxl.h _libxl_types.h libxl_utils.h libxl_uuid.h
$(DESTDIR)$(INCLUDEDIR)
+ $(INSTALL_DATA) libxl.h libxl_json.h _libxl_types.h _libxl_types_json.h
libxl_utils.h libxl_uuid.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) bash-completion $(DESTDIR)$(BASH_COMPLETION_DIR)/xl.sh
.PHONY: clean
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/gentest.py
--- a/tools/libxl/gentest.py Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/gentest.py Thu Sep 29 17:02:14 2011 +0100
@@ -5,6 +5,7 @@ import re
import random
import libxltypes
+
def randomize_char(c):
if random.random() < 0.5:
return str.lower(c)
@@ -15,6 +16,50 @@ def randomize_case(s):
r = [randomize_char(c) for c in s]
return "".join(r)
+def randomize_enum(e):
+ return random.choice([v.name for v in e.values])
+
+handcoded = ["libxl_cpumap", "libxl_key_value_list",
+ "libxl_cpuid_policy_list", "libxl_file_reference",
+ "libxl_string_list", "libxl_cpuarray"]
+
+def gen_rand_init(ty, v, indent = " ", parent = None):
+ s = ""
+ if isinstance(ty, libxltypes.Enumeration):
+ s += "%s = %s;\n" % (ty.pass_arg(v, parent is None),
randomize_enum(ty))
+ elif isinstance(ty, libxltypes.KeyedUnion):
+ if parent is None:
+ raise Exception("KeyedUnion type must have a parent")
+ s += "switch (%s) {\n" % (parent + ty.keyvar_name)
+ for f in ty.fields:
+ (nparent,fexpr) = ty.member(v, f, parent is None)
+ s += "case %s:\n" % f.enumname
+ s += gen_rand_init(f.type, fexpr, indent + " ", nparent)
+ s += " break;\n"
+ s += "}\n"
+ elif isinstance(ty, libxltypes.Struct) and (parent is None or ty.json_fn
is None):
+ for f in [f for f in ty.fields if not f.const]:
+ (nparent,fexpr) = ty.member(v, f, parent is None)
+ s += gen_rand_init(f.type, fexpr, "", nparent)
+ elif hasattr(ty, "rand_init") and ty.rand_init is not None:
+ s += "%s(%s);\n" % (ty.rand_init, ty.pass_arg(v, isref=parent is
None, passby=libxltypes.PASS_BY_REFERENCE))
+ elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap"]:
+ s += "rand_bytes((uint8_t *)%s, sizeof(*%s));\n" % (v,v)
+ elif ty.typename in ["libxl_domid"] or isinstance(ty, libxltypes.Number):
+ s += "%s = rand() %% (sizeof(%s)*8);\n" % (ty.pass_arg(v, parent is
None), ty.pass_arg(v, parent is None))
+ elif ty.typename in ["bool"]:
+ s += "%s = rand() %% 2;\n" % v
+ elif ty.typename in ["char *"]:
+ s += "%s = rand_str();\n" % v
+ elif ty.typename in handcoded:
+ raise Exception("Gen for handcoded %s" % ty.typename)
+ else:
+ raise Exception("Cannot randomly init %s" % ty.typename)
+
+ if s != "":
+ s = indent + s
+ return s.replace("\n", "\n%s" % indent).rstrip(indent)
+
if __name__ == '__main__':
if len(sys.argv) < 3:
print >>sys.stderr, "Usage: gentest.py <idl> <implementation>"
@@ -23,23 +68,191 @@ if __name__ == '__main__':
random.seed()
idl = sys.argv[1]
- (_,types) = libxltypes.parse(idl)
+ (builtins,types) = libxltypes.parse(idl)
impl = sys.argv[2]
f = open(impl, "w")
f.write("""
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include \"libxl.h\"
+#include \"libxl_utils.h\"
+static char *rand_str(void)
+{
+ int i, sz = rand() % 32;
+ char *s = malloc(sz+1);
+ for (i=0; i<sz; i++)
+ s[i] = 'a' + (rand() % 26);
+ s[i] = '\\0';
+ return s;
+}
+
+static void rand_bytes(uint8_t *p, size_t sz)
+{
+ int i;
+ for (i=0; i<sz; i++)
+ p[i] = rand() % 256;
+ //p[i] = i;
+}
+
+static void libxl_cpumap_rand_init(libxl_cpumap *cpumap)
+{
+ int i;
+ cpumap->size = rand() % 16;
+ cpumap->map = calloc(cpumap->size, sizeof(*cpumap->map));
+ libxl_for_each_cpu(i, *cpumap) {
+ if (rand() % 2)
+ libxl_cpumap_set(cpumap, i);
+ else
+ libxl_cpumap_reset(cpumap, i);
+ }
+}
+
+static void libxl_key_value_list_rand_init(libxl_key_value_list *pkvl)
+{
+ int i, nr_kvp = rand() % 16;
+ libxl_key_value_list kvl = calloc(nr_kvp+1, 2*sizeof(char *));
+
+ for (i = 0; i<2*nr_kvp; i += 2) {
+ kvl[i] = rand_str();
+ if (rand() % 8)
+ kvl[i+1] = rand_str();
+ else
+ kvl[i+1] = NULL;
+ }
+ kvl[i] = NULL;
+ kvl[i+1] = NULL;
+ *pkvl = kvl;
+}
+
+static void libxl_cpuid_policy_list_rand_init(libxl_cpuid_policy_list *pp)
+{
+ int i, nr_policies = rand() % 16;
+ struct {
+ const char *n;
+ int w;
+ } options[] = {
+ /* A random selection from libxl_cpuid_parse_config */
+ {"maxleaf", 32},
+ {"family", 8},
+ {"model", 8},
+ {"stepping", 4},
+ {"localapicid", 8},
+ {"proccount", 8},
+ {"clflush", 8},
+ {"brandid", 8},
+ {"f16c", 1},
+ {"avx", 1},
+ {"osxsave", 1},
+ {"xsave", 1},
+ {"aes", 1},
+ {"popcnt", 1},
+ {"movbe", 1},
+ {"x2apic", 1},
+ {"sse4.2", 1},
+ {"sse4.1", 1},
+ {"dca", 1},
+ {"pdcm", 1},
+ {"procpkg", 6},
+ };
+ const int nr_options = sizeof(options)/sizeof(options[0]);
+ char buf[64];
+ libxl_cpuid_policy_list p = NULL;
+
+ for (i = 0; i < nr_policies; i++) {
+ int opt = rand() % nr_options;
+ int val = rand() % (1<<options[opt].w);
+ snprintf(buf, 64, "%s=%#x", options[opt].n, val);
+ libxl_cpuid_parse_config(&p, buf);
+ }
+ *pp = p;
+}
+
+static void libxl_file_reference_rand_init(libxl_file_reference *p)
+{
+ memset(p, 0, sizeof(*p));
+ if (rand() % 8)
+ p->path = rand_str();
+}
+
+static void libxl_string_list_rand_init(libxl_string_list *p)
+{
+ int i, nr = rand() % 16;
+ libxl_string_list l = calloc(nr+1, sizeof(char *));
+
+ for (i = 0; i<nr; i++) {
+ l[i] = rand_str();
+ }
+ l[i] = NULL;
+ *p = l;
+}
+
+static void libxl_cpuarray_rand_init(libxl_cpuarray *p)
+{
+ int i;
+ /* Up to 16 VCPUs on 32 PCPUS */
+ p->entries = rand() % 16;
+ p->array = calloc(p->entries, sizeof(*p->array));
+ for (i = 0; i < p->entries; i++) {
+ int r = rand() % 32*1.5; /* 2:1 valid:invalid */
+ if (r >= 32)
+ p->array[i] = LIBXL_CPUARRAY_INVALID_ENTRY;
+ else
+ p->array[i] = r;
+ }
+}
+""")
+ for ty in builtins + types:
+ if ty.typename not in handcoded:
+ f.write("static void %s_rand_init(%s);\n" % (ty.typename,
ty.make_arg("p", passby=libxltypes.PASS_BY_REFERENCE)))
+ f.write("static void %s_rand_init(%s)\n" % (ty.typename,
ty.make_arg("p", passby=libxltypes.PASS_BY_REFERENCE)))
+ f.write("{\n")
+ f.write(gen_rand_init(ty, "p"))
+ f.write("}\n")
+ f.write("\n")
+ ty.rand_init = "%s_rand_init" % ty.typename
+
+ f.write("""
int main(int argc, char **argv)
{
""")
- for ty in [t for t in types if isinstance(t,libxltypes.Enumeration)]:
+ for ty in types:
f.write(" %s %s_val;\n" % (ty.typename, ty.typename))
- f.write(" int rc;\n")
- f.write("\n")
+ f.write("""
+ int rc;
+ char *s;
+ xentoollog_logger_stdiostream *logger;
+ libxl_ctx *ctx;
+ logger = xtl_createlogger_stdiostream(stderr, XTL_DETAIL, 0);
+ if (!logger) exit(1);
+
+ if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, (xentoollog_logger*)logger)) {
+ fprintf(stderr, "cannot init xl context\\n");
+ exit(1);
+ }
+""")
+ f.write(" printf(\"Testing TYPE_to_json()\\n\");\n")
+ f.write(" printf(\"----------------------\\n\");\n")
+ f.write(" printf(\"\\n\");\n")
+ for ty in [t for t in types if t.json_fn is not None]:
+ arg = ty.typename + "_val"
+ f.write(" %s_rand_init(%s);\n" % (ty.typename, ty.pass_arg(arg,
isref=False, passby=libxltypes.PASS_BY_REFERENCE)))
+ f.write(" s = %s_to_json(ctx, %s);\n" % (ty.typename,
ty.pass_arg(arg, isref=False)))
+ f.write(" printf(\"%%s: %%s\\n\", \"%s\", s);\n" % ty.typename)
+ f.write(" if (s == NULL) abort();\n")
+ f.write(" free(s);\n")
+ if ty.destructor_fn is not None:
+ f.write(" %s(&%s_val);\n" % (ty.destructor_fn, ty.typename))
+ f.write("\n")
+
+ f.write(" printf(\"Testing Enumerations\\n\");\n")
+ f.write(" printf(\"--------------------\\n\");\n")
+ f.write(" printf(\"\\n\");\n")
for ty in [t for t in types if isinstance(t,libxltypes.Enumeration)]:
f.write(" printf(\"%s -- to string:\\n\");\n" % (ty.typename))
for v in ty.values:
@@ -47,6 +260,12 @@ int main(int argc, char **argv)
(v.valuename, v.name, ty.typename, v.name))
f.write("\n")
+ f.write(" printf(\"%s -- to JSON:\\n\");\n" % (ty.typename))
+ for v in ty.values:
+ f.write(" printf(\"\\t%s = %%d = %%s\", %s, %s_to_json(ctx,
%s));\n" %\
+ (v.valuename, v.name, ty.typename, v.name))
+ f.write("\n")
+
f.write(" printf(\"%s -- from string:\\n\");\n" % (ty.typename))
for v in [v.valuename for v in ty.values] + ["AN INVALID VALUE"]:
n = randomize_case(v)
@@ -58,6 +277,11 @@ int main(int argc, char **argv)
(v, n, ty.typename))
f.write("\n")
- f.write("""return 0;
+ f.write("""
+
+ libxl_ctx_free(ctx);
+ xtl_logger_destroy((xentoollog_logger*)logger);
+
+ return 0;
}
""")
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/gentypes.py
--- a/tools/libxl/gentypes.py Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/gentypes.py Thu Sep 29 17:02:14 2011 +0100
@@ -29,7 +29,6 @@ def libxl_C_instance_of(ty, instancename
def libxl_C_type_define(ty, indent = ""):
s = ""
-
if isinstance(ty, libxltypes.Enumeration):
if ty.comment is not None:
s += format_comment(0, ty.comment)
@@ -76,7 +75,6 @@ def libxl_C_type_define(ty, indent = "")
return s.replace("\n", "\n%s" % indent)
def libxl_C_type_destroy(ty, v, indent = " ", parent = None):
-
s = ""
if isinstance(ty, libxltypes.KeyedUnion):
if parent is None:
@@ -100,6 +98,66 @@ def libxl_C_type_destroy(ty, v, indent =
s = indent + s
return s.replace("\n", "\n%s" % indent).rstrip(indent)
+def libxl_C_type_gen_json(ty, v, indent = " ", parent = None):
+ s = ""
+ if parent is None:
+ s += "yajl_gen_status s;\n"
+ if isinstance(ty, libxltypes.Enumeration):
+ s += "{\n"
+ s += " const char *se = %s_to_string(%s);\n" % (ty.typename,
ty.pass_arg(v, parent is None))
+ s += " if (se)\n"
+ s += " s = yajl_gen_string(hand, (const unsigned char *)se,
strlen(se));\n"
+ s += " else\n"
+ s += " s = yajl_gen_null(hand);\n"
+ s += " if (s != yajl_gen_status_ok)\n"
+ s += " goto out;\n"
+ s += "}\n"
+ elif isinstance(ty, libxltypes.KeyedUnion):
+ if parent is None:
+ raise Exception("KeyedUnion type must have a parent")
+ s += "switch (%s) {\n" % (parent + ty.keyvar_name)
+ for f in ty.fields:
+ (nparent,fexpr) = ty.member(v, f, parent is None)
+ s += "case %s:\n" % f.enumname
+ s += libxl_C_type_gen_json(f.type, fexpr, indent + " ", nparent)
+ s += " break;\n"
+ s += "}\n"
+ elif isinstance(ty, libxltypes.Struct) and (parent is None or ty.json_fn
is None):
+ s += "s = yajl_gen_map_open(hand);\n"
+ s += "if (s != yajl_gen_status_ok)\n"
+ s += " goto out;\n"
+ for f in [f for f in ty.fields if not f.const]:
+ (nparent,fexpr) = ty.member(v, f, parent is None)
+ s += "s = yajl_gen_string(hand, (const unsigned char *)\"%s\",
sizeof(\"%s\")-1);\n" % (f.name, f.name)
+ s += "if (s != yajl_gen_status_ok)\n"
+ s += " goto out;\n"
+ s += libxl_C_type_gen_json(f.type, fexpr, "", nparent)
+ s += "s = yajl_gen_map_close(hand);\n"
+ s += "if (s != yajl_gen_status_ok)\n"
+ s += " goto out;\n"
+ else:
+ if ty.json_fn is not None:
+ s += "s = %s(hand, %s);\n" % (ty.json_fn, ty.pass_arg(v, parent is
None))
+ s += "if (s != yajl_gen_status_ok)\n"
+ s += " goto out;\n"
+
+ if parent is None:
+ s += "out:\n"
+ s += "return s;\n"
+
+ if s != "":
+ s = indent + s
+ return s.replace("\n", "\n%s" % indent).rstrip(indent)
+
+def libxl_C_type_to_json(ty, v, indent = " "):
+ s = ""
+ gen = "(libxl__gen_json_callback)&%s_gen_json" % ty.typename
+ s += "return libxl__object_to_json(ctx, \"%s\", %s, (void *)%s);\n" %
(ty.typename, gen, ty.pass_arg(v, passby=libxltypes.PASS_BY_REFERENCE))
+
+ if s != "":
+ s = indent + s
+ return s.replace("\n", "\n%s" % indent).rstrip(indent)
+
def libxl_C_enum_to_string(ty, e, indent = " "):
s = ""
s += "switch(%s) {\n" % e
@@ -138,11 +196,11 @@ def libxl_C_enum_from_string(ty, str, e,
if __name__ == '__main__':
- if len(sys.argv) != 4:
- print >>sys.stderr, "Usage: gentypes.py <idl> <header>
<implementation>"
+ if len(sys.argv) != 5:
+ print >>sys.stderr, "Usage: gentypes.py <idl> <header> <header-json>
<implementation>"
sys.exit(1)
- (_, idl, header, impl) = sys.argv
+ (_, idl, header, header_json, impl) = sys.argv
(_,types) = libxltypes.parse(idl)
@@ -167,6 +225,8 @@ if __name__ == '__main__':
f.write(libxl_C_type_define(ty) + ";\n")
if ty.destructor_fn is not None:
f.write("void %s(%s);\n" % (ty.destructor_fn, ty.make_arg("p")))
+ if ty.json_fn is not None:
+ f.write("char *%s_to_json(libxl_ctx *ctx, %s);\n" % (ty.typename,
ty.make_arg("p")))
if isinstance(ty, libxltypes.Enumeration):
f.write("const char *%s_to_string(%s);\n" % (ty.typename,
ty.make_arg("p")))
f.write("int %s_from_string(const char *s, %s);\n" % (ty.typename,
ty.make_arg("e", passby=libxltypes.PASS_BY_REFERENCE)))
@@ -176,6 +236,30 @@ if __name__ == '__main__':
f.write("""#endif /* %s */\n""" % (header_define))
f.close()
+ print "outputting libxl JSON definitions to %s" % header_json
+
+ f = open(header_json, "w")
+
+ header_json_define = header_json.upper().replace('.','_')
+ f.write("""#ifndef %s
+#define %s
+
+/*
+ * DO NOT EDIT.
+ *
+ * This file is autogenerated by
+ * "%s"
+ */
+
+""" % (header_json_define, header_json_define, " ".join(sys.argv)))
+
+ for ty in [ty for ty in types if ty.json_fn is not None]:
+ f.write("yajl_gen_status %s_gen_json(yajl_gen hand, %s);\n" %
(ty.typename, ty.make_arg("p", passby=libxltypes.PASS_BY_REFERENCE)))
+
+ f.write("\n")
+ f.write("""#endif /* %s */\n""" % header_json_define)
+ f.close()
+
print "outputting libxl type implementations to %s" % impl
f = open(impl, "w")
@@ -222,5 +306,17 @@ if __name__ == '__main__':
f.write("}\n")
f.write("\n")
+ for ty in [t for t in types if t.json_fn is not None]:
+ f.write("yajl_gen_status %s_gen_json(yajl_gen hand, %s)\n" %
(ty.typename, ty.make_arg("p", passby=libxltypes.PASS_BY_REFERENCE)))
+ f.write("{\n")
+ f.write(libxl_C_type_gen_json(ty, "p"))
+ f.write("}\n")
+ f.write("\n")
+
+ f.write("char *%s_to_json(libxl_ctx *ctx, %s)\n" % (ty.typename,
ty.make_arg("p")))
+ f.write("{\n")
+ f.write(libxl_C_type_to_json(ty, "p"))
+ f.write("}\n")
+ f.write("\n")
f.close()
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/idl.txt
--- a/tools/libxl/idl.txt Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/idl.txt Thu Sep 29 17:02:14 2011 +0100
@@ -49,6 +49,15 @@ Type.autogenerate_destructor: (default:
Indicates if the above named Type.destructor_fn should be
autogenerated.
+Type.json_fn: (default: typename + "_gen_json" or None if type == None)
+
+ The name of the C function which will generate a YAJL data structure
+ representing this type.
+
+Type.autogenerate_json: (default: True)
+
+ Indicates if the above named Type.json_fn should be autogenerated.
+
Other simple type-Classes
-------------------------
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxl.h
--- a/tools/libxl/libxl.h Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/libxl.h Thu Sep 29 17:02:14 2011 +0100
@@ -199,10 +199,10 @@ typedef struct {
int v;
} libxl_enum_string_table;
+typedef struct libxl__ctx libxl_ctx;
+
#include "_libxl_types.h"
-typedef struct libxl__ctx libxl_ctx;
-
const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
typedef struct {
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/libxl_internal.h Thu Sep 29 17:02:14 2011 +0100
@@ -35,7 +35,9 @@
#include "flexarray.h"
#include "libxl_utils.h"
+
#include "_libxl_types_internal.h"
+#include "libxl_json.h"
#define LIBXL_DESTROY_TIMEOUT 10
#define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
@@ -337,6 +339,14 @@ _hidden char *libxl__cpupoolid_to_name(l
_hidden int libxl__enum_from_string(const libxl_enum_string_table *t,
const char *s, int *e);
+_hidden yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str);
+
+_hidden yajl_gen_status libxl__string_gen_json(yajl_gen hand, const char *p);
+
+typedef yajl_gen_status (*libxl__gen_json_callback)(yajl_gen hand, void *);
+_hidden char *libxl__object_to_json(libxl_ctx *ctx, const char *type,
+ libxl__gen_json_callback gen, void *p);
+
/* holds the CPUID response for a single CPUID leaf
* input contains the value of the EAX and ECX register,
* and each policy string contains a filter to apply to
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxl_json.c
--- a/tools/libxl/libxl_json.c Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/libxl_json.c Thu Sep 29 17:02:14 2011 +0100
@@ -18,6 +18,7 @@
#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>
+#include <libxl.h>
#include "libxl_internal.h"
/* #define DEBUG_ANSWER */
@@ -71,6 +72,207 @@ yajl_gen_status libxl__yajl_gen_asciiz(y
return yajl_gen_string(hand, (const unsigned char *)str, strlen(str));
}
+/*
+ * YAJL generators for builtin libxl types.
+ */
+yajl_gen_status libxl_uuid_gen_json(yajl_gen hand,
+ libxl_uuid *uuid)
+{
+ char buf[LIBXL_UUID_FMTLEN+1];
+ snprintf(buf, sizeof(buf), LIBXL_UUID_FMT, LIBXL_UUID_BYTES((*uuid)));
+ return yajl_gen_string(hand, (const unsigned char *)buf,
LIBXL_UUID_FMTLEN);
+}
+
+yajl_gen_status libxl_cpumap_gen_json(yajl_gen hand,
+ libxl_cpumap *cpumap)
+{
+ yajl_gen_status s;
+ int i;
+
+ s = yajl_gen_array_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ libxl_for_each_cpu(i, *cpumap) {
+ if (libxl_cpumap_test(cpumap, i)) {
+ s = yajl_gen_integer(hand, i);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+ }
+ s = yajl_gen_array_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand,
+ libxl_key_value_list *pkvl)
+{
+ libxl_key_value_list kvl = *pkvl;
+ yajl_gen_status s;
+ int i;
+
+ s = yajl_gen_map_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ if (!kvl) goto empty;
+
+ for (i = 0; kvl[i] != NULL; i += 2) {
+ s = libxl__yajl_gen_asciiz(hand, kvl[i]);
+ if (s != yajl_gen_status_ok) goto out;
+ if (kvl[i + 1])
+ s = libxl__yajl_gen_asciiz(hand, kvl[i+1]);
+ else
+ s = yajl_gen_null(hand);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+empty:
+ s = yajl_gen_map_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
+ libxl_cpuid_policy_list *pcpuid)
+{
+ libxl_cpuid_policy_list cpuid = *pcpuid;
+ yajl_gen_status s;
+ const char *input_names[2] = { "leaf", "subleaf" };
+ const char *policy_names[4] = { "eax", "ebx", "ecx", "edx" };
+ int i, j;
+
+ /*
+ * Aiming for:
+ * [
+ * { 'leaf': 'val-eax',
+ * 'subleaf': 'val-edx',
+ * 'ebx': 'filter',
+ * 'ecx': 'filter',
+ * 'edx': 'filter' }, ],
+ * { 'leaf': 'val-eax', ..., 'eax': 'filter', ... },
+ * ... etc ...
+ * }
+ */
+
+ s = yajl_gen_array_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ if (cpuid == NULL) goto empty;
+
+ for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
+ s = yajl_gen_map_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ for (j = 0; j < 2; j++) {
+ if (cpuid[i].input[j] != XEN_CPUID_INPUT_UNUSED) {
+ s = libxl__yajl_gen_asciiz(hand, input_names[j]);
+ if (s != yajl_gen_status_ok) goto out;
+ s = yajl_gen_integer(hand, cpuid[i].input[j]);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+ }
+
+ for (j = 0; j < 4; j++) {
+ if (cpuid[i].policy[j] != NULL) {
+ s = libxl__yajl_gen_asciiz(hand, policy_names[j]);
+ if (s != yajl_gen_status_ok) goto out;
+ s = yajl_gen_string(hand,
+ (const unsigned char *)cpuid[i].policy[j], 32);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+ }
+ s = yajl_gen_map_close(hand);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+
+empty:
+ s = yajl_gen_array_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_string_list_gen_json(yajl_gen hand, libxl_string_list
*pl)
+{
+ libxl_string_list l = *pl;
+ yajl_gen_status s;
+ int i;
+
+ s = yajl_gen_array_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ if (!l) goto empty;
+
+ for (i = 0; l[i] != NULL; i++) {
+ s = libxl__yajl_gen_asciiz(hand, l[i]);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+empty:
+ s = yajl_gen_array_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_mac_gen_json(yajl_gen hand, libxl_mac *mac)
+{
+ char buf[LIBXL_MAC_FMTLEN+1];
+ snprintf(buf, sizeof(buf), LIBXL_MAC_FMT, LIBXL_MAC_BYTES((*mac)));
+ return yajl_gen_string(hand, (const unsigned char *)buf, LIBXL_MAC_FMTLEN);
+}
+
+yajl_gen_status libxl_hwcap_gen_json(yajl_gen hand,
+ libxl_hwcap p)
+{
+ yajl_gen_status s;
+ int i;
+
+ s = yajl_gen_array_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ for(i=0; i<4; i++) {
+ s = yajl_gen_integer(hand, p[i]);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+ s = yajl_gen_array_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_cpuarray_gen_json(yajl_gen hand,
+ libxl_cpuarray *cpuarray)
+{
+ yajl_gen_status s;
+ int i;
+
+ s = yajl_gen_array_open(hand);
+ if (s != yajl_gen_status_ok) goto out;
+
+ for(i=0; i<cpuarray->entries; i++) {
+ if (cpuarray->array[i] == LIBXL_CPUARRAY_INVALID_ENTRY)
+ s = yajl_gen_null(hand);
+ else
+ s = yajl_gen_integer(hand, cpuarray->array[i]);
+ if (s != yajl_gen_status_ok) goto out;
+ }
+ s = yajl_gen_array_close(hand);
+out:
+ return s;
+}
+
+yajl_gen_status libxl_file_reference_gen_json(yajl_gen hand,
+ libxl_file_reference *p)
+{
+ if (p->path)
+ return libxl__yajl_gen_asciiz(hand, p->path);
+ else
+ return yajl_gen_null(hand);
+}
+
+yajl_gen_status libxl__string_gen_json(yajl_gen hand,
+ const char *p)
+{
+ if (p)
+ return libxl__yajl_gen_asciiz(hand, p);
+ else
+ return yajl_gen_null(hand);
+}
/*
* libxl__json_object helper functions
@@ -558,3 +760,68 @@ libxl__json_object *libxl__json_parse(li
return NULL;
}
}
+
+static const char *yajl_gen_status_to_string(yajl_gen_status s)
+{
+ switch (s) {
+ case yajl_gen_status_ok: abort();
+ case yajl_gen_keys_must_be_strings:
+ return "keys must be strings";
+ case yajl_max_depth_exceeded:
+ return "max depth exceeded";
+ case yajl_gen_in_error_state:
+ return "in error state";
+ case yajl_gen_generation_complete:
+ return "generation complete";
+ case yajl_gen_invalid_number:
+ return "invalid number";
+ case yajl_gen_no_buf:
+ return "no buffer";
+#if 0 /* This is in the docs but not implemented in the version I am running.
*/
+ case yajl_gen_invalid_string:
+ return "invalid string";
+#endif
+ default:
+ return "unknown error";
+ }
+}
+
+char *libxl__object_to_json(libxl_ctx *ctx, const char *type,
+ libxl__gen_json_callback gen, void *p)
+{
+ yajl_gen_config conf = { 1, " " };
+ const unsigned char *buf;
+ char *ret = NULL;
+ unsigned int len = 0;
+ yajl_gen_status s;
+ yajl_gen hand;
+
+ hand = yajl_gen_alloc(&conf, NULL);
+ if (!hand)
+ return NULL;
+
+ s = gen(hand, p);
+ if (s != yajl_gen_status_ok)
+ goto out;
+
+ s = yajl_gen_get_buf(hand, &buf, &len);
+ if (s != yajl_gen_status_ok)
+ goto out;
+ ret = strdup((const char *)buf);
+
+out:
+ yajl_gen_free(hand);
+
+ if (s != yajl_gen_status_ok) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "unable to convert %s to JSON representation. "
+ "YAJL error code %d: %s", type,
+ s, yajl_gen_status_to_string(s));
+ } else if (!ret) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "unable to allocate space for to JSON representation of %s",
+ type);
+ }
+
+ return ret;
+}
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxl_json.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxl_json.h Thu Sep 29 17:02:14 2011 +0100
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBXL_JSON_H
+#define LIBXL_JSON_H
+
+#include <yajl/yajl_gen.h>
+
+#include <_libxl_types_json.h>
+#include <_libxl_types_internal_json.h>
+
+yajl_gen_status libxl_uuid_gen_json(yajl_gen hand,
+ libxl_uuid *p);
+yajl_gen_status libxl_cpumap_gen_json(yajl_gen hand,
+ libxl_cpumap *p);
+yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand,
+ libxl_key_value_list *p);
+yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
+ libxl_cpuid_policy_list *p);
+yajl_gen_status libxl_string_list_gen_json(yajl_gen hand,
+ libxl_string_list *p);
+yajl_gen_status libxl_mac_gen_json(yajl_gen hand,
+ libxl_mac *p);
+yajl_gen_status libxl_hwcap_gen_json(yajl_gen hand,
+ libxl_hwcap p);
+yajl_gen_status libxl_cpuarray_gen_json(yajl_gen hand,
+ libxl_cpuarray *p);
+yajl_gen_status libxl_file_reference_gen_json(yajl_gen hand,
+ libxl_file_reference *p);
+
+#endif /* LIBXL_JSON_H */
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxl_types.idl
--- a/tools/libxl/libxl_types.idl Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/libxl_types.idl Thu Sep 29 17:02:14 2011 +0100
@@ -5,7 +5,7 @@
namespace("libxl_")
-libxl_domid = Builtin("domid")
+libxl_domid = Builtin("domid", json_fn = "yajl_gen_integer", autogenerate_json
= False)
libxl_uuid = Builtin("uuid", passby=PASS_BY_REFERENCE)
libxl_mac = Builtin("mac", passby=PASS_BY_REFERENCE)
libxl_cpumap = Builtin("cpumap", destructor_fn="libxl_cpumap_destroy",
passby=PASS_BY_REFERENCE)
diff -r fb42038b1f5c -r 030e844fcceb tools/libxl/libxltypes.py
--- a/tools/libxl/libxltypes.py Thu Sep 29 16:57:52 2011 +0100
+++ b/tools/libxl/libxltypes.py Thu Sep 29 17:02:14 2011 +0100
@@ -50,6 +50,13 @@ class Type(object):
self.autogenerate_destructor =
kwargs.setdefault('autogenerate_destructor', True)
+ if self.typename is not None:
+ self.json_fn = kwargs.setdefault('json_fn', self.typename +
"_gen_json")
+ else:
+ self.json_fn = kwargs.setdefault('json_fn', None)
+
+ self.autogenerate_json = kwargs.setdefault('autogenerate_json', True)
+
def marshal_in(self):
return self.dir in [DIR_IN, DIR_BOTH]
def marshal_out(self):
@@ -83,6 +90,7 @@ class Builtin(Type):
def __init__(self, typename, **kwargs):
kwargs.setdefault('destructor_fn', None)
kwargs.setdefault('autogenerate_destructor', False)
+ kwargs.setdefault('autogenerate_json', False)
Type.__init__(self, typename, **kwargs)
class Number(Builtin):
@@ -90,6 +98,7 @@ class Number(Builtin):
kwargs.setdefault('namespace', None)
kwargs.setdefault('destructor_fn', None)
kwargs.setdefault('signed', False)
+ kwargs.setdefault('json_fn', "yajl_gen_integer")
self.signed = kwargs['signed']
Builtin.__init__(self, ctype, **kwargs)
@@ -163,6 +172,8 @@ class Aggregate(Type):
comment = None
else:
n,t,const,comment = f
+ if n is None:
+ raise ValueError
self.fields.append(Field(t,n,const=const,comment=comment))
# Returns a tuple (stem, field-expr)
@@ -220,7 +231,10 @@ class KeyedUnion(Aggregate):
#
void = Builtin("void *", namespace = None)
-bool = Builtin("bool", namespace = None)
+bool = Builtin("bool", namespace = None,
+ json_fn = "yajl_gen_bool",
+ autogenerate_json = False)
+
size_t = Number("size_t", namespace = None)
integer = Number("int", namespace = None, signed = True)
@@ -230,7 +244,9 @@ uint16 = UInt(16)
uint32 = UInt(32)
uint64 = UInt(64)
-string = Builtin("char *", namespace = None, destructor_fn = "free")
+string = Builtin("char *", namespace = None, destructor_fn = "free",
+ json_fn = "libxl__string_gen_json",
+ autogenerate_json = False)
class OrderedDict(dict):
"""A dictionary which remembers insertion order.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|