qemu/scripts/qapi-event.py
Markus Armbruster 26df4e7fab qapi: Turn generators into modules
The next commit will introduce a common driver program for all
generators.  The generators need to be modules for that.  qapi2texi.py
already is.  Make the other generators follow suit.

The changes are actually trivial.  Obvious in the diffs once you view
them with whitespace changes ignored.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180211093607.27351-8-armbru@redhat.com>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
[eblake: minor tweak to keep 'blurb' one line]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-02 13:14:09 -06:00

215 lines
5.2 KiB
Python

"""
QAPI event generator
Copyright (c) 2014 Wenchao Xia
Copyright (c) 2015-2018 Red Hat Inc.
Authors:
Wenchao Xia <wenchaoqemu@gmail.com>
Markus Armbruster <armbru@redhat.com>
This work is licensed under the terms of the GNU GPL, version 2.
See the COPYING file in the top-level directory.
"""
from qapi import *
def build_event_send_proto(name, arg_type, boxed):
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
'param': build_params(arg_type, boxed, 'Error **errp')}
def gen_event_send_decl(name, arg_type, boxed):
return mcgen('''
%(proto)s;
''',
proto=build_event_send_proto(name, arg_type, boxed))
# Declare and initialize an object 'qapi' using parameters from build_params()
def gen_param_var(typ):
assert not typ.variants
ret = mcgen('''
%(c_name)s param = {
''',
c_name=typ.c_name())
sep = ' '
for memb in typ.members:
ret += sep
sep = ', '
if memb.optional:
ret += 'has_' + c_name(memb.name) + sep
if memb.type.name == 'str':
# Cast away const added in build_params()
ret += '(char *)'
ret += c_name(memb.name)
ret += mcgen('''
};
''')
if not typ.is_implicit():
ret += mcgen('''
%(c_name)s *arg = &param;
''',
c_name=typ.c_name())
return ret
def gen_event_send(name, arg_type, boxed, event_enum_name):
# FIXME: Our declaration of local variables (and of 'errp' in the
# parameter list) can collide with exploded members of the event's
# data type passed in as parameters. If this collision ever hits in
# practice, we can rename our local variables with a leading _ prefix,
# or split the code into a wrapper function that creates a boxed
# 'param' object then calls another to do the real work.
ret = mcgen('''
%(proto)s
{
QDict *qmp;
Error *err = NULL;
QMPEventFuncEmit emit;
''',
proto=build_event_send_proto(name, arg_type, boxed))
if arg_type and not arg_type.is_empty():
ret += mcgen('''
QObject *obj;
Visitor *v;
''')
if not boxed:
ret += gen_param_var(arg_type)
else:
assert not boxed
ret += mcgen('''
emit = qmp_event_get_func_emit();
if (!emit) {
return;
}
qmp = qmp_event_build_dict("%(name)s");
''',
name=name)
if arg_type and not arg_type.is_empty():
ret += mcgen('''
v = qobject_output_visitor_new(&obj);
''')
if not arg_type.is_implicit():
ret += mcgen('''
visit_type_%(c_name)s(v, "%(name)s", &arg, &err);
''',
name=name, c_name=arg_type.c_name())
else:
ret += mcgen('''
visit_start_struct(v, "%(name)s", NULL, 0, &err);
if (err) {
goto out;
}
visit_type_%(c_name)s_members(v, &param, &err);
if (!err) {
visit_check_struct(v, &err);
}
visit_end_struct(v, NULL);
''',
name=name, c_name=arg_type.c_name())
ret += mcgen('''
if (err) {
goto out;
}
visit_complete(v, &obj);
qdict_put_obj(qmp, "data", obj);
''')
ret += mcgen('''
emit(%(c_enum)s, qmp, &err);
''',
c_enum=c_enum_const(event_enum_name, name))
if arg_type and not arg_type.is_empty():
ret += mcgen('''
out:
visit_free(v);
''')
ret += mcgen('''
error_propagate(errp, err);
QDECREF(qmp);
}
''')
return ret
class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
def __init__(self, prefix):
self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
self.decl = None
self.defn = None
self._event_names = None
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._event_names = []
def visit_end(self):
self.decl += gen_enum(self._enum_name, self._event_names)
self.defn += gen_enum_lookup(self._enum_name, self._event_names)
self._event_names = None
def visit_event(self, name, info, arg_type, boxed):
self.decl += gen_event_send_decl(name, arg_type, boxed)
self.defn += gen_event_send(name, arg_type, boxed, self._enum_name)
self._event_names.append(name)
def main(argv):
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
blurb = ' * Schema-defined QAPI/QMP events'
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
#include "%(prefix)sqapi-visit.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp-event.h"
''',
prefix=prefix))
genh.add(mcgen('''
#include "qapi/util.h"
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix))
schema = QAPISchema(input_file)
vis = QAPISchemaGenEventVisitor(prefix)
schema.visit(vis)
genc.add(vis.defn)
genh.add(vis.decl)
if do_c:
genc.write(output_dir, prefix + 'qapi-event.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-event.h')
if __name__ == '__main__':
main(sys.argv)