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