diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-05-15 17:51:20 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-05-15 17:51:20 +0100 |
commit | 385057cbec9b4a0eb6150330c572e875ed714965 (patch) | |
tree | 7adc24566bfe8afc56aee25128b2fc3bd5a6a9a5 | |
parent | 99e7627a70d1a23e30a514e5a4798005cf4eb3aa (diff) | |
parent | 4180978c9205c50acd2d6c385def9b3e81911696 (diff) | |
download | qemu-385057cbec9b4a0eb6150330c572e875ed714965.zip qemu-385057cbec9b4a0eb6150330c572e875ed714965.tar.gz qemu-385057cbec9b4a0eb6150330c572e875ed714965.tar.bz2 |
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-05-15' into staging
qapi: Fix qapi mangling of downstream names, and more
# gpg: Signature made Fri May 15 17:41:31 2015 BST using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>"
* remotes/armbru/tags/pull-qapi-2015-05-15: (26 commits)
qapi: Inline gen_command_decl_prologue(), gen_command_def_prologue()
qapi: Drop pointless flush() before close()
qapi: Factor open_output(), close_output() out of generators
qapi: Turn generators' mandatory option -i into an argument
qapi: Fix generators to report command line errors decently
qapi: Factor parse_command_line() out of the generators
qapi: qapi-commands.py option --type is unused, drop it
qapi: qapi-event.py option -b does nothing, drop it
tests: Add missing dependencies on $(qapi-py)
qapi: Support downstream events and commands
qapi: Support downstream alternates
qapi: Support downstream flat unions
qapi: Support downstream simple unions
qapi: Support downstream structs
qapi: Support downstream enums
qapi: Make c_type() consistently convert qapi names
qapi: Tidy c_type() logic
qapi: Move camel_to_upper(), c_enum_const() to closely related code
qapi: Use c_enum_const() in generate_alternate_qtypes()
qapi: Simplify c_enum_const()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | cpus.c | 1 | ||||
-rw-r--r-- | docs/qapi-code-gen.txt | 10 | ||||
-rw-r--r-- | docs/qmp/qmp-events.txt | 4 | ||||
-rw-r--r-- | qapi-schema.json | 8 | ||||
-rw-r--r-- | qmp-commands.hx | 7 | ||||
-rw-r--r-- | scripts/qapi-commands.py | 222 | ||||
-rw-r--r-- | scripts/qapi-event.py | 125 | ||||
-rw-r--r-- | scripts/qapi-types.py | 147 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 151 | ||||
-rw-r--r-- | scripts/qapi.py | 244 | ||||
-rw-r--r-- | tests/Makefile | 16 | ||||
-rw-r--r-- | tests/qapi-schema/qapi-schema-test.json | 20 | ||||
-rw-r--r-- | tests/qapi-schema/qapi-schema-test.out | 21 | ||||
-rw-r--r-- | tests/test-qmp-commands.c | 15 |
15 files changed, 453 insertions, 552 deletions
@@ -243,17 +243,17 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ @@ -263,22 +263,22 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." -b $<, \ " GEN $@") qapi-visit.c qapi-visit.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." -b $<, \ " GEN $@") qapi-event.c qapi-event.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." $<, \ " GEN $@") qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o "." -m -i $<, \ + $(gen-out-type) -o "." -m $<, \ " GEN $@") QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) @@ -1435,6 +1435,7 @@ CpuInfoList *qmp_query_cpus(Error **errp) info->value->CPU = cpu->cpu_index; info->value->current = (cpu == first_cpu); info->value->halted = cpu->halted; + info->value->qom_path = object_get_canonical_path(OBJECT(cpu)); info->value->thread_id = cpu->thread_id; #if defined(TARGET_I386) info->value->has_pc = true; diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 269a1f3..3f0522e 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -536,7 +536,7 @@ created code. Example: $ python scripts/qapi-types.py --output-dir="qapi-generated" \ - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-types.c [Uninteresting stuff omitted...] @@ -623,7 +623,7 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor Example: $ python scripts/qapi-visit.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-visit.c [Uninteresting stuff omitted...] @@ -681,7 +681,7 @@ Example: error_propagate(errp, err); } $ python scripts/qapi-commands.py --output-dir="qapi-generated" \ - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-visit.h [Uninteresting stuff omitted...] @@ -715,7 +715,7 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands Example: $ python scripts/qapi-commands.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qmp-marshal.c [Uninteresting stuff omitted...] @@ -806,7 +806,7 @@ $(prefix)qapi-event.c - Implementation of functions to send an event Example: $ python scripts/qapi-event.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-event.c [Uninteresting stuff omitted...] diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt index 6dc2cca..4c13d48 100644 --- a/docs/qmp/qmp-events.txt +++ b/docs/qmp/qmp-events.txt @@ -232,7 +232,7 @@ Example: { "event": "GUEST_PANICKED", "data": { "action": "pause" } } -MEM_HOT_UNPLUG_ERROR +MEM_UNPLUG_ERROR -------------------- Emitted when memory hot unplug error occurs. @@ -243,7 +243,7 @@ Data: Example: -{ "event": "MEM_HOT_UNPLUG_ERROR" +{ "event": "MEM_UNPLUG_ERROR" "data": { "device": "dimm1", "msg": "acpi: device unplug for unsupported device" }, diff --git a/qapi-schema.json b/qapi-schema.json index 9c92482..f97ffa1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -679,6 +679,8 @@ # @halted: true if the virtual CPU is in the halt state. Halt usually refers # to a processor specific low power mode. # +# @qom_path: path to the CPU object in the QOM tree (since 2.4) +# # @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction # pointer. # If the target is Sparc, this is the PC component of the @@ -699,8 +701,10 @@ # data is sent to the client, the guest may no longer be halted. ## { 'struct': 'CpuInfo', - 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int', - '*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} } + 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', + 'qom_path': 'str', + '*pc': 'int', '*nip': 'int', '*npc': 'int', '*PC': 'int', + 'thread_id': 'int'} } ## # @query-cpus: diff --git a/qmp-commands.hx b/qmp-commands.hx index 7506774..14e109e 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2569,6 +2569,7 @@ Return a json-array. Each CPU is represented by a json-object, which contains: - "CPU": CPU index (json-int) - "current": true if this is the current CPU, false otherwise (json-bool) - "halted": true if the cpu is halted, false otherwise (json-bool) +- "qom_path": path to the CPU object in the QOM tree (json-str) - Current program counter. The key's name depends on the architecture: "pc": i386/x86_64 (json-int) "nip": PPC (json-int) @@ -2585,14 +2586,16 @@ Example: "CPU":0, "current":true, "halted":false, - "pc":3227107138 + "qom_path":"/machine/unattached/device[0]", + "pc":3227107138, "thread_id":3134 }, { "CPU":1, "current":false, "halted":true, - "pc":7108165 + "qom_path":"/machine/unattached/device[2]", + "pc":7108165, "thread_id":3135 } ] diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 93e43f0..1c1d3aa 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -15,28 +15,19 @@ from ordereddict import OrderedDict from qapi import * import re -import sys -import os -import getopt -import errno - -def type_visitor(name): - if type(name) == list: - return 'visit_type_%sList' % name[0] - else: - return 'visit_type_%s' % name def generate_command_decl(name, args, ret_type): arglist="" for argname, argtype, optional in parse_args(args): argtype = c_type(argtype, is_param=True) if optional: - arglist += "bool has_%s, " % c_var(argname) - arglist += "%s %s, " % (argtype, c_var(argname)) + arglist += "bool has_%s, " % c_name(argname) + arglist += "%s %s, " % (argtype, c_name(argname)) return mcgen(''' %(ret_type)s qmp_%(name)s(%(args)sError **errp); ''', - ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() + ret_type=c_type(ret_type), name=c_name(name), + args=arglist).strip() def gen_err_check(errvar): if errvar: @@ -55,14 +46,14 @@ def gen_sync_call(name, args, ret_type, indent=0): retval = "retval = " for argname, argtype, optional in parse_args(args): if optional: - arglist += "has_%s, " % c_var(argname) - arglist += "%s, " % (c_var(argname)) + arglist += "has_%s, " % c_name(argname) + arglist += "%s, " % (c_name(argname)) push_indent(indent) ret = mcgen(''' %(retval)sqmp_%(name)s(%(args)s&local_err); ''', - name=c_fun(name), args=arglist, retval=retval).rstrip() + name=c_name(name), args=arglist, retval=retval).rstrip() if ret_type: ret += "\n" + gen_err_check('local_err') ret += "\n" + mcgen('''' @@ -76,7 +67,7 @@ def gen_sync_call(name, args, ret_type, indent=0): def gen_marshal_output_call(name, ret_type): if not ret_type: return "" - return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name) + return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_name(name) def gen_visitor_input_containers_decl(args, obj): ret = "" @@ -101,17 +92,17 @@ def gen_visitor_input_vars_decl(args): ret += mcgen(''' bool has_%(argname)s = false; ''', - argname=c_var(argname)) + argname=c_name(argname)) if is_c_ptr(argtype): ret += mcgen(''' %(argtype)s %(argname)s = NULL; ''', - argname=c_var(argname), argtype=c_type(argtype)) + argname=c_name(argname), argtype=c_type(argtype)) else: ret += mcgen(''' %(argtype)s %(argname)s = {0}; ''', - argname=c_var(argname), argtype=c_type(argtype)) + argname=c_name(argname), argtype=c_type(argtype)) pop_indent() return ret.rstrip() @@ -144,18 +135,18 @@ v = qmp_input_get_visitor(mi); ret += mcgen(''' visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); ''', - c_name=c_var(argname), name=argname, errp=errparg) + c_name=c_name(argname), name=argname, errp=errparg) ret += gen_err_check(errarg) ret += mcgen(''' if (has_%(c_name)s) { ''', - c_name=c_var(argname)) + c_name=c_name(argname)) push_indent() ret += mcgen(''' -%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); +visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); ''', - c_name=c_var(argname), name=argname, argtype=argtype, - visitor=type_visitor(argtype), errp=errparg) + c_name=c_name(argname), name=argname, argtype=argtype, + visitor=type_name(argtype), errp=errparg) ret += gen_err_check(errarg) if optional: pop_indent() @@ -183,7 +174,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o Visitor *v; v = qmp_output_get_visitor(mo); - %(visitor)s(v, &ret_in, "unused", &local_err); + visit_type_%(visitor)s(v, &ret_in, "unused", &local_err); if (local_err) { goto out; } @@ -194,20 +185,20 @@ out: qmp_output_visitor_cleanup(mo); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); - %(visitor)s(v, &ret_in, "unused", NULL); + visit_type_%(visitor)s(v, &ret_in, "unused", NULL); qapi_dealloc_visitor_cleanup(md); } ''', - c_ret_type=c_type(ret_type), c_name=c_fun(name), - visitor=type_visitor(ret_type)) + c_ret_type=c_type(ret_type), c_name=c_name(name), + visitor=type_name(ret_type)) return ret def gen_marshal_input_decl(name, args, ret_type, middle_mode): if middle_mode: - return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name) + return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_name(name) else: - return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name) + return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) @@ -304,7 +295,7 @@ def gen_registry(commands): registry += mcgen(''' qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s); ''', - name=cmd['command'], c_name=c_fun(cmd['command']), + name=cmd['command'], c_name=c_name(cmd['command']), opts=options) pop_indent() ret = mcgen(''' @@ -318,12 +309,22 @@ qapi_init(qmp_init_marshal); registry=registry.rstrip()) return ret -def gen_command_decl_prologue(header, guard, prefix=""): - ret = mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ +middle_mode = False + +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("m", ["middle"]) + +for o, a in opts: + if o in ("-m", "--middle"): + middle_mode = True +exprs = parse_schema(input_file) +commands = filter(lambda expr: expr.has_key('command'), exprs) +commands = filter(lambda expr: not expr.has_key('gen'), commands) + +c_comment = ''' /* - * schema-defined QAPI function prototypes + * schema-defined QMP->QAPI command dispatch * * Copyright IBM, Corp. 2011 * @@ -334,24 +335,10 @@ def gen_command_decl_prologue(header, guard, prefix=""): * See the COPYING.LIB file in the top-level directory. * */ - -#ifndef %(guard)s -#define %(guard)s - -#include "%(prefix)sqapi-types.h" -#include "qapi/qmp/qdict.h" -#include "qapi/error.h" - -''', - header=basename(header), guard=guardname(header), prefix=prefix) - return ret - -def gen_command_def_prologue(prefix="", proxy=False): - ret = mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* - * schema-defined QMP->QAPI command dispatch + * schema-defined QAPI function prototypes * * Copyright IBM, Corp. 2011 * @@ -362,7 +349,13 @@ def gen_command_def_prologue(prefix="", proxy=False): * See the COPYING.LIB file in the top-level directory. * */ +''' + +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qmp-marshal.c', 'qmp-commands.h', + c_comment, h_comment) +fdef.write(mcgen(''' #include "qemu-common.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" @@ -374,107 +367,40 @@ def gen_command_def_prologue(prefix="", proxy=False): #include "qapi/dealloc-visitor.h" #include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-visit.h" +#include "%(prefix)sqmp-commands.h" ''', - prefix=prefix) - if not proxy: - ret += '#include "%sqmp-commands.h"' % prefix - return ret + "\n\n" - - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:m", - ["source", "header", "prefix=", - "input-file=", "output-dir=", - "type=", "middle"]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -output_dir = "" -prefix = "" -dispatch_type = "sync" -c_file = 'qmp-marshal.c' -h_file = 'qmp-commands.h' -middle_mode = False - -do_c = False -do_h = False - -for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-t", "--type"): - dispatch_type = a - elif o in ("-m", "--middle"): - middle_mode = True - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - -if not do_c and not do_h: - do_c = True - do_h = True - -c_file = output_dir + prefix + c_file -h_file = output_dir + prefix + h_file + prefix=prefix)) -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -try: - os.makedirs(output_dir) -except os.error, e: - if e.errno != errno.EEXIST: - raise - -exprs = parse_schema(input_file) -commands = filter(lambda expr: expr.has_key('command'), exprs) -commands = filter(lambda expr: not expr.has_key('gen'), commands) +fdecl.write(mcgen(''' +#include "%(prefix)sqapi-types.h" +#include "qapi/qmp/qdict.h" +#include "qapi/error.h" -if dispatch_type == "sync": - fdecl = maybe_open(do_h, h_file, 'w') - fdef = maybe_open(do_c, c_file, 'w') - ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) +''', + prefix=prefix)) + +for cmd in commands: + arglist = [] + ret_type = None + if cmd.has_key('data'): + arglist = cmd['data'] + if cmd.has_key('returns'): + ret_type = cmd['returns'] + ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" fdecl.write(ret) - ret = gen_command_def_prologue(prefix=prefix) - fdef.write(ret) - - for cmd in commands: - arglist = [] - ret_type = None - if cmd.has_key('data'): - arglist = cmd['data'] - if cmd.has_key('returns'): - ret_type = cmd['returns'] - ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" - fdecl.write(ret) - if ret_type: - ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" - fdef.write(ret) - - if middle_mode: - fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) - - ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" + if ret_type: + ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" fdef.write(ret) - fdecl.write("\n#endif\n"); + if middle_mode: + fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) - if not middle_mode: - ret = gen_registry(commands) - fdef.write(ret) + ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" + fdef.write(ret) + +if not middle_mode: + ret = gen_registry(commands) + fdef.write(ret) - fdef.flush() - fdef.close() - fdecl.flush() - fdecl.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 47dc041..56bc602 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -11,23 +11,19 @@ from ordereddict import OrderedDict from qapi import * -import sys -import os -import getopt -import errno def _generate_event_api_name(event_name, params): - api_name = "void qapi_event_send_%s(" % c_fun(event_name).lower(); + api_name = "void qapi_event_send_%s(" % c_name(event_name).lower(); l = len(api_name) if params: for argname, argentry, optional in parse_args(params): if optional: - api_name += "bool has_%s,\n" % c_var(argname) + api_name += "bool has_%s,\n" % c_name(argname) api_name += "".ljust(l) api_name += "%s %s,\n" % (c_type(argentry, is_param=True), - c_var(argname)) + c_name(argname)) api_name += "".ljust(l) api_name += "Error **errp)" @@ -98,7 +94,7 @@ def generate_event_implement(api_name, event_name, params): ret += mcgen(""" if (has_%(var)s) { """, - var = c_var(argname)) + var = c_name(argname)) push_indent() if argentry == "str": @@ -113,7 +109,7 @@ def generate_event_implement(api_name, event_name, params): } """, var_type = var_type, - var = c_var(argname), + var = c_name(argname), type = type_name(argentry), name = argname) @@ -177,7 +173,7 @@ typedef enum %(event_enum_name)s event_enum_name = event_enum_name) # append automatically generated _MAX value - enum_max_value = generate_enum_full_value(event_enum_name, "MAX") + enum_max_value = c_enum_const(event_enum_name, "MAX") enum_values = event_enum_values + [ enum_max_value ] i = 0 @@ -216,67 +212,9 @@ const char *%(event_enum_name)s_lookup[] = { ''') return ret +(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() -# Start the real job - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", "prefix=", - "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -input_file = "" -output_dir = "" -prefix = "" -c_file = 'qapi-event.c' -h_file = 'qapi-event.h' - -do_c = False -do_h = False -do_builtins = False - -for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - elif o in ("-b", "--builtins"): - do_builtins = True - -if not do_c and not do_h: - do_c = True - do_h = True - -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 - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') - -fdef.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +c_comment = ''' /* * schema-defined QAPI event functions * @@ -289,19 +227,8 @@ fdef.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ - -#include "qemu-common.h" -#include "%(header)s" -#include "%(prefix)sqapi-visit.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-event.h" - -''', - prefix=prefix, header=basename(h_file))) - -fdecl.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* * schema-defined QAPI event functions * @@ -314,16 +241,29 @@ fdecl.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ +''' -#ifndef %(guard)s -#define %(guard)s +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-event.c', 'qapi-event.h', + c_comment, h_comment) +fdef.write(mcgen(''' +#include "qemu-common.h" +#include "%(prefix)sqapi-event.h" +#include "%(prefix)sqapi-visit.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/qmp-event.h" + +''', + prefix=prefix)) + +fdecl.write(mcgen(''' #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "%(prefix)sqapi-types.h" ''', - prefix=prefix, guard=guardname(h_file))) + prefix=prefix)) exprs = parse_schema(input_file) @@ -343,8 +283,7 @@ for expr in exprs: fdecl.write(ret) # We need an enum value per event - event_enum_value = generate_enum_full_value(event_enum_name, - event_name) + event_enum_value = c_enum_const(event_enum_name, event_name) ret = generate_event_implement(api_name, event_name, params) fdef.write(ret) @@ -357,12 +296,4 @@ fdecl.write(ret) ret = generate_event_enum_lookup(event_enum_name, event_enum_strings) fdef.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 2bf8145..6bd0b13 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -11,10 +11,6 @@ from ordereddict import OrderedDict from qapi import * -import sys -import os -import getopt -import errno def generate_fwd_struct(name, members, builtin_type=False): if builtin_type: @@ -45,7 +41,7 @@ typedef struct %(name)sList struct %(name)sList *next; } %(name)sList; ''', - name=name) + name=c_name(name)) def generate_fwd_enum_struct(name, members): return mcgen(''' @@ -58,7 +54,7 @@ typedef struct %(name)sList struct %(name)sList *next; } %(name)sList; ''', - name=name) + name=c_name(name)) def generate_struct_fields(members): ret = '' @@ -68,11 +64,11 @@ def generate_struct_fields(members): ret += mcgen(''' bool has_%(c_name)s; ''', - c_name=c_var(argname)) + c_name=c_name(argname)) ret += mcgen(''' %(c_type)s %(c_name)s; ''', - c_type=c_type(argentry), c_name=c_var(argname)) + c_type=c_type(argentry), c_name=c_name(argname)) return ret @@ -87,7 +83,7 @@ def generate_struct(expr): struct %(name)s { ''', - name=structname) + name=c_name(structname)) if base: ret += generate_struct_fields({'base': base}) @@ -115,16 +111,16 @@ def generate_enum_lookup(name, values): ret = mcgen(''' const char *%(name)s_lookup[] = { ''', - name=name) + name=c_name(name)) i = 0 for value in values: - index = generate_enum_full_value(name, value) + index = c_enum_const(name, value) ret += mcgen(''' [%(index)s] = "%(value)s", ''', index = index, value = value) - max_index = generate_enum_full_value(name, 'MAX') + max_index = c_enum_const(name, 'MAX') ret += mcgen(''' [%(max_index)s] = NULL, }; @@ -134,6 +130,7 @@ const char *%(name)s_lookup[] = { return ret def generate_enum(name, values): + name = c_name(name) lookup_decl = mcgen(''' extern const char *%(name)s_lookup[]; ''', @@ -150,7 +147,7 @@ typedef enum %(name)s i = 0 for value in enum_values: - enum_full_value = generate_enum_full_value(name, value) + enum_full_value = c_enum_const(name, value) enum_decl += mcgen(''' %(enum_full_value)s = %(i)d, ''', @@ -173,18 +170,17 @@ def generate_alternate_qtypes(expr): ret = mcgen(''' const int %(name)s_qtypes[QTYPE_MAX] = { ''', - name=name) + name=c_name(name)) for key in members: qtype = find_alternate_member_qtype(members[key]) assert qtype, "Invalid alternate member" ret += mcgen(''' - [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, + [%(qtype)s] = %(enum_const)s, ''', - qtype = qtype, - abbrev = de_camel_case(name).upper(), - enum = c_fun(de_camel_case(key),False).upper()) + qtype = qtype, + enum_const = c_enum_const(name + 'Kind', key)) ret += mcgen(''' }; @@ -194,7 +190,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = { def generate_union(expr, meta): - name = expr[meta] + name = c_name(expr[meta]) typeinfo = expr['data'] base = expr.get('base') @@ -214,14 +210,14 @@ struct %(name)s void *data; ''', name=name, - discriminator_type_name=discriminator_type_name) + discriminator_type_name=c_name(discriminator_type_name)) for key in typeinfo: ret += mcgen(''' %(c_type)s %(c_name)s; ''', c_type=c_type(typeinfo[key]), - c_name=c_fun(key)) + c_name=c_name(key)) ret += mcgen(''' }; @@ -249,15 +245,15 @@ extern const int %(name)s_qtypes[]; def generate_type_cleanup_decl(name): ret = mcgen(''' -void qapi_free_%(type)s(%(c_type)s obj); +void qapi_free_%(name)s(%(c_type)s obj); ''', - c_type=c_type(name),type=name) + c_type=c_type(name), name=c_name(name)) return ret def generate_type_cleanup(name): ret = mcgen(''' -void qapi_free_%(type)s(%(c_type)s obj) +void qapi_free_%(name)s(%(c_type)s obj) { QapiDeallocVisitor *md; Visitor *v; @@ -268,72 +264,23 @@ void qapi_free_%(type)s(%(c_type)s obj) md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); - visit_type_%(type)s(v, &obj, NULL, NULL); + visit_type_%(name)s(v, &obj, NULL, NULL); qapi_dealloc_visitor_cleanup(md); } ''', - c_type=c_type(name),type=name) + c_type=c_type(name), name=c_name(name)) return ret - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", - "prefix=", "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -output_dir = "" -input_file = "" -prefix = "" -c_file = 'qapi-types.c' -h_file = 'qapi-types.h' - -do_c = False -do_h = False do_builtins = False +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("b", ["builtins"]) + for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - elif o in ("-b", "--builtins"): + if o in ("-b", "--builtins"): do_builtins = True -if not do_c and not do_h: - do_c = True - do_h = True - -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 - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') - -fdef.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +c_comment = ''' /* * deallocation functions for schema-defined QAPI types * @@ -347,16 +294,8 @@ fdef.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ - -#include "qapi/dealloc-visitor.h" -#include "%(prefix)sqapi-types.h" -#include "%(prefix)sqapi-visit.h" - -''', prefix=prefix)) - -fdecl.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* * schema-defined QAPI types * @@ -369,15 +308,25 @@ fdecl.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ +''' -#ifndef %(guard)s -#define %(guard)s +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-types.c', 'qapi-types.h', + c_comment, h_comment) +fdef.write(mcgen(''' +#include "qapi/dealloc-visitor.h" +#include "%(prefix)sqapi-types.h" +#include "%(prefix)sqapi-visit.h" + +''', + prefix=prefix)) + +fdecl.write(mcgen(''' #include <stdbool.h> #include <stdint.h> -''', - guard=guardname(h_file))) +''')) exprs = parse_schema(input_file) exprs = filter(lambda expr: not expr.has_key('gen'), exprs) @@ -455,12 +404,4 @@ for expr in exprs: continue fdecl.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 0e67b33..5b99336 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,10 +15,6 @@ from ordereddict import OrderedDict from qapi import * import re -import sys -import os -import getopt -import errno implicit_structs = [] @@ -56,7 +52,7 @@ static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) { Error *err = NULL; ''', - name=name) + name=c_name(name)) push_indent() if base: @@ -66,7 +62,7 @@ if (err) { goto out; } ''', - type=type_name(base), c_name=c_var('base')) + type=type_name(base), c_name=c_name('base')) for argname, argentry, optional in parse_args(members): if optional: @@ -74,13 +70,13 @@ if (err) { visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err); if (!err && (*obj)->has_%(c_name)s) { ''', - c_name=c_var(argname), name=argname) + c_name=c_name(argname), name=argname) push_indent() ret += mcgen(''' visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err); ''', - type=type_name(argentry), c_name=c_var(argname), + type=type_name(argentry), c_name=c_name(argname), name=argname) if optional: @@ -111,16 +107,16 @@ def generate_visit_struct_body(name, members): ret = mcgen(''' Error *err = NULL; - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err); if (!err) { if (*obj) { - visit_type_%(name)s_fields(m, obj, errp); + visit_type_%(c_name)s_fields(m, obj, errp); } visit_end_struct(m, &err); } error_propagate(errp, err); ''', - name=name) + name=name, c_name=c_name(name)) return ret @@ -137,7 +133,7 @@ def generate_visit_struct(expr): void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) { ''', - name=name) + name=c_name(name)) ret += generate_visit_struct_body(name, members) @@ -173,7 +169,7 @@ out: error_propagate(errp, err); } ''', - name=name) + name=type_name(name)) def generate_visit_enum(name, members): return mcgen(''' @@ -183,7 +179,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); } ''', - name=name) + name=c_name(name)) def generate_visit_alternate(name, members): ret = mcgen(''' @@ -202,11 +198,11 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e } switch ((*obj)->kind) { ''', - name=name) + name=c_name(name)) # For alternate, always use the default enum type automatically generated - # as "'%sKind' % (name)" - disc_type = '%sKind' % (name) + # as name + 'Kind' + disc_type = c_name(name) + 'Kind' for key in members: assert (members[key] in builtin_types.keys() @@ -214,7 +210,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e or find_union(members[key]) or find_enum(members[key])), "Invalid alternate member" - enum_full_value = generate_enum_full_value(disc_type, key) + enum_full_value = c_enum_const(disc_type, key) ret += mcgen(''' case %(enum_full_value)s: visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); @@ -222,7 +218,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e ''', enum_full_value = enum_full_value, c_type = type_name(members[key]), - c_name = c_fun(key)) + c_name = c_name(key)) ret += mcgen(''' default: @@ -252,12 +248,12 @@ def generate_visit_union(expr): if enum_define: # Use the enum type as discriminator ret = "" - disc_type = enum_define['enum_name'] + disc_type = c_name(enum_define['enum_name']) else: # There will always be a discriminator in the C switch code, by default - # it is an enum type generated silently as "'%sKind' % (name)" - ret = generate_visit_enum('%sKind' % name, members.keys()) - disc_type = '%sKind' % (name) + # it is an enum type generated silently + ret = generate_visit_enum(name + 'Kind', members.keys()) + disc_type = c_name(name) + 'Kind' if base: assert discriminator @@ -281,7 +277,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e } if (*obj) { ''', - name=name) + name=c_name(name)) if base: ret += mcgen(''' @@ -290,7 +286,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e goto out_obj; } ''', - name=name) + name=c_name(name)) if not discriminator: disc_key = "type" @@ -315,7 +311,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e else: fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' - enum_full_value = generate_enum_full_value(disc_type, key) + enum_full_value = c_enum_const(disc_type, key) ret += mcgen(''' case %(enum_full_value)s: ''' + fmt + ''' @@ -323,7 +319,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e ''', enum_full_value = enum_full_value, c_type=type_name(members[key]), - c_name=c_fun(key)) + c_name=c_name(key)) ret += mcgen(''' default: @@ -347,6 +343,7 @@ out: def generate_declaration(name, members, builtin_type=False): ret = "" if not builtin_type: + name = c_name(name) ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp); @@ -364,7 +361,7 @@ def generate_enum_declaration(name, members): ret = mcgen(''' void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); ''', - name=name) + name=c_name(name)) return ret @@ -373,66 +370,18 @@ def generate_decl_enum(name, members): void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp); ''', - name=name) - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", "prefix=", - "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -input_file = "" -output_dir = "" -prefix = "" -c_file = 'qapi-visit.c' -h_file = 'qapi-visit.h' - -do_c = False -do_h = False + name=c_name(name)) + do_builtins = False +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("b", ["builtins"]) + for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - elif o in ("-b", "--builtins"): + if o in ("-b", "--builtins"): do_builtins = True -if not do_c and not do_h: - do_c = True - do_h = True - -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 - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') - -fdef.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +c_comment = ''' /* * schema-defined QAPI visitor functions * @@ -445,15 +394,8 @@ fdef.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ - -#include "qemu-common.h" -#include "%(header)s" -''', - header=basename(h_file))) - -fdecl.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* * schema-defined QAPI visitor functions * @@ -466,15 +408,24 @@ fdecl.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ +''' + +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-visit.c', 'qapi-visit.h', + c_comment, h_comment) -#ifndef %(guard)s -#define %(guard)s +fdef.write(mcgen(''' +#include "qemu-common.h" +#include "%(prefix)sqapi-visit.h" +''', + prefix = prefix)) +fdecl.write(mcgen(''' #include "qapi/visitor.h" #include "%(prefix)sqapi-types.h" ''', - prefix=prefix, guard=guardname(h_file))) + prefix=prefix)) exprs = parse_schema(input_file) @@ -530,12 +481,4 @@ for expr in exprs: ret += generate_enum_declaration(expr['enum'], expr['data']) fdecl.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi.py b/scripts/qapi.py index 166b74f..f96a777 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -13,8 +13,11 @@ import re from ordereddict import OrderedDict +import errno +import getopt import os import sys +import string builtin_types = { 'str': 'QTYPE_QSTRING', @@ -537,7 +540,7 @@ def check_union(expr, expr_info): # Otherwise, check for conflicts in the generated enum else: - c_key = _generate_enum_string(key) + c_key = camel_to_upper(key) if c_key in values: raise QAPIExprError(expr_info, "Union '%s' member '%s' clashes with '%s'" @@ -555,7 +558,7 @@ def check_alternate(expr, expr_info): check_name(expr_info, "Member of alternate '%s'" % name, key) # Check for conflicts in the generated enum - c_key = _generate_enum_string(key) + c_key = camel_to_upper(key) if c_key in values: raise QAPIExprError(expr_info, "Alternate '%s' member '%s' clashes with '%s'" @@ -586,7 +589,7 @@ def check_enum(expr, expr_info): for member in members: check_name(expr_info, "Member of enum '%s'" %name, member, enum_member=True) - key = _generate_enum_string(member) + key = camel_to_upper(member) if key in values: raise QAPIExprError(expr_info, "Enum '%s' member '%s' clashes with '%s'" @@ -728,17 +731,6 @@ def parse_args(typeinfo): # value of an optional argument. yield (argname, argentry, optional) -def de_camel_case(name): - new_name = '' - for ch in name: - if ch.isupper() and new_name: - new_name += '_' - if ch == '-': - new_name += '_' - else: - new_name += ch.lower() - return new_name - def camel_case(name): new_name = '' first = True @@ -752,7 +744,43 @@ def camel_case(name): new_name += ch.lower() return new_name -def c_var(name, protect=True): +# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 +# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 +# ENUM24_Name -> ENUM24_NAME +def camel_to_upper(value): + c_fun_str = c_name(value, False) + if value.isupper(): + return c_fun_str + + new_name = '' + l = len(c_fun_str) + for i in range(l): + c = c_fun_str[i] + # When c is upper and no "_" appears before, do more checks + if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": + # Case 1: next string is lower + # Case 2: previous string is digit + if (i < (l - 1) and c_fun_str[i + 1].islower()) or \ + c_fun_str[i - 1].isdigit(): + new_name += '_' + new_name += c + return new_name.lstrip('_').upper() + +def c_enum_const(type_name, const_name): + return camel_to_upper(type_name + '_' + const_name) + +c_name_trans = string.maketrans('.-', '__') + +# Map @name to a valid C identifier. +# If @protect, avoid returning certain ticklish identifiers (like +# C keywords) by prepending "q_". +# +# Used for converting 'name' from a 'name':'type' qapi definition +# into a generated struct member, as well as converting type names +# into substrings of a generated C function name. +# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo' +# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int' +def c_name(name, protect=True): # ANSI X3J11/88-090, 3.1.1 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extern', 'float', @@ -781,18 +809,27 @@ def c_var(name, protect=True): polluted_words = set(['unix', 'errno']) if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words): return "q_" + name - return name.replace('-', '_').lstrip("*") - -def c_fun(name, protect=True): - return c_var(name, protect).replace('.', '_') + return name.translate(c_name_trans) +# Map type @name to the C typedef name for the list form. +# +# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList' def c_list_type(name): - return '%sList' % name + return type_name(name) + 'List' -def type_name(name): - if type(name) == list: - return c_list_type(name[0]) - return name +# Map type @value to the C typedef form. +# +# Used for converting 'type' from a 'member':'type' qapi definition +# into the alphanumeric portion of the type for a generated C parameter, +# as well as generated C function names. See c_type() for the rest of +# the conversion such as adding '*' on pointer types. +# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c' +def type_name(value): + if type(value) == list: + return c_list_type(value[0]) + if value in builtin_types.keys(): + return value + return c_name(value) def add_name(name, info, meta, implicit = False): global all_names @@ -849,42 +886,48 @@ def is_enum(name): return find_enum(name) != None eatspace = '\033EATSPACE.' +pointer_suffix = ' *' + eatspace +# Map type @name to its C type expression. +# If @is_param, const-qualify the string type. +# +# This function is used for computing the full C type of 'member':'name'. # A special suffix is added in c_type() for pointer types, and it's # stripped in mcgen(). So please notice this when you check the return # value of c_type() outside mcgen(). -def c_type(name, is_param=False): - if name == 'str': +def c_type(value, is_param=False): + if value == 'str': if is_param: - return 'const char *' + eatspace - return 'char *' + eatspace + return 'const char' + pointer_suffix + return 'char' + pointer_suffix - elif name == 'int': + elif value == 'int': return 'int64_t' - elif (name == 'int8' or name == 'int16' or name == 'int32' or - name == 'int64' or name == 'uint8' or name == 'uint16' or - name == 'uint32' or name == 'uint64'): - return name + '_t' - elif name == 'size': + elif (value == 'int8' or value == 'int16' or value == 'int32' or + value == 'int64' or value == 'uint8' or value == 'uint16' or + value == 'uint32' or value == 'uint64'): + return value + '_t' + elif value == 'size': return 'uint64_t' - elif name == 'bool': + elif value == 'bool': return 'bool' - elif name == 'number': + elif value == 'number': return 'double' - elif type(name) == list: - return '%s *%s' % (c_list_type(name[0]), eatspace) - elif is_enum(name): - return name - elif name == None or len(name) == 0: + elif type(value) == list: + return c_list_type(value[0]) + pointer_suffix + elif is_enum(value): + return c_name(value) + elif value == None: return 'void' - elif name in events: - return '%sEvent *%s' % (camel_case(name), eatspace) + elif value in events: + return camel_case(value) + 'Event' + pointer_suffix else: - return '%s *%s' % (name, eatspace) + # complex type name + assert isinstance(value, str) and value != "" + return c_name(value) + pointer_suffix -def is_c_ptr(name): - suffix = "*" + eatspace - return c_type(name).endswith(suffix) +def is_c_ptr(value): + return c_type(value).endswith(pointer_suffix) def genindent(count): ret = "" @@ -938,29 +981,88 @@ def guardend(name): ''', name=guardname(name)) -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 -# ENUM24_Name -> ENUM24_NAME -def _generate_enum_string(value): - c_fun_str = c_fun(value, False) - if value.isupper(): - return c_fun_str +def parse_command_line(extra_options = "", extra_long_options = []): - new_name = '' - l = len(c_fun_str) - for i in range(l): - c = c_fun_str[i] - # When c is upper and no "_" appears before, do more checks - if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": - # Case 1: next string is lower - # Case 2: previous string is digit - if (i < (l - 1) and c_fun_str[i + 1].islower()) or \ - c_fun_str[i - 1].isdigit(): - new_name += '_' - new_name += c - return new_name.lstrip('_').upper() + try: + opts, args = getopt.gnu_getopt(sys.argv[1:], + "chp:o:" + extra_options, + ["source", "header", "prefix=", + "output-dir="] + extra_long_options) + except getopt.GetoptError, err: + print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err)) + sys.exit(1) + + output_dir = "" + prefix = "" + do_c = False + do_h = False + extra_opts = [] + + for oa in opts: + o, a = oa + if o in ("-p", "--prefix"): + prefix = a + elif o in ("-o", "--output-dir"): + output_dir = a + "/" + elif o in ("-c", "--source"): + do_c = True + elif o in ("-h", "--header"): + do_h = True + else: + extra_opts.append(oa) + + if not do_c and not do_h: + do_c = True + do_h = True + + if len(args) != 1: + print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0] + sys.exit(1) + input_file = args[0] + + return (input_file, output_dir, do_c, do_h, prefix, extra_opts) + +def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, + c_comment, h_comment): + 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 + + def maybe_open(really, name, opt): + if really: + return open(name, opt) + else: + import StringIO + return StringIO.StringIO() + + fdef = maybe_open(do_c, c_file, 'w') + fdecl = maybe_open(do_h, h_file, 'w') + + fdef.write(mcgen(''' +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +%(comment)s +''', + comment = c_comment)) + + fdecl.write(mcgen(''' +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +%(comment)s +#ifndef %(guard)s +#define %(guard)s + +''', + comment = h_comment, guard = guardname(h_file))) + + return (fdef, fdecl) -def generate_enum_full_value(enum_name, enum_value): - abbrev_string = _generate_enum_string(enum_name) - value_string = _generate_enum_string(enum_value) - return "%s_%s" % (abbrev_string, value_string) +def close_output(fdef, fdecl): + fdecl.write(''' +#endif +''') + fdecl.close() + fdef.close() diff --git a/tests/Makefile b/tests/Makefile index 666aee2..729b969 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -301,24 +301,24 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ libqemuutil.a libqemustub.a tests/test-qapi-types.c tests/test-qapi-types.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qapi-event.c tests/test-qapi-event.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 8193dc1..c7eaa86 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -107,3 +107,23 @@ 'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } } { 'event': 'EVENT_D', 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } + +# test that we correctly compile downstream extensions +{ 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } +{ 'struct': '__org.qemu_x-Base', + 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } +{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', + 'data': { '__org.qemu_x-member2': 'str' } } +{ 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } +{ 'struct': '__org.qemu_x-Struct2', + 'data': { 'array': ['__org.qemu_x-Union1'] } } +{ 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base', + 'discriminator': '__org.qemu_x-member1', + 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } +{ 'alternate': '__org.qemu_x-Alt', + 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } +{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' } +{ 'command': '__org.qemu_x-command', + 'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'], + 'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' }, + 'returns': '__org.qemu_x-Union1' } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 93c4963..cf0ccc4 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -22,10 +22,22 @@ OrderedDict([('event', 'EVENT_A')]), OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]), OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), - OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])] + OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]), + OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]), + OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), + OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]), + OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]), + OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))]), + OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]), + OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, + {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, - {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}] + {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}, + {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}, + {'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}] [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), @@ -37,4 +49,7 @@ OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), - OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])] + OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), + OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))])] diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index ad2e403..9918f23 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -51,6 +51,21 @@ int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp) return a + (has_b ? b : 0); } +__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, + __org_qemu_x_StructList *b, + __org_qemu_x_Union2 *c, + __org_qemu_x_Alt *d, + Error **errp) +{ + __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1); + + ret->kind = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH; + ret->__org_qemu_x_branch = strdup("blah1"); + + return ret; +} + + /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { |