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