]> git.proxmox.com Git - qemu.git/blame - scripts/qapi-commands.py
qapi: use middle mode in QMP server
[qemu.git] / scripts / qapi-commands.py
CommitLineData
c17d9908
MR
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
13from ordereddict import OrderedDict
14from qapi import *
15import sys
16import os
17import getopt
18import errno
19
20def generate_decl_enum(name, members, genlist=True):
21 return mcgen('''
22
23void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
24''',
25 name=name)
26
27def 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
41def 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
66def 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
71def gen_visitor_output_containers_decl(ret_type):
72 ret = ""
73 push_indent()
74 if ret_type:
75 ret += mcgen('''
76QmpOutputVisitor *mo;
77QapiDeallocVisitor *md;
78Visitor *v;
79''')
80 pop_indent()
81
82 return ret
83
84def gen_visitor_input_containers_decl(args):
85 ret = ""
86
87 push_indent()
88 if len(args) > 0:
89 ret += mcgen('''
90QmpInputVisitor *mi;
91QapiDeallocVisitor *md;
92Visitor *v;
93''')
94 pop_indent()
95
96 return ret.rstrip()
97
98def 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('''
104bool 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
121def 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('''
130md = qapi_dealloc_visitor_new();
131v = qapi_dealloc_get_visitor(md);
132''')
133 else:
134 ret += mcgen('''
135mi = qmp_input_visitor_new(%(obj)s);
136v = 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('''
143visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
144if (has_%(c_name)s) {
145''',
146 c_name=c_var(argname), name=argname)
147 push_indent()
148 ret += mcgen('''
149visit_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}
156visit_end_optional(v, errp);
157''')
158
159 if dealloc:
160 ret += mcgen('''
161qapi_dealloc_visitor_cleanup(md);
162''')
163 else:
164 ret += mcgen('''
165qmp_input_visitor_cleanup(mi);
166''')
167 pop_indent()
168 return ret.rstrip()
169
776574d6 170def gen_marshal_output(name, args, ret_type, middle_mode):
c17d9908
MR
171 if not ret_type:
172 return ""
776574d6 173
c17d9908
MR
174 ret = mcgen('''
175static 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''',
776574d6
AL
192 c_ret_type=c_type(ret_type), c_name=c_var(name),
193 ret_type=ret_type)
c17d9908
MR
194
195 return ret
196
776574d6
AL
197def 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
205def 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
MR
210{
211''',
776574d6
AL
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''')
c17d9908
MR
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)"))
776574d6
AL
242 else:
243 ret += mcgen('''
244 (void)args;
245''')
c17d9908
MR
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
256out:
257''')
258 ret += mcgen('''
259%(visitor_input_block_cleanup)s
776574d6
AL
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('''
c17d9908 276 return;
776574d6
AL
277''')
278
279 ret += mcgen('''
c17d9908 280}
776574d6
AL
281''')
282
c17d9908
MR
283 return ret
284
285def gen_registry(commands):
286 registry=""
287 push_indent()
288 for cmd in commands:
289 registry += mcgen('''
290qmp_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('''
295static void qmp_init_marshal(void)
296{
297%(registry)s
298}
299
300qapi_init(qmp_init_marshal);
301''',
302 registry=registry.rstrip())
303 return ret
304
305def 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''',
776574d6 329 header=basename(header), guard=guardname(header), prefix=prefix)
c17d9908
MR
330 return ret
331
332def 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
776574d6 362 return ret + "\n\n"
c17d9908
MR
363
364
365try:
776574d6 366 opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"])
c17d9908
MR
367except getopt.GetoptError, err:
368 print str(err)
369 sys.exit(1)
370
371output_dir = ""
372prefix = ""
373dispatch_type = "sync"
374c_file = 'qmp-marshal.c'
375h_file = 'qmp-commands.h'
776574d6 376middle_mode = False
c17d9908
MR
377
378for 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
776574d6
AL
385 elif o in ("-m", "--middle"):
386 middle_mode = True
c17d9908
MR
387
388c_file = output_dir + prefix + c_file
389h_file = output_dir + prefix + h_file
390
391try:
392 os.makedirs(output_dir)
393except os.error, e:
394 if e.errno != errno.EEXIST:
395 raise
396
397exprs = parse_schema(sys.stdin)
398commands = filter(lambda expr: expr.has_key('command'), exprs)
399
400if 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:
776574d6 418 ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
c17d9908 419 fdef.write(ret)
776574d6
AL
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"
c17d9908
MR
425 fdef.write(ret)
426
7534ba01 427 fdecl.write("\n#endif\n");
776574d6
AL
428
429 if not middle_mode:
430 ret = gen_registry(commands)
431 fdef.write(ret)
c17d9908
MR
432
433 fdef.flush()
434 fdef.close()
435 fdecl.flush()
436 fdecl.close()