root / scripts / qapi-commands.py @ c17d9908
History | View | Annotate | Download (9.6 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): |
171 |
if not ret_type: |
172 |
return "" |
173 |
ret = mcgen('''
|
174 |
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
|
175 |
{
|
176 |
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
177 |
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
178 |
Visitor *v;
|
179 |
|
180 |
v = qmp_output_get_visitor(mo);
|
181 |
visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
|
182 |
if (!error_is_set(errp)) {
|
183 |
*ret_out = qmp_output_get_qobject(mo);
|
184 |
}
|
185 |
qmp_output_visitor_cleanup(mo);
|
186 |
v = qapi_dealloc_get_visitor(md);
|
187 |
visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
|
188 |
qapi_dealloc_visitor_cleanup(md);
|
189 |
}
|
190 |
''',
|
191 |
c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type) |
192 |
|
193 |
return ret
|
194 |
|
195 |
def gen_marshal_input(name, args, ret_type): |
196 |
ret = mcgen('''
|
197 |
static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
|
198 |
{
|
199 |
''',
|
200 |
c_name=c_var(name)) |
201 |
|
202 |
if ret_type:
|
203 |
if c_type(ret_type).endswith("*"): |
204 |
retval = " %s retval = NULL;" % c_type(ret_type)
|
205 |
else:
|
206 |
retval = " %s retval;" % c_type(ret_type)
|
207 |
ret += mcgen('''
|
208 |
%(retval)s
|
209 |
''',
|
210 |
retval=retval) |
211 |
|
212 |
if len(args) > 0: |
213 |
ret += mcgen('''
|
214 |
%(visitor_input_containers_decl)s
|
215 |
%(visitor_input_vars_decl)s
|
216 |
|
217 |
%(visitor_input_block)s
|
218 |
|
219 |
''',
|
220 |
visitor_input_containers_decl=gen_visitor_input_containers_decl(args), |
221 |
visitor_input_vars_decl=gen_visitor_input_vars_decl(args), |
222 |
visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
|
223 |
|
224 |
ret += mcgen('''
|
225 |
if (error_is_set(errp)) {
|
226 |
goto out;
|
227 |
}
|
228 |
%(sync_call)s
|
229 |
''',
|
230 |
sync_call=gen_sync_call(name, args, ret_type, indent=4))
|
231 |
ret += mcgen('''
|
232 |
|
233 |
out:
|
234 |
''')
|
235 |
ret += mcgen('''
|
236 |
%(visitor_input_block_cleanup)s
|
237 |
return;
|
238 |
}
|
239 |
''',
|
240 |
visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True)) |
241 |
return ret
|
242 |
|
243 |
def gen_registry(commands): |
244 |
registry=""
|
245 |
push_indent() |
246 |
for cmd in commands: |
247 |
registry += mcgen('''
|
248 |
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
|
249 |
''',
|
250 |
name=cmd['command'], c_name=c_var(cmd['command'])) |
251 |
pop_indent() |
252 |
ret = mcgen('''
|
253 |
static void qmp_init_marshal(void)
|
254 |
{
|
255 |
%(registry)s
|
256 |
}
|
257 |
|
258 |
qapi_init(qmp_init_marshal);
|
259 |
''',
|
260 |
registry=registry.rstrip()) |
261 |
return ret
|
262 |
|
263 |
def gen_command_decl_prologue(header, guard, prefix=""): |
264 |
ret = mcgen('''
|
265 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
266 |
|
267 |
/*
|
268 |
* schema-defined QAPI function prototypes
|
269 |
*
|
270 |
* Copyright IBM, Corp. 2011
|
271 |
*
|
272 |
* Authors:
|
273 |
* Anthony Liguori <aliguori@us.ibm.com>
|
274 |
*
|
275 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
276 |
* See the COPYING.LIB file in the top-level directory.
|
277 |
*
|
278 |
*/
|
279 |
|
280 |
#ifndef %(guard)s
|
281 |
#define %(guard)s
|
282 |
|
283 |
#include "%(prefix)sqapi-types.h"
|
284 |
#include "error.h"
|
285 |
|
286 |
''',
|
287 |
header=basename(h_file), guard=guardname(h_file), prefix=prefix) |
288 |
return ret
|
289 |
|
290 |
def gen_command_def_prologue(prefix="", proxy=False): |
291 |
ret = mcgen('''
|
292 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
293 |
|
294 |
/*
|
295 |
* schema-defined QMP->QAPI command dispatch
|
296 |
*
|
297 |
* Copyright IBM, Corp. 2011
|
298 |
*
|
299 |
* Authors:
|
300 |
* Anthony Liguori <aliguori@us.ibm.com>
|
301 |
*
|
302 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
303 |
* See the COPYING.LIB file in the top-level directory.
|
304 |
*
|
305 |
*/
|
306 |
|
307 |
#include "qemu-objects.h"
|
308 |
#include "qapi/qmp-core.h"
|
309 |
#include "qapi/qapi-visit-core.h"
|
310 |
#include "qapi/qmp-output-visitor.h"
|
311 |
#include "qapi/qmp-input-visitor.h"
|
312 |
#include "qapi/qapi-dealloc-visitor.h"
|
313 |
#include "%(prefix)sqapi-types.h"
|
314 |
#include "%(prefix)sqapi-visit.h"
|
315 |
|
316 |
''',
|
317 |
prefix=prefix) |
318 |
if not proxy: |
319 |
ret += '#include "%sqmp-commands.h"' % prefix
|
320 |
return ret + "\n" |
321 |
|
322 |
|
323 |
try:
|
324 |
opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="]) |
325 |
except getopt.GetoptError, err:
|
326 |
print str(err) |
327 |
sys.exit(1)
|
328 |
|
329 |
output_dir = ""
|
330 |
prefix = ""
|
331 |
dispatch_type = "sync"
|
332 |
c_file = 'qmp-marshal.c'
|
333 |
h_file = 'qmp-commands.h'
|
334 |
|
335 |
for o, a in opts: |
336 |
if o in ("-p", "--prefix"): |
337 |
prefix = a |
338 |
elif o in ("-o", "--output-dir"): |
339 |
output_dir = a + "/"
|
340 |
elif o in ("-t", "--type"): |
341 |
dispatch_type = a |
342 |
|
343 |
c_file = output_dir + prefix + c_file |
344 |
h_file = output_dir + prefix + h_file |
345 |
|
346 |
try:
|
347 |
os.makedirs(output_dir) |
348 |
except os.error, e:
|
349 |
if e.errno != errno.EEXIST:
|
350 |
raise
|
351 |
|
352 |
exprs = parse_schema(sys.stdin) |
353 |
commands = filter(lambda expr: expr.has_key('command'), exprs) |
354 |
|
355 |
if dispatch_type == "sync": |
356 |
fdecl = open(h_file, 'w') |
357 |
fdef = open(c_file, 'w') |
358 |
ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) |
359 |
fdecl.write(ret) |
360 |
ret = gen_command_def_prologue(prefix=prefix) |
361 |
fdef.write(ret) |
362 |
|
363 |
for cmd in commands: |
364 |
arglist = [] |
365 |
ret_type = None
|
366 |
if cmd.has_key('data'): |
367 |
arglist = cmd['data']
|
368 |
if cmd.has_key('returns'): |
369 |
ret_type = cmd['returns']
|
370 |
ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" |
371 |
fdecl.write(ret) |
372 |
if ret_type:
|
373 |
ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n" |
374 |
fdef.write(ret) |
375 |
ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n" |
376 |
fdef.write(ret) |
377 |
|
378 |
fdecl.write("\n#endif");
|
379 |
ret = gen_registry(commands) |
380 |
fdef.write(ret) |
381 |
|
382 |
fdef.flush() |
383 |
fdef.close() |
384 |
fdecl.flush() |
385 |
fdecl.close() |