]> Git Repo - qemu.git/blob - scripts/qapi-commands.py
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20160513' into staging
[qemu.git] / scripts / qapi-commands.py
1 #
2 # QAPI command marshaller generator
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (C) 2014-2016 Red Hat, Inc.
6 #
7 # Authors:
8 #  Anthony Liguori <[email protected]>
9 #  Michael Roth    <[email protected]>
10 #  Markus Armbruster <[email protected]>
11 #
12 # This work is licensed under the terms of the GNU GPL, version 2.
13 # See the COPYING file in the top-level directory.
14
15 from qapi import *
16 import re
17
18
19 def gen_command_decl(name, arg_type, ret_type):
20     return mcgen('''
21 %(c_type)s qmp_%(c_name)s(%(params)s);
22 ''',
23                  c_type=(ret_type and ret_type.c_type()) or 'void',
24                  c_name=c_name(name),
25                  params=gen_params(arg_type, 'Error **errp'))
26
27
28 def gen_call(name, arg_type, ret_type):
29     ret = ''
30
31     argstr = ''
32     if arg_type:
33         assert not arg_type.variants
34         for memb in arg_type.members:
35             if memb.optional:
36                 argstr += 'arg.has_%s, ' % c_name(memb.name)
37             argstr += 'arg.%s, ' % c_name(memb.name)
38
39     lhs = ''
40     if ret_type:
41         lhs = 'retval = '
42
43     ret = mcgen('''
44
45     %(lhs)sqmp_%(c_name)s(%(args)s&err);
46 ''',
47                 c_name=c_name(name), args=argstr, lhs=lhs)
48     if ret_type:
49         ret += gen_err_check()
50         ret += mcgen('''
51
52     qmp_marshal_output_%(c_name)s(retval, ret, &err);
53 ''',
54                      c_name=ret_type.c_name())
55     return ret
56
57
58 def gen_marshal_output(ret_type):
59     return mcgen('''
60
61 static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
62 {
63     Error *err = NULL;
64     QmpOutputVisitor *qov = qmp_output_visitor_new();
65     QapiDeallocVisitor *qdv;
66     Visitor *v;
67
68     v = qmp_output_get_visitor(qov);
69     visit_type_%(c_name)s(v, "unused", &ret_in, &err);
70     if (err) {
71         goto out;
72     }
73     *ret_out = qmp_output_get_qobject(qov);
74
75 out:
76     error_propagate(errp, err);
77     qmp_output_visitor_cleanup(qov);
78     qdv = qapi_dealloc_visitor_new();
79     v = qapi_dealloc_get_visitor(qdv);
80     visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
81     qapi_dealloc_visitor_cleanup(qdv);
82 }
83 ''',
84                  c_type=ret_type.c_type(), c_name=ret_type.c_name())
85
86
87 def gen_marshal_proto(name):
88     ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
89     if not middle_mode:
90         ret = 'static ' + ret
91     return ret
92
93
94 def gen_marshal_decl(name):
95     return mcgen('''
96 %(proto)s;
97 ''',
98                  proto=gen_marshal_proto(name))
99
100
101 def gen_marshal(name, arg_type, ret_type):
102     ret = mcgen('''
103
104 %(proto)s
105 {
106     Error *err = NULL;
107 ''',
108                 proto=gen_marshal_proto(name))
109
110     if ret_type:
111         ret += mcgen('''
112     %(c_type)s retval;
113 ''',
114                      c_type=ret_type.c_type())
115
116     if arg_type and arg_type.members:
117         ret += mcgen('''
118     QmpInputVisitor *qiv = qmp_input_visitor_new(QOBJECT(args), true);
119     QapiDeallocVisitor *qdv;
120     Visitor *v;
121     %(c_name)s arg = {0};
122
123     v = qmp_input_get_visitor(qiv);
124     visit_start_struct(v, NULL, NULL, 0, &err);
125     if (err) {
126         goto out;
127     }
128     visit_type_%(c_name)s_members(v, &arg, &err);
129     if (!err) {
130         visit_check_struct(v, &err);
131     }
132     visit_end_struct(v);
133     if (err) {
134         goto out;
135     }
136 ''',
137                      c_name=arg_type.c_name())
138
139     else:
140         ret += mcgen('''
141
142     (void)args;
143 ''')
144
145     ret += gen_call(name, arg_type, ret_type)
146
147     # 'goto out' produced above for arg_type, and by gen_call() for ret_type
148     if (arg_type and arg_type.members) or ret_type:
149         ret += mcgen('''
150
151 out:
152 ''')
153     ret += mcgen('''
154     error_propagate(errp, err);
155 ''')
156     if arg_type and arg_type.members:
157         ret += mcgen('''
158     qmp_input_visitor_cleanup(qiv);
159     qdv = qapi_dealloc_visitor_new();
160     v = qapi_dealloc_get_visitor(qdv);
161     visit_start_struct(v, NULL, NULL, 0, NULL);
162     visit_type_%(c_name)s_members(v, &arg, NULL);
163     visit_end_struct(v);
164     qapi_dealloc_visitor_cleanup(qdv);
165 ''',
166                      c_name=arg_type.c_name())
167
168     ret += mcgen('''
169 }
170 ''')
171     return ret
172
173
174 def gen_register_command(name, success_response):
175     options = 'QCO_NO_OPTIONS'
176     if not success_response:
177         options = 'QCO_NO_SUCCESS_RESP'
178
179     ret = mcgen('''
180     qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
181 ''',
182                 name=name, c_name=c_name(name),
183                 opts=options)
184     return ret
185
186
187 def gen_registry(registry):
188     ret = mcgen('''
189
190 static void qmp_init_marshal(void)
191 {
192 ''')
193     ret += registry
194     ret += mcgen('''
195 }
196
197 qapi_init(qmp_init_marshal);
198 ''')
199     return ret
200
201
202 class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
203     def __init__(self):
204         self.decl = None
205         self.defn = None
206         self._regy = None
207         self._visited_ret_types = None
208
209     def visit_begin(self, schema):
210         self.decl = ''
211         self.defn = ''
212         self._regy = ''
213         self._visited_ret_types = set()
214
215     def visit_end(self):
216         if not middle_mode:
217             self.defn += gen_registry(self._regy)
218         self._regy = None
219         self._visited_ret_types = None
220
221     def visit_command(self, name, info, arg_type, ret_type,
222                       gen, success_response):
223         if not gen:
224             return
225         self.decl += gen_command_decl(name, arg_type, ret_type)
226         if ret_type and ret_type not in self._visited_ret_types:
227             self._visited_ret_types.add(ret_type)
228             self.defn += gen_marshal_output(ret_type)
229         if middle_mode:
230             self.decl += gen_marshal_decl(name)
231         self.defn += gen_marshal(name, arg_type, ret_type)
232         if not middle_mode:
233             self._regy += gen_register_command(name, success_response)
234
235
236 middle_mode = False
237
238 (input_file, output_dir, do_c, do_h, prefix, opts) = \
239     parse_command_line("m", ["middle"])
240
241 for o, a in opts:
242     if o in ("-m", "--middle"):
243         middle_mode = True
244
245 c_comment = '''
246 /*
247  * schema-defined QMP->QAPI command dispatch
248  *
249  * Copyright IBM, Corp. 2011
250  *
251  * Authors:
252  *  Anthony Liguori   <[email protected]>
253  *
254  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
255  * See the COPYING.LIB file in the top-level directory.
256  *
257  */
258 '''
259 h_comment = '''
260 /*
261  * schema-defined QAPI function prototypes
262  *
263  * Copyright IBM, Corp. 2011
264  *
265  * Authors:
266  *  Anthony Liguori   <[email protected]>
267  *
268  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
269  * See the COPYING.LIB file in the top-level directory.
270  *
271  */
272 '''
273
274 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
275                             'qmp-marshal.c', 'qmp-commands.h',
276                             c_comment, h_comment)
277
278 fdef.write(mcgen('''
279 #include "qemu/osdep.h"
280 #include "qemu-common.h"
281 #include "qemu/module.h"
282 #include "qapi/qmp/types.h"
283 #include "qapi/qmp/dispatch.h"
284 #include "qapi/visitor.h"
285 #include "qapi/qmp-output-visitor.h"
286 #include "qapi/qmp-input-visitor.h"
287 #include "qapi/dealloc-visitor.h"
288 #include "%(prefix)sqapi-types.h"
289 #include "%(prefix)sqapi-visit.h"
290 #include "%(prefix)sqmp-commands.h"
291
292 ''',
293                  prefix=prefix))
294
295 fdecl.write(mcgen('''
296 #include "%(prefix)sqapi-types.h"
297 #include "qapi/qmp/qdict.h"
298 #include "qapi/error.h"
299
300 ''',
301                   prefix=prefix))
302
303 schema = QAPISchema(input_file)
304 gen = QAPISchemaGenCommandVisitor()
305 schema.visit(gen)
306 fdef.write(gen.defn)
307 fdecl.write(gen.decl)
308
309 close_output(fdef, fdecl)
This page took 0.041658 seconds and 4 git commands to generate.