|
|
1.1 root 1: #
2: # QAPI command marshaller generator
3: #
4: # Copyright IBM, Corp. 2011
5: #
6: # Authors:
7: # Anthony Liguori <[email protected]>
8: # Michael Roth <[email protected]>
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 <[email protected]>
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 <[email protected]>
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()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.