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