root / scripts / qapi-commands.py @ c9da228b
History | View | Annotate | Download (11.5 kB)
1 |
#
|
---|---|
2 |
# QAPI command marshaller generator
|
3 |
#
|
4 |
# Copyright IBM, Corp. 2011
|
5 |
#
|
6 |
# Authors:
|
7 |
# Anthony Liguori <aliguori@us.ibm.com>
|
8 |
# Michael Roth <mdroth@linux.vnet.ibm.com>
|
9 |
#
|
10 |
# This work is licensed under the terms of the GNU GPLv2.
|
11 |
# See the COPYING.LIB file in the top-level directory.
|
12 |
|
13 |
from ordereddict import OrderedDict |
14 |
from qapi import * |
15 |
import sys |
16 |
import os |
17 |
import getopt |
18 |
import errno |
19 |
|
20 |
def type_visitor(name): |
21 |
if type(name) == list: |
22 |
return 'visit_type_%sList' % name[0] |
23 |
else:
|
24 |
return 'visit_type_%s' % name |
25 |
|
26 |
def generate_decl_enum(name, members, genlist=True): |
27 |
return mcgen(''' |
28 |
|
29 |
void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
|
30 |
''',
|
31 |
visitor=type_visitor(name)) |
32 |
|
33 |
def generate_command_decl(name, args, ret_type): |
34 |
arglist=""
|
35 |
for argname, argtype, optional, structured in parse_args(args): |
36 |
argtype = c_type(argtype) |
37 |
if argtype == "char *": |
38 |
argtype = "const char *"
|
39 |
if optional:
|
40 |
arglist += "bool has_%s, " % c_var(argname)
|
41 |
arglist += "%s %s, " % (argtype, c_var(argname))
|
42 |
return mcgen(''' |
43 |
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
|
44 |
''',
|
45 |
ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() |
46 |
|
47 |
def gen_sync_call(name, args, ret_type, indent=0): |
48 |
ret = ""
|
49 |
arglist=""
|
50 |
retval=""
|
51 |
if ret_type:
|
52 |
retval = "retval = "
|
53 |
for argname, argtype, optional, structured in parse_args(args): |
54 |
if optional:
|
55 |
arglist += "has_%s, " % c_var(argname)
|
56 |
arglist += "%s, " % (c_var(argname))
|
57 |
push_indent(indent) |
58 |
ret = mcgen('''
|
59 |
%(retval)sqmp_%(name)s(%(args)serrp);
|
60 |
|
61 |
''',
|
62 |
name=c_fun(name), args=arglist, retval=retval).rstrip() |
63 |
if ret_type:
|
64 |
ret += "\n" + mcgen('''' |
65 |
if (!error_is_set(errp)) {
|
66 |
%(marshal_output_call)s
|
67 |
}
|
68 |
''',
|
69 |
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() |
70 |
pop_indent(indent) |
71 |
return ret.rstrip()
|
72 |
|
73 |
|
74 |
def gen_marshal_output_call(name, ret_type): |
75 |
if not ret_type: |
76 |
return "" |
77 |
return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) |
78 |
|
79 |
def gen_visitor_output_containers_decl(ret_type): |
80 |
ret = ""
|
81 |
push_indent() |
82 |
if ret_type:
|
83 |
ret += mcgen('''
|
84 |
QmpOutputVisitor *mo;
|
85 |
QapiDeallocVisitor *md;
|
86 |
Visitor *v;
|
87 |
''')
|
88 |
pop_indent() |
89 |
|
90 |
return ret
|
91 |
|
92 |
def gen_visitor_input_containers_decl(args): |
93 |
ret = ""
|
94 |
|
95 |
push_indent() |
96 |
if len(args) > 0: |
97 |
ret += mcgen('''
|
98 |
QmpInputVisitor *mi;
|
99 |
QapiDeallocVisitor *md;
|
100 |
Visitor *v;
|
101 |
''')
|
102 |
pop_indent() |
103 |
|
104 |
return ret.rstrip()
|
105 |
|
106 |
def gen_visitor_input_vars_decl(args): |
107 |
ret = ""
|
108 |
push_indent() |
109 |
for argname, argtype, optional, structured in parse_args(args): |
110 |
if optional:
|
111 |
ret += mcgen('''
|
112 |
bool has_%(argname)s = false;
|
113 |
''',
|
114 |
argname=c_var(argname)) |
115 |
if c_type(argtype).endswith("*"): |
116 |
ret += mcgen('''
|
117 |
%(argtype)s %(argname)s = NULL;
|
118 |
''',
|
119 |
argname=c_var(argname), argtype=c_type(argtype)) |
120 |
else:
|
121 |
ret += mcgen('''
|
122 |
%(argtype)s %(argname)s;
|
123 |
''',
|
124 |
argname=c_var(argname), argtype=c_type(argtype)) |
125 |
|
126 |
pop_indent() |
127 |
return ret.rstrip()
|
128 |
|
129 |
def gen_visitor_input_block(args, obj, dealloc=False): |
130 |
ret = ""
|
131 |
if len(args) == 0: |
132 |
return ret
|
133 |
|
134 |
push_indent() |
135 |
|
136 |
if dealloc:
|
137 |
ret += mcgen('''
|
138 |
md = qapi_dealloc_visitor_new();
|
139 |
v = qapi_dealloc_get_visitor(md);
|
140 |
''')
|
141 |
else:
|
142 |
ret += mcgen('''
|
143 |
mi = qmp_input_visitor_new(%(obj)s);
|
144 |
v = qmp_input_get_visitor(mi);
|
145 |
''',
|
146 |
obj=obj) |
147 |
|
148 |
for argname, argtype, optional, structured in parse_args(args): |
149 |
if optional:
|
150 |
ret += mcgen('''
|
151 |
visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
|
152 |
if (has_%(c_name)s) {
|
153 |
''',
|
154 |
c_name=c_var(argname), name=argname) |
155 |
push_indent() |
156 |
ret += mcgen('''
|
157 |
%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
|
158 |
''',
|
159 |
c_name=c_var(argname), name=argname, argtype=argtype, |
160 |
visitor=type_visitor(argtype)) |
161 |
if optional:
|
162 |
pop_indent() |
163 |
ret += mcgen('''
|
164 |
}
|
165 |
visit_end_optional(v, errp);
|
166 |
''')
|
167 |
|
168 |
if dealloc:
|
169 |
ret += mcgen('''
|
170 |
qapi_dealloc_visitor_cleanup(md);
|
171 |
''')
|
172 |
else:
|
173 |
ret += mcgen('''
|
174 |
qmp_input_visitor_cleanup(mi);
|
175 |
''')
|
176 |
pop_indent() |
177 |
return ret.rstrip()
|
178 |
|
179 |
def gen_marshal_output(name, args, ret_type, middle_mode): |
180 |
if not ret_type: |
181 |
return "" |
182 |
|
183 |
ret = mcgen('''
|
184 |
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
|
185 |
{
|
186 |
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
187 |
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
188 |
Visitor *v;
|
189 |
|
190 |
v = qmp_output_get_visitor(mo);
|
191 |
%(visitor)s(v, &ret_in, "unused", errp);
|
192 |
if (!error_is_set(errp)) {
|
193 |
*ret_out = qmp_output_get_qobject(mo);
|
194 |
}
|
195 |
qmp_output_visitor_cleanup(mo);
|
196 |
v = qapi_dealloc_get_visitor(md);
|
197 |
%(visitor)s(v, &ret_in, "unused", errp);
|
198 |
qapi_dealloc_visitor_cleanup(md);
|
199 |
}
|
200 |
''',
|
201 |
c_ret_type=c_type(ret_type), c_name=c_fun(name), |
202 |
visitor=type_visitor(ret_type)) |
203 |
|
204 |
return ret
|
205 |
|
206 |
def gen_marshal_input_decl(name, args, ret_type, middle_mode): |
207 |
if middle_mode:
|
208 |
return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name) |
209 |
else:
|
210 |
return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name) |
211 |
|
212 |
|
213 |
|
214 |
def gen_marshal_input(name, args, ret_type, middle_mode): |
215 |
hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode) |
216 |
|
217 |
ret = mcgen('''
|
218 |
%(header)s
|
219 |
{
|
220 |
''',
|
221 |
header=hdr) |
222 |
|
223 |
if middle_mode:
|
224 |
ret += mcgen('''
|
225 |
Error *local_err = NULL;
|
226 |
Error **errp = &local_err;
|
227 |
QDict *args = (QDict *)qdict;
|
228 |
''')
|
229 |
|
230 |
if ret_type:
|
231 |
if c_type(ret_type).endswith("*"): |
232 |
retval = " %s retval = NULL;" % c_type(ret_type)
|
233 |
else:
|
234 |
retval = " %s retval;" % c_type(ret_type)
|
235 |
ret += mcgen('''
|
236 |
%(retval)s
|
237 |
''',
|
238 |
retval=retval) |
239 |
|
240 |
if len(args) > 0: |
241 |
ret += mcgen('''
|
242 |
%(visitor_input_containers_decl)s
|
243 |
%(visitor_input_vars_decl)s
|
244 |
|
245 |
%(visitor_input_block)s
|
246 |
|
247 |
''',
|
248 |
visitor_input_containers_decl=gen_visitor_input_containers_decl(args), |
249 |
visitor_input_vars_decl=gen_visitor_input_vars_decl(args), |
250 |
visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
|
251 |
else:
|
252 |
ret += mcgen('''
|
253 |
(void)args;
|
254 |
''')
|
255 |
|
256 |
ret += mcgen('''
|
257 |
if (error_is_set(errp)) {
|
258 |
goto out;
|
259 |
}
|
260 |
%(sync_call)s
|
261 |
''',
|
262 |
sync_call=gen_sync_call(name, args, ret_type, indent=4))
|
263 |
ret += mcgen('''
|
264 |
|
265 |
out:
|
266 |
''')
|
267 |
ret += mcgen('''
|
268 |
%(visitor_input_block_cleanup)s
|
269 |
''',
|
270 |
visitor_input_block_cleanup=gen_visitor_input_block(args, None,
|
271 |
dealloc=True))
|
272 |
|
273 |
if middle_mode:
|
274 |
ret += mcgen('''
|
275 |
|
276 |
if (local_err) {
|
277 |
qerror_report_err(local_err);
|
278 |
error_free(local_err);
|
279 |
return -1;
|
280 |
}
|
281 |
return 0;
|
282 |
''')
|
283 |
else:
|
284 |
ret += mcgen('''
|
285 |
return;
|
286 |
''')
|
287 |
|
288 |
ret += mcgen('''
|
289 |
}
|
290 |
''')
|
291 |
|
292 |
return ret
|
293 |
|
294 |
def gen_registry(commands): |
295 |
registry=""
|
296 |
push_indent() |
297 |
for cmd in commands: |
298 |
registry += mcgen('''
|
299 |
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
|
300 |
''',
|
301 |
name=cmd['command'], c_name=c_fun(cmd['command'])) |
302 |
pop_indent() |
303 |
ret = mcgen('''
|
304 |
static void qmp_init_marshal(void)
|
305 |
{
|
306 |
%(registry)s
|
307 |
}
|
308 |
|
309 |
qapi_init(qmp_init_marshal);
|
310 |
''',
|
311 |
registry=registry.rstrip()) |
312 |
return ret
|
313 |
|
314 |
def gen_command_decl_prologue(header, guard, prefix=""): |
315 |
ret = mcgen('''
|
316 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
317 |
|
318 |
/*
|
319 |
* schema-defined QAPI function prototypes
|
320 |
*
|
321 |
* Copyright IBM, Corp. 2011
|
322 |
*
|
323 |
* Authors:
|
324 |
* Anthony Liguori <aliguori@us.ibm.com>
|
325 |
*
|
326 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
327 |
* See the COPYING.LIB file in the top-level directory.
|
328 |
*
|
329 |
*/
|
330 |
|
331 |
#ifndef %(guard)s
|
332 |
#define %(guard)s
|
333 |
|
334 |
#include "%(prefix)sqapi-types.h"
|
335 |
#include "error.h"
|
336 |
|
337 |
''',
|
338 |
header=basename(header), guard=guardname(header), prefix=prefix) |
339 |
return ret
|
340 |
|
341 |
def gen_command_def_prologue(prefix="", proxy=False): |
342 |
ret = mcgen('''
|
343 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
344 |
|
345 |
/*
|
346 |
* schema-defined QMP->QAPI command dispatch
|
347 |
*
|
348 |
* Copyright IBM, Corp. 2011
|
349 |
*
|
350 |
* Authors:
|
351 |
* Anthony Liguori <aliguori@us.ibm.com>
|
352 |
*
|
353 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
354 |
* See the COPYING.LIB file in the top-level directory.
|
355 |
*
|
356 |
*/
|
357 |
|
358 |
#include "qemu-objects.h"
|
359 |
#include "qapi/qmp-core.h"
|
360 |
#include "qapi/qapi-visit-core.h"
|
361 |
#include "qapi/qmp-output-visitor.h"
|
362 |
#include "qapi/qmp-input-visitor.h"
|
363 |
#include "qapi/qapi-dealloc-visitor.h"
|
364 |
#include "%(prefix)sqapi-types.h"
|
365 |
#include "%(prefix)sqapi-visit.h"
|
366 |
|
367 |
''',
|
368 |
prefix=prefix) |
369 |
if not proxy: |
370 |
ret += '#include "%sqmp-commands.h"' % prefix
|
371 |
return ret + "\n\n" |
372 |
|
373 |
|
374 |
try:
|
375 |
opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m", |
376 |
["source", "header", "prefix=", |
377 |
"output-dir=", "type=", "middle"]) |
378 |
except getopt.GetoptError, err:
|
379 |
print str(err) |
380 |
sys.exit(1)
|
381 |
|
382 |
output_dir = ""
|
383 |
prefix = ""
|
384 |
dispatch_type = "sync"
|
385 |
c_file = 'qmp-marshal.c'
|
386 |
h_file = 'qmp-commands.h'
|
387 |
middle_mode = False
|
388 |
|
389 |
do_c = False
|
390 |
do_h = False
|
391 |
|
392 |
for o, a in opts: |
393 |
if o in ("-p", "--prefix"): |
394 |
prefix = a |
395 |
elif o in ("-o", "--output-dir"): |
396 |
output_dir = a + "/"
|
397 |
elif o in ("-t", "--type"): |
398 |
dispatch_type = a |
399 |
elif o in ("-m", "--middle"): |
400 |
middle_mode = True
|
401 |
elif o in ("-c", "--source"): |
402 |
do_c = True
|
403 |
elif o in ("-h", "--header"): |
404 |
do_h = True
|
405 |
|
406 |
if not do_c and not do_h: |
407 |
do_c = True
|
408 |
do_h = True
|
409 |
|
410 |
c_file = output_dir + prefix + c_file |
411 |
h_file = output_dir + prefix + h_file |
412 |
|
413 |
def maybe_open(really, name, opt): |
414 |
if really:
|
415 |
return open(name, opt) |
416 |
else:
|
417 |
import StringIO |
418 |
return StringIO.StringIO()
|
419 |
|
420 |
try:
|
421 |
os.makedirs(output_dir) |
422 |
except os.error, e:
|
423 |
if e.errno != errno.EEXIST:
|
424 |
raise
|
425 |
|
426 |
exprs = parse_schema(sys.stdin) |
427 |
commands = filter(lambda expr: expr.has_key('command'), exprs) |
428 |
commands = filter(lambda expr: not expr.has_key('gen'), commands) |
429 |
|
430 |
if dispatch_type == "sync": |
431 |
fdecl = maybe_open(do_h, h_file, 'w')
|
432 |
fdef = maybe_open(do_c, c_file, 'w')
|
433 |
ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) |
434 |
fdecl.write(ret) |
435 |
ret = gen_command_def_prologue(prefix=prefix) |
436 |
fdef.write(ret) |
437 |
|
438 |
for cmd in commands: |
439 |
arglist = [] |
440 |
ret_type = None
|
441 |
if cmd.has_key('data'): |
442 |
arglist = cmd['data']
|
443 |
if cmd.has_key('returns'): |
444 |
ret_type = cmd['returns']
|
445 |
ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" |
446 |
fdecl.write(ret) |
447 |
if ret_type:
|
448 |
ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" |
449 |
fdef.write(ret) |
450 |
|
451 |
if middle_mode:
|
452 |
fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) |
453 |
|
454 |
ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" |
455 |
fdef.write(ret) |
456 |
|
457 |
fdecl.write("\n#endif\n");
|
458 |
|
459 |
if not middle_mode: |
460 |
ret = gen_registry(commands) |
461 |
fdef.write(ret) |
462 |
|
463 |
fdef.flush() |
464 |
fdef.close() |
465 |
fdecl.flush() |
466 |
fdecl.close() |