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