[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1 of 4 v2] libxl: IDL: autogenerate functions to produce JSON from libxl data structures



# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxx>
# Date 1317981945 -3600
# Node ID 75a0a29cccbfce75ba3087cdaf53adfd1b377a11
# Parent  43b99763284fa639e47dbeb9245f0ebd1d4f2dad
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 43b99763284f -r 75a0a29cccbf tools/libxl/Makefile
--- a/tools/libxl/Makefile      Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/Makefile      Fri Oct 07 11:05:45 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 43b99763284f -r 75a0a29cccbf tools/libxl/gentest.py
--- a/tools/libxl/gentest.py    Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/gentest.py    Fri Oct 07 11:05:45 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,55 @@ 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,27 +73,208 @@ 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 \"libxl.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;
+}
+
+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:
-            f.write("    printf(\"\\t%s = %%d = \\\"%%s\\\"\\n\", %s, 
%s_to_string(%s));\n" %\
+            f.write("    printf(\"\\t%s = %%d = \\\"%%s\\\"\\n\", " \
+                    "%s, %s_to_string(%s));\n" % \
+                    (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")
 
@@ -54,10 +285,16 @@ int main(int argc, char **argv)
             f.write("    rc = %s_from_string(\"%s\", &%s_val);\n" %\
                     (ty.typename, n, ty.typename))
 
-            f.write("    printf(\"\\t%s = \\\"%%s\\\" = %%d (rc %%d)\\n\", 
\"%s\", %s_val, rc);\n" %\
+            f.write("    printf(\"\\t%s = \\\"%%s\\\" = %%d (rc %%d)\\n\", " \
+                    "\"%s\", %s_val, rc);\n" %\
                     (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 43b99763284f -r 75a0a29cccbf tools/libxl/gentypes.py
--- a/tools/libxl/gentypes.py   Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/gentypes.py   Fri Oct 07 11:05:45 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,60 @@ 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 += "s = libxl__yajl_gen_enum(hand, %s_to_string(%s));\n" % 
(ty.typename, ty.pass_arg(v, parent is None))
+        s += "if (s != yajl_gen_status_ok)\n"
+        s += "    goto out;\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,13 +190,13 @@ 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)
+    (builtins,types) = libxltypes.parse(idl)
 
     print "outputting libxl type definitions to %s" % header
 
@@ -167,6 +219,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 +230,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+builtins 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 +300,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 43b99763284f -r 75a0a29cccbf tools/libxl/idl.txt
--- a/tools/libxl/idl.txt       Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/idl.txt       Fri Oct 07 11:05:45 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 43b99763284f -r 75a0a29cccbf tools/libxl/libxl.h
--- a/tools/libxl/libxl.h       Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/libxl.h       Fri Oct 07 11:05:45 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 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/libxl_internal.h      Fri Oct 07 11:05:45 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
@@ -362,6 +364,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
@@ -447,6 +457,7 @@ _hidden int libxl__qmp_initializations(l
 #include <yajl/yajl_gen.h>
 
 _hidden yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str);
+_hidden yajl_gen_status libxl__yajl_gen_enum(yajl_gen hand, const char *str);
 
 typedef enum {
     JSON_ERROR,
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_json.c
--- a/tools/libxl/libxl_json.c  Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/libxl_json.c  Fri Oct 07 11:05:45 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,216 @@ yajl_gen_status libxl__yajl_gen_asciiz(y
     return yajl_gen_string(hand, (const unsigned char *)str, strlen(str));
 }
 
+yajl_gen_status libxl__yajl_gen_enum(yajl_gen hand, const char *str)
+{
+    if (str)
+        return libxl__yajl_gen_asciiz(hand, str);
+    else
+        return yajl_gen_null(hand);
+}
+
+/*
+ * 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-ecx',
+     *       'eax':     'filter',
+     *       '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 +769,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 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_json.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxl_json.h  Fri Oct 07 11:05:45 2011 +0100
@@ -0,0 +1,23 @@
+/*
+ * 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>
+
+#endif /* LIBXL_JSON_H */
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_types.idl
--- a/tools/libxl/libxl_types.idl       Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/libxl_types.idl       Fri Oct 07 11:05:45 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)
@@ -16,7 +16,7 @@ libxl_string_list = Builtin("string_list
 libxl_key_value_list = Builtin("key_value_list", 
destructor_fn="libxl_key_value_list_destroy", passby=PASS_BY_REFERENCE)
 libxl_file_reference = Builtin("file_reference", 
destructor_fn="libxl_file_reference_destroy", passby=PASS_BY_REFERENCE)
 
-libxl_hwcap = Builtin("hwcap")
+libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE)
 
 #
 # Constants / Enumerations
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxltypes.py
--- a/tools/libxl/libxltypes.py Fri Oct 07 10:10:31 2011 +0100
+++ b/tools/libxl/libxltypes.py Fri Oct 07 11:05:45 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.