Patchwork [7/9] qapi: add qapi-errors.py

login
register
mail settings
Submitter Luiz Capitulino
Date July 18, 2012, 5:49 p.m.
Message ID <1342633760-351-8-git-send-email-lcapitulino@redhat.com>
Download mbox | patch
Permalink /patch/171804/
State New
Headers show

Comments

Luiz Capitulino - July 18, 2012, 5:49 p.m.
This script generates two files from qapi-schema-errors.json:

 o qapi-errors.h: contains error macro definitions, eg. QERR_BASE_NOT_FOUND,
                  corresponds to most of today's qerror.h

 o qapi-errors.c: contains the error table that currently exists in qerror.c

The script is not used yet though, that's going to be done by the next
commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 Makefile               |   8 ++-
 scripts/qapi-errors.py | 180 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 2 deletions(-)
 create mode 100644 scripts/qapi-errors.py

Patch

diff --git a/Makefile b/Makefile
index ab82ef3..2cdc732 100644
--- a/Makefile
+++ b/Makefile
@@ -22,8 +22,9 @@  GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 ifeq ($(TRACE_BACKEND),dtrace)
 GENERATED_HEADERS += trace-dtrace.h
 endif
-GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
-GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c
+GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-errors.h
+GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-errors.c \
+                     trace.c
 
 # Don't try to regenerate Makefile or configure
 # We don't generate any of them
@@ -200,6 +201,9 @@  $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
 qmp-commands.h qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
+qapi-errors.h qapi-errors.c :\
+$(SRC_PATH)/qapi-schema-errors.json $(SRC_PATH)/scripts/qapi-errors.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-errors.py -o "." < $<, "  GEN   $@")
 
 QGALIB_OBJ=$(addprefix qapi-generated/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o)
 QGALIB_GEN=$(addprefix qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
diff --git a/scripts/qapi-errors.py b/scripts/qapi-errors.py
new file mode 100644
index 0000000..eb86b8e
--- /dev/null
+++ b/scripts/qapi-errors.py
@@ -0,0 +1,180 @@ 
+#
+# QAPI errors generator
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+import getopt, sys, os, errno
+from qapi import *
+
+def gen_error_decl_prologue(header, guard, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI Errors
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+''',
+                 header=basename(header), guard=guardname(header), prefix=prefix)
+    return ret
+
+def gen_error_def_prologue(error_header, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QMP Error table
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "%(prefix)s%(error_header)s"
+
+''',
+                prefix=prefix, error_header=error_header)
+    return ret
+
+def gen_error_def_table_init():
+    ret = mcgen('''
+static const QErrorStringTable qerror_table[] = {
+''')
+    return ret
+
+def gen_error_macro(err_domain):
+    string = ''
+    cur = err_domain[0]
+    for nxt in err_domain[1:]:
+        if string and cur.isupper() and nxt.islower():
+            string += '_'
+        string += cur
+        cur = nxt
+    string += cur
+    return 'QERR_' + string.upper()
+
+def gen_error_def_table_entry(name, desc):
+    err_macro = gen_error_macro(name)
+    ret = mcgen('''
+    {
+        .error_fmt = %(error_macro)s,
+        .desc      = "%(error_desc)s",
+    },
+''',
+                error_macro=err_macro, error_desc=desc)
+    return ret
+
+def gen_error_def_table_close():
+    ret = mcgen('''
+    {}
+};
+''')
+    return ret
+
+def maybe_open(really, name, opt):
+    if really:
+        return open(name, opt)
+    else:
+        import StringIO
+        return StringIO.StringIO()
+
+def gen_error_decl_macro(name, data):
+    colon = ''
+    data_str = ''
+    for k, v in data.items():
+        data_str += colon + "'%s': " % k
+        if v == 'str':
+            data_str += "%s"
+        elif v == 'int':
+            data_str += '%"PRId64"'
+        else:
+            sys.exit("unknown data type '%s' for error '%s'" % (v, name))
+        colon = ', '
+
+    err_macro = gen_error_macro(name)
+
+    ret = mcgen('''
+#define %(error_macro)s \\
+    "{ 'class': '%(error_class)s', 'data': { %(error_data)s } }"
+
+''',
+                error_macro=err_macro, error_class=name, error_data=data_str)
+    return ret
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
+                                       ["prefix=", "output-dir="])
+    except getopt.GetoptError, err:
+        print str(err)
+        sys.exit(1)
+
+    prefix = ""
+    output_dir = ""
+    do_c = True
+    do_h = True
+    c_file = 'qapi-errors.c'
+    h_file = 'qapi-errors.h'
+
+    for o, a in opts:
+        if o in ("-p", "--prefix"):
+            prefix = a
+        elif o in ("-o", "--output-dir"):
+            output_dir = a + "/"
+
+    c_file = output_dir + prefix + c_file
+    h_file = output_dir + prefix + h_file
+
+    try:
+        os.makedirs(output_dir)
+    except os.error, e:
+        if e.errno != errno.EEXIST:
+            raise
+
+    exprs = parse_schema(sys.stdin)
+
+    fdecl = maybe_open(do_h, h_file, 'w')
+    ret = gen_error_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    fdecl.write(ret)
+
+    fdef = maybe_open(do_c, c_file, 'w')
+    ret = gen_error_def_prologue(error_header=h_file, prefix=prefix)
+    fdef.write(ret)
+
+    ret = gen_error_def_table_init()
+    fdef.write(ret)
+
+    for err in exprs:
+        data = {}
+        if err.has_key('data'):
+            data = err['data']
+        ret = gen_error_decl_macro(err['error'], data)
+        fdecl.write(ret)
+
+        ret = gen_error_def_table_entry(err['error'], err['description'])
+        fdef.write(ret)
+
+    ret = gen_error_def_table_close()
+    fdef.write(ret)
+
+    fdecl.write("#endif\n")
+
+    fdecl.flush()
+    fdecl.close()
+    fdef.flush()
+    fdef.close()