2 QAPI command marshaller generator
4 Copyright IBM, Corp. 2011
5 Copyright (C) 2014-2018 Red Hat, Inc.
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
12 This work is licensed under the terms of the GNU GPL, version 2.
13 See the COPYING file in the top-level directory.
16 from qapi
.common
import *
17 from qapi
.gen
import QAPIGenCCode
, QAPISchemaModularCVisitor
, ifcontext
20 def gen_command_decl(name
, arg_type
, boxed
, ret_type
):
22 %(c_type)s qmp_%(c_name)s(%(params)s);
24 c_type
=(ret_type
and ret_type
.c_type()) or 'void',
26 params
=build_params(arg_type
, boxed
, 'Error **errp'))
29 def gen_call(name
, arg_type
, boxed
, ret_type
):
37 assert not arg_type
.variants
38 for memb
in arg_type
.members
:
40 argstr
+= 'arg.has_%s, ' % c_name(memb
.name
)
41 argstr
+= 'arg.%s, ' % c_name(memb
.name
)
49 %(lhs)sqmp_%(c_name)s(%(args)s&err);
50 error_propagate(errp, err);
52 c_name
=c_name(name
), args
=argstr
, lhs
=lhs
)
59 qmp_marshal_output_%(c_name)s(retval, ret, errp);
61 c_name
=ret_type
.c_name())
65 def gen_marshal_output(ret_type
):
68 static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
72 v = qobject_output_visitor_new(ret_out);
73 if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
74 visit_complete(v, ret_out);
77 v = qapi_dealloc_visitor_new();
78 visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
82 c_type
=ret_type
.c_type(), c_name
=ret_type
.c_name())
85 def build_marshal_proto(name
):
86 return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
90 def gen_marshal_decl(name
):
94 proto
=build_marshal_proto(name
))
97 def gen_marshal(name
, arg_type
, boxed
, ret_type
):
98 have_args
= boxed
or (arg_type
and not arg_type
.is_empty())
108 proto
=build_marshal_proto(name
))
114 c_type
=ret_type
.c_type())
118 %(c_name)s arg = {0};
120 c_name
=arg_type
.c_name())
124 v = qobject_input_visitor_new(QOBJECT(args));
125 if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
132 if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) {
133 ok = visit_check_struct(v, errp);
136 c_arg_type
=arg_type
.c_name())
139 ok = visit_check_struct(v, errp);
143 visit_end_struct(v, NULL);
149 ret
+= gen_call(name
, arg_type
, boxed
, ret_type
)
158 v = qapi_dealloc_visitor_new();
159 visit_start_struct(v, NULL, NULL, 0, NULL);
164 visit_type_%(c_arg_type)s_members(v, &arg, NULL);
166 c_arg_type
=arg_type
.c_name())
169 visit_end_struct(v, NULL);
179 def gen_register_command(name
, success_response
, allow_oob
, allow_preconfig
):
182 if not success_response
:
183 options
+= ['QCO_NO_SUCCESS_RESP']
185 options
+= ['QCO_ALLOW_OOB']
187 options
+= ['QCO_ALLOW_PRECONFIG']
190 options
= ['QCO_NO_OPTIONS']
192 options
= " | ".join(options
)
195 qmp_register_command(cmds, "%(name)s",
196 qmp_marshal_%(c_name)s, %(opts)s);
198 name
=name
, c_name
=c_name(name
),
203 def gen_registry(registry
, prefix
):
206 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
211 c_prefix
=c_name(prefix
, protect
=False))
219 class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor
):
221 def __init__(self
, prefix
):
223 prefix
, 'qapi-commands',
224 ' * Schema-defined QAPI/QMP commands', None, __doc__
)
225 self
._regy
= QAPIGenCCode(None)
226 self
._visited
_ret
_types
= {}
228 def _begin_user_module(self
, name
):
229 self
._visited
_ret
_types
[self
._genc
] = set()
230 commands
= self
._module
_basename
('qapi-commands', name
)
231 types
= self
._module
_basename
('qapi-types', name
)
232 visit
= self
._module
_basename
('qapi-visit', name
)
233 self
._genc
.add(mcgen('''
234 #include "qemu/osdep.h"
235 #include "qapi/visitor.h"
236 #include "qapi/qmp/qdict.h"
237 #include "qapi/qobject-output-visitor.h"
238 #include "qapi/qobject-input-visitor.h"
239 #include "qapi/dealloc-visitor.h"
240 #include "qapi/error.h"
241 #include "%(visit)s.h"
242 #include "%(commands)s.h"
245 commands
=commands
, visit
=visit
))
246 self
._genh
.add(mcgen('''
247 #include "%(types)s.h"
253 self
._add
_system
_module
('init', ' * QAPI Commands initialization')
254 self
._genh
.add(mcgen('''
255 #include "qapi/qmp/dispatch.h"
257 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
259 c_prefix
=c_name(self
._prefix
, protect
=False)))
260 self
._genc
.preamble_add(mcgen('''
261 #include "qemu/osdep.h"
262 #include "%(prefix)sqapi-commands.h"
263 #include "%(prefix)sqapi-init-commands.h"
265 prefix
=self
._prefix
))
266 self
._genc
.add(gen_registry(self
._regy
.get_content(), self
._prefix
))
268 def visit_command(self
, name
, info
, ifcond
, features
,
269 arg_type
, ret_type
, gen
, success_response
, boxed
,
270 allow_oob
, allow_preconfig
):
273 # FIXME: If T is a user-defined type, the user is responsible
274 # for making this work, i.e. to make T's condition the
275 # conjunction of the T-returning commands' conditions. If T
276 # is a built-in type, this isn't possible: the
277 # qmp_marshal_output_T() will be generated unconditionally.
278 if ret_type
and ret_type
not in self
._visited
_ret
_types
[self
._genc
]:
279 self
._visited
_ret
_types
[self
._genc
].add(ret_type
)
280 with
ifcontext(ret_type
.ifcond
,
281 self
._genh
, self
._genc
, self
._regy
):
282 self
._genc
.add(gen_marshal_output(ret_type
))
283 with
ifcontext(ifcond
, self
._genh
, self
._genc
, self
._regy
):
284 self
._genh
.add(gen_command_decl(name
, arg_type
, boxed
, ret_type
))
285 self
._genh
.add(gen_marshal_decl(name
))
286 self
._genc
.add(gen_marshal(name
, arg_type
, boxed
, ret_type
))
287 self
._regy
.add(gen_register_command(name
, success_response
,
288 allow_oob
, allow_preconfig
))
291 def gen_commands(schema
, output_dir
, prefix
):
292 vis
= QAPISchemaGenCommandVisitor(prefix
)
294 vis
.write(output_dir
)