]> git.ipfire.org Git - thirdparty/qemu.git/blame - scripts/qapi/commands.py
qapi: Move qapi-schema.json to qapi/, rename generated files
[thirdparty/qemu.git] / scripts / qapi / commands.py
CommitLineData
5ddeec83
MA
1"""
2QAPI command marshaller generator
3
4Copyright IBM, Corp. 2011
5Copyright (C) 2014-2018 Red Hat, Inc.
6
7Authors:
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
11
12This work is licensed under the terms of the GNU GPL, version 2.
13See the COPYING file in the top-level directory.
14"""
c17d9908 15
fb0bc835 16from qapi.common import *
c17d9908 17
e98859a9 18
48825ca4 19def gen_command_decl(name, arg_type, boxed, ret_type):
c17d9908 20 return mcgen('''
03b4367a 21%(c_type)s qmp_%(c_name)s(%(params)s);
c17d9908 22''',
e98859a9
MA
23 c_type=(ret_type and ret_type.c_type()) or 'void',
24 c_name=c_name(name),
086ee7a6 25 params=build_params(arg_type, boxed, 'Error **errp'))
e98859a9 26
c17d9908 27
48825ca4 28def gen_call(name, arg_type, boxed, ret_type):
e98859a9
MA
29 ret = ''
30
31 argstr = ''
48825ca4 32 if boxed:
c818408e
EB
33 assert arg_type and not arg_type.is_empty()
34 argstr = '&arg, '
48825ca4 35 elif arg_type:
29f6bd15 36 assert not arg_type.variants
e98859a9 37 for memb in arg_type.members:
ee446028 38 if memb.optional:
386230a2
EB
39 argstr += 'arg.has_%s, ' % c_name(memb.name)
40 argstr += 'arg.%s, ' % c_name(memb.name)
e98859a9
MA
41
42 lhs = ''
43 if ret_type:
44 lhs = 'retval = '
45
c17d9908 46 ret = mcgen('''
f1538019 47
05372f70 48 %(lhs)sqmp_%(c_name)s(%(args)s&err);
c17d9908 49''',
e98859a9 50 c_name=c_name(name), args=argstr, lhs=lhs)
c17d9908 51 if ret_type:
e02bca28 52 ret += mcgen('''
fa274ed6
EB
53 if (err) {
54 goto out;
55 }
e02bca28 56
05372f70 57 qmp_marshal_output_%(c_name)s(retval, ret, &err);
c17d9908 58''',
56d92b00 59 c_name=ret_type.c_name())
1f9a7a1a 60 return ret
c17d9908 61
e98859a9 62
56d92b00 63def gen_marshal_output(ret_type):
f1538019 64 return mcgen('''
ee446028 65
56d92b00 66static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
c17d9908 67{
2a0f50e8 68 Error *err = NULL;
c17d9908
MR
69 Visitor *v;
70
7d5e199a 71 v = qobject_output_visitor_new(ret_out);
51e72bc1 72 visit_type_%(c_name)s(v, "unused", &ret_in, &err);
3b098d56
EB
73 if (!err) {
74 visit_complete(v, ret_out);
c17d9908 75 }
2a0f50e8 76 error_propagate(errp, err);
2c0ef9f4
EB
77 visit_free(v);
78 v = qapi_dealloc_visitor_new();
51e72bc1 79 visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
2c0ef9f4 80 visit_free(v);
c17d9908
MR
81}
82''',
56d92b00 83 c_type=ret_type.c_type(), c_name=ret_type.c_name())
c17d9908 84
e98859a9 85
086ee7a6 86def build_marshal_proto(name):
c2613949
MA
87 return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
88 % c_name(name))
776574d6 89
e98859a9 90
f1538019
MA
91def gen_marshal_decl(name):
92 return mcgen('''
93%(proto)s;
94''',
086ee7a6 95 proto=build_marshal_proto(name))
f1538019 96
776574d6 97
48825ca4 98def gen_marshal(name, arg_type, boxed, ret_type):
a0067da1
MAL
99 have_args = arg_type and not arg_type.is_empty()
100
c17d9908 101 ret = mcgen('''
ee446028 102
f1538019 103%(proto)s
c17d9908 104{
c1ff0e6c 105 Error *err = NULL;
c17d9908 106''',
086ee7a6 107 proto=build_marshal_proto(name))
c17d9908 108
c1ff0e6c
EB
109 if ret_type:
110 ret += mcgen('''
111 %(c_type)s retval;
112''',
113 c_type=ret_type.c_type())
114
a0067da1
MAL
115 if have_args:
116 visit_members = ('visit_type_%s_members(v, &arg, &err);'
117 % arg_type.c_name())
c1ff0e6c 118 ret += mcgen('''
c1ff0e6c
EB
119 Visitor *v;
120 %(c_name)s arg = {0};
121
a0067da1
MAL
122''',
123 c_name=arg_type.c_name())
124 else:
125 visit_members = ''
126 ret += mcgen('''
127 Visitor *v = NULL;
128
129 if (args) {
130''')
131 push_indent()
132
133 ret += mcgen('''
048abb7b 134 v = qobject_input_visitor_new(QOBJECT(args));
ed841535
EB
135 visit_start_struct(v, NULL, NULL, 0, &err);
136 if (err) {
137 goto out;
138 }
a0067da1 139 %(visit_members)s
15c2f669
EB
140 if (!err) {
141 visit_check_struct(v, &err);
142 }
1158bb2a 143 visit_end_struct(v, NULL);
c1ff0e6c
EB
144 if (err) {
145 goto out;
146 }
147''',
a0067da1 148 visit_members=visit_members)
c1ff0e6c 149
a0067da1
MAL
150 if not have_args:
151 pop_indent()
c1ff0e6c 152 ret += mcgen('''
a0067da1 153 }
c1ff0e6c
EB
154''')
155
48825ca4 156 ret += gen_call(name, arg_type, boxed, ret_type)
1f9a7a1a 157
a0067da1 158 ret += mcgen('''
c17d9908
MR
159
160out:
2a0f50e8 161 error_propagate(errp, err);
a0067da1 162 visit_free(v);
1f9a7a1a 163''')
a0067da1
MAL
164
165 if have_args:
166 visit_members = ('visit_type_%s_members(v, &arg, NULL);'
167 % arg_type.c_name())
168 else:
169 visit_members = ''
c1ff0e6c 170 ret += mcgen('''
a0067da1
MAL
171 if (args) {
172''')
173 push_indent()
174
175 ret += mcgen('''
2c0ef9f4 176 v = qapi_dealloc_visitor_new();
ed841535 177 visit_start_struct(v, NULL, NULL, 0, NULL);
a0067da1 178 %(visit_members)s
1158bb2a 179 visit_end_struct(v, NULL);
2c0ef9f4 180 visit_free(v);
c1ff0e6c 181''',
a0067da1
MAL
182 visit_members=visit_members)
183
184 if not have_args:
185 pop_indent()
186 ret += mcgen('''
187 }
188''')
c1ff0e6c 189
1f9a7a1a 190 ret += mcgen('''
485febc6 191}
1f9a7a1a 192''')
c17d9908
MR
193 return ret
194
e98859a9 195
ee446028 196def gen_register_command(name, success_response):
ee446028
MA
197 options = 'QCO_NO_OPTIONS'
198 if not success_response:
199 options = 'QCO_NO_SUCCESS_RESP'
d34b867d 200
ee446028 201 ret = mcgen('''
c2613949 202 qmp_register_command(cmds, "%(name)s",
1527badb 203 qmp_marshal_%(c_name)s, %(opts)s);
c17d9908 204''',
e98859a9
MA
205 name=name, c_name=c_name(name),
206 opts=options)
ee446028
MA
207 return ret
208
e98859a9 209
93b564c4 210def gen_registry(registry, prefix):
c17d9908 211 ret = mcgen('''
ee446028 212
1527badb 213void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
c17d9908 214{
1527badb
MA
215 QTAILQ_INIT(cmds);
216
217''',
218 c_prefix=c_name(prefix, protect=False))
1f9a7a1a
MA
219 ret += registry
220 ret += mcgen('''
c17d9908 221}
1f9a7a1a 222''')
c17d9908
MR
223 return ret
224
ee446028 225
252dc310 226class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
71b3f045 227
93b564c4 228 def __init__(self, prefix):
252dc310
MA
229 QAPISchemaModularCVisitor.__init__(
230 self, prefix, 'qapi-commands',
71b3f045 231 ' * Schema-defined QAPI/QMP commands', __doc__)
ee446028 232 self._regy = ''
252dc310
MA
233 self._visited_ret_types = {}
234
252dc310
MA
235 def _begin_module(self, name):
236 self._visited_ret_types[self._genc] = set()
9af23989
MA
237 commands = self._module_basename('qapi-commands', name)
238 types = self._module_basename('qapi-types', name)
239 visit = self._module_basename('qapi-visit', name)
71b3f045 240 self._genc.add(mcgen('''
9167ebd9 241#include "qemu/osdep.h"
4180978c
MA
242#include "qemu-common.h"
243#include "qemu/module.h"
4180978c 244#include "qapi/visitor.h"
452fcdbc 245#include "qapi/qmp/qdict.h"
b3db211f
DB
246#include "qapi/qobject-output-visitor.h"
247#include "qapi/qobject-input-visitor.h"
4180978c 248#include "qapi/dealloc-visitor.h"
e688df6b 249#include "qapi/error.h"
9af23989
MA
250#include "%(visit)s.h"
251#include "%(commands)s.h"
4180978c
MA
252
253''',
9af23989 254 commands=commands, visit=visit))
71b3f045 255 self._genh.add(mcgen('''
9af23989 256#include "%(types)s.h"
1527badb 257#include "qapi/qmp/dispatch.h"
4180978c
MA
258
259''',
9af23989 260 types=types))
71b3f045
MA
261
262 def visit_end(self):
252dc310
MA
263 (genc, genh) = self._module[self._main_module]
264 genh.add(mcgen('''
265void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
266''',
267 c_prefix=c_name(self._prefix, protect=False)))
268 genc.add(gen_registry(self._regy, self._prefix))
71b3f045
MA
269
270 def visit_command(self, name, info, arg_type, ret_type,
271 gen, success_response, boxed):
272 if not gen:
273 return
274 self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
252dc310
MA
275 if ret_type and ret_type not in self._visited_ret_types[self._genc]:
276 self._visited_ret_types[self._genc].add(ret_type)
71b3f045
MA
277 self._genc.add(gen_marshal_output(ret_type))
278 self._genh.add(gen_marshal_decl(name))
279 self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
280 self._regy += gen_register_command(name, success_response)
281
26df4e7f 282
71b3f045 283def gen_commands(schema, output_dir, prefix):
26df4e7f
MA
284 vis = QAPISchemaGenCommandVisitor(prefix)
285 schema.visit(vis)
71b3f045 286 vis.write(output_dir)