]> Git Repo - qemu.git/blob - scripts/qapi-commands.py
qapi: Clean up after recent conversions to QAPISchemaVisitor
[qemu.git] / scripts / qapi-commands.py
1 #
2 # QAPI command marshaller generator
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (C) 2014-2015 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     argstr = ''
21     if arg_type:
22         for memb in arg_type.members:
23             if memb.optional:
24                 argstr += 'bool has_%s, ' % c_name(memb.name)
25             argstr += '%s %s, ' % (memb.type.c_type(is_param=True),
26                                    c_name(memb.name))
27     return mcgen('''
28 %(c_type)s qmp_%(c_name)s(%(args)sError **errp);
29 ''',
30                  c_type=(ret_type and ret_type.c_type()) or 'void',
31                  c_name=c_name(name),
32                  args=argstr)
33
34
35 def gen_err_check(err):
36     if not err:
37         return ''
38     return mcgen('''
39 if (%(err)s) {
40     goto out;
41 }
42 ''',
43                  err=err)
44
45
46 def gen_call(name, arg_type, ret_type):
47     ret = ''
48
49     argstr = ''
50     if arg_type:
51         for memb in arg_type.members:
52             if memb.optional:
53                 argstr += 'has_%s, ' % c_name(memb.name)
54             argstr += '%s, ' % c_name(memb.name)
55
56     lhs = ''
57     if ret_type:
58         lhs = 'retval = '
59
60     push_indent()
61     ret = mcgen('''
62 %(lhs)sqmp_%(c_name)s(%(args)s&local_err);
63 ''',
64                 c_name=c_name(name), args=argstr, lhs=lhs)
65     if ret_type:
66         ret += gen_err_check('local_err')
67         ret += mcgen('''
68
69 qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
70 ''',
71                      c_name=c_name(name))
72     pop_indent()
73     return ret
74
75
76 def gen_visitor_input_containers_decl(arg_type):
77     ret = ''
78
79     push_indent()
80     if arg_type:
81         ret += mcgen('''
82 QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
83 QapiDeallocVisitor *md;
84 Visitor *v;
85 ''')
86     pop_indent()
87
88     return ret
89
90
91 def gen_visitor_input_vars_decl(arg_type):
92     ret = ''
93     push_indent()
94
95     if arg_type:
96         for memb in arg_type.members:
97             if memb.optional:
98                 ret += mcgen('''
99 bool has_%(c_name)s = false;
100 ''',
101                              c_name=c_name(memb.name))
102             ret += mcgen('''
103 %(c_type)s %(c_name)s = %(c_null)s;
104 ''',
105                          c_name=c_name(memb.name),
106                          c_type=memb.type.c_type(),
107                          c_null=memb.type.c_null())
108
109     pop_indent()
110     return ret
111
112
113 def gen_visitor_input_block(arg_type, dealloc=False):
114     ret = ''
115     errparg = '&local_err'
116     errarg = 'local_err'
117
118     if not arg_type:
119         return ret
120
121     push_indent()
122
123     if dealloc:
124         errparg = 'NULL'
125         errarg = None
126         ret += mcgen('''
127 qmp_input_visitor_cleanup(mi);
128 md = qapi_dealloc_visitor_new();
129 v = qapi_dealloc_get_visitor(md);
130 ''')
131     else:
132         ret += mcgen('''
133 v = qmp_input_get_visitor(mi);
134 ''')
135
136     for memb in arg_type.members:
137         if memb.optional:
138             ret += mcgen('''
139 visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
140 ''',
141                          c_name=c_name(memb.name), name=memb.name,
142                          errp=errparg)
143             ret += gen_err_check(errarg)
144             ret += mcgen('''
145 if (has_%(c_name)s) {
146 ''',
147                          c_name=c_name(memb.name))
148             push_indent()
149         ret += mcgen('''
150 visit_type_%(c_type)s(v, &%(c_name)s, "%(name)s", %(errp)s);
151 ''',
152                      c_name=c_name(memb.name), name=memb.name,
153                      c_type=memb.type.c_name(), errp=errparg)
154         ret += gen_err_check(errarg)
155         if memb.optional:
156             pop_indent()
157             ret += mcgen('''
158 }
159 ''')
160
161     if dealloc:
162         ret += mcgen('''
163 qapi_dealloc_visitor_cleanup(md);
164 ''')
165     pop_indent()
166     return ret
167
168
169 def gen_marshal_output(name, ret_type):
170     if not ret_type:
171         return ''
172
173     ret = mcgen('''
174
175 static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
176 {
177     Error *local_err = NULL;
178     QmpOutputVisitor *mo = qmp_output_visitor_new();
179     QapiDeallocVisitor *md;
180     Visitor *v;
181
182     v = qmp_output_get_visitor(mo);
183     visit_type_%(c_name)s(v, &ret_in, "unused", &local_err);
184     if (local_err) {
185         goto out;
186     }
187     *ret_out = qmp_output_get_qobject(mo);
188
189 out:
190     error_propagate(errp, local_err);
191     qmp_output_visitor_cleanup(mo);
192     md = qapi_dealloc_visitor_new();
193     v = qapi_dealloc_get_visitor(md);
194     visit_type_%(c_name)s(v, &ret_in, "unused", NULL);
195     qapi_dealloc_visitor_cleanup(md);
196 }
197 ''',
198                 c_type=ret_type.c_type(), c_cmd_name=c_name(name),
199                 c_name=ret_type.c_name())
200
201     return ret
202
203
204 def gen_marshal_input_decl(name):
205     ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
206     if not middle_mode:
207         ret = 'static ' + ret
208     return ret
209
210
211 def gen_marshal_input(name, arg_type, ret_type):
212     hdr = gen_marshal_input_decl(name)
213
214     ret = mcgen('''
215
216 %(header)s
217 {
218     Error *local_err = NULL;
219 ''',
220                 header=hdr)
221
222     if ret_type:
223         ret += mcgen('''
224     %(c_type)s retval;
225 ''',
226                      c_type=ret_type.c_type())
227
228     if arg_type:
229         ret += gen_visitor_input_containers_decl(arg_type)
230         ret += gen_visitor_input_vars_decl(arg_type) + '\n'
231         ret += gen_visitor_input_block(arg_type) + '\n'
232     else:
233         ret += mcgen('''
234
235     (void)args;
236
237 ''')
238
239     ret += gen_call(name, arg_type, ret_type)
240
241     if re.search('^ *goto out;', ret, re.MULTILINE):
242         ret += mcgen('''
243
244 out:
245 ''')
246     ret += mcgen('''
247     error_propagate(errp, local_err);
248 ''')
249     ret += gen_visitor_input_block(arg_type, dealloc=True)
250     ret += mcgen('''
251 }
252 ''')
253     return ret
254
255
256 def gen_register_command(name, success_response):
257     push_indent()
258     options = 'QCO_NO_OPTIONS'
259     if not success_response:
260         options = 'QCO_NO_SUCCESS_RESP'
261
262     ret = mcgen('''
263 qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
264 ''',
265                 name=name, c_name=c_name(name),
266                 opts=options)
267     pop_indent()
268     return ret
269
270
271 def gen_registry(registry):
272     ret = mcgen('''
273
274 static void qmp_init_marshal(void)
275 {
276 ''')
277     ret += registry
278     ret += mcgen('''
279 }
280
281 qapi_init(qmp_init_marshal);
282 ''')
283     return ret
284
285
286 class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
287     def __init__(self):
288         self.decl = None
289         self.defn = None
290         self._regy = None
291
292     def visit_begin(self, schema):
293         self.decl = ''
294         self.defn = ''
295         self._regy = ''
296
297     def visit_end(self):
298         if not middle_mode:
299             self.defn += gen_registry(self._regy)
300         self._regy = None
301
302     def visit_command(self, name, info, arg_type, ret_type,
303                       gen, success_response):
304         if not gen:
305             return
306         self.decl += gen_command_decl(name, arg_type, ret_type)
307         if ret_type:
308             self.defn += gen_marshal_output(name, ret_type)
309         if middle_mode:
310             self.decl += gen_marshal_input_decl(name) + ';\n'
311         self.defn += gen_marshal_input(name, arg_type, ret_type)
312         if not middle_mode:
313             self._regy += gen_register_command(name, success_response)
314
315
316 middle_mode = False
317
318 (input_file, output_dir, do_c, do_h, prefix, opts) = \
319     parse_command_line("m", ["middle"])
320
321 for o, a in opts:
322     if o in ("-m", "--middle"):
323         middle_mode = True
324
325 c_comment = '''
326 /*
327  * schema-defined QMP->QAPI command dispatch
328  *
329  * Copyright IBM, Corp. 2011
330  *
331  * Authors:
332  *  Anthony Liguori   <[email protected]>
333  *
334  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
335  * See the COPYING.LIB file in the top-level directory.
336  *
337  */
338 '''
339 h_comment = '''
340 /*
341  * schema-defined QAPI function prototypes
342  *
343  * Copyright IBM, Corp. 2011
344  *
345  * Authors:
346  *  Anthony Liguori   <[email protected]>
347  *
348  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
349  * See the COPYING.LIB file in the top-level directory.
350  *
351  */
352 '''
353
354 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
355                             'qmp-marshal.c', 'qmp-commands.h',
356                             c_comment, h_comment)
357
358 fdef.write(mcgen('''
359 #include "qemu-common.h"
360 #include "qemu/module.h"
361 #include "qapi/qmp/types.h"
362 #include "qapi/qmp/dispatch.h"
363 #include "qapi/visitor.h"
364 #include "qapi/qmp-output-visitor.h"
365 #include "qapi/qmp-input-visitor.h"
366 #include "qapi/dealloc-visitor.h"
367 #include "%(prefix)sqapi-types.h"
368 #include "%(prefix)sqapi-visit.h"
369 #include "%(prefix)sqmp-commands.h"
370
371 ''',
372                  prefix=prefix))
373
374 fdecl.write(mcgen('''
375 #include "%(prefix)sqapi-types.h"
376 #include "qapi/qmp/qdict.h"
377 #include "qapi/error.h"
378
379 ''',
380                   prefix=prefix))
381
382 schema = QAPISchema(input_file)
383 gen = QAPISchemaGenCommandVisitor()
384 schema.visit(gen)
385 fdef.write(gen.defn)
386 fdecl.write(gen.decl)
387
388 close_output(fdef, fdecl)
This page took 0.045375 seconds and 4 git commands to generate.