|
|
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:
1.1.1.2 ! root 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:
1.1 root 26: def generate_decl_enum(name, members, genlist=True):
27: return mcgen('''
28:
1.1.1.2 ! root 29: void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
1.1 root 30: ''',
1.1.1.2 ! root 31: visitor=type_visitor(name))
1.1 root 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_var(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_var(name), args=arglist, retval=retval).rstrip()
63: if ret_type:
64: ret += "\n" + mcgen(''''
1.1.1.2 ! root 65: if (!error_is_set(errp)) {
! 66: %(marshal_output_call)s
! 67: }
1.1 root 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_var(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('''
1.1.1.2 ! root 157: %(visitor)s(v, &%(c_name)s, "%(name)s", errp);
1.1 root 158: ''',
1.1.1.2 ! root 159: c_name=c_var(argname), name=argname, argtype=argtype,
! 160: visitor=type_visitor(argtype))
1.1 root 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:
1.1.1.2 ! root 179: def gen_marshal_output(name, args, ret_type, middle_mode):
1.1 root 180: if not ret_type:
181: return ""
1.1.1.2 ! root 182:
1.1 root 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);
1.1.1.2 ! root 191: %(visitor)s(v, &ret_in, "unused", errp);
1.1 root 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);
1.1.1.2 ! root 197: %(visitor)s(v, &ret_in, "unused", errp);
1.1 root 198: qapi_dealloc_visitor_cleanup(md);
199: }
200: ''',
1.1.1.2 ! root 201: c_ret_type=c_type(ret_type), c_name=c_var(name),
! 202: visitor=type_visitor(ret_type))
1.1 root 203:
204: return ret
205:
1.1.1.2 ! root 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_var(name)
! 209: else:
! 210: return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(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:
1.1 root 217: ret = mcgen('''
1.1.1.2 ! root 218: %(header)s
1.1 root 219: {
220: ''',
1.1.1.2 ! root 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: ''')
1.1 root 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)"))
1.1.1.2 ! root 251: else:
! 252: ret += mcgen('''
! 253: (void)args;
! 254: ''')
1.1 root 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
1.1.1.2 ! root 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('''
1.1 root 285: return;
1.1.1.2 ! root 286: ''')
! 287:
! 288: ret += mcgen('''
1.1 root 289: }
1.1.1.2 ! root 290: ''')
! 291:
1.1 root 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_var(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 <[email protected]>
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: ''',
1.1.1.2 ! root 338: header=basename(header), guard=guardname(header), prefix=prefix)
1.1 root 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 <[email protected]>
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
1.1.1.2 ! root 371: return ret + "\n\n"
1.1 root 372:
373:
374: try:
1.1.1.2 ! root 375: opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"])
1.1 root 376: except getopt.GetoptError, err:
377: print str(err)
378: sys.exit(1)
379:
380: output_dir = ""
381: prefix = ""
382: dispatch_type = "sync"
383: c_file = 'qmp-marshal.c'
384: h_file = 'qmp-commands.h'
1.1.1.2 ! root 385: middle_mode = False
1.1 root 386:
387: for o, a in opts:
388: if o in ("-p", "--prefix"):
389: prefix = a
390: elif o in ("-o", "--output-dir"):
391: output_dir = a + "/"
392: elif o in ("-t", "--type"):
393: dispatch_type = a
1.1.1.2 ! root 394: elif o in ("-m", "--middle"):
! 395: middle_mode = True
1.1 root 396:
397: c_file = output_dir + prefix + c_file
398: h_file = output_dir + prefix + h_file
399:
400: try:
401: os.makedirs(output_dir)
402: except os.error, e:
403: if e.errno != errno.EEXIST:
404: raise
405:
406: exprs = parse_schema(sys.stdin)
407: commands = filter(lambda expr: expr.has_key('command'), exprs)
408:
409: if dispatch_type == "sync":
410: fdecl = open(h_file, 'w')
411: fdef = open(c_file, 'w')
412: ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
413: fdecl.write(ret)
414: ret = gen_command_def_prologue(prefix=prefix)
415: fdef.write(ret)
416:
417: for cmd in commands:
418: arglist = []
419: ret_type = None
420: if cmd.has_key('data'):
421: arglist = cmd['data']
422: if cmd.has_key('returns'):
423: ret_type = cmd['returns']
424: ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
425: fdecl.write(ret)
426: if ret_type:
1.1.1.2 ! root 427: ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
1.1 root 428: fdef.write(ret)
1.1.1.2 ! root 429:
! 430: if middle_mode:
! 431: fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
! 432:
! 433: ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
1.1 root 434: fdef.write(ret)
435:
1.1.1.2 ! root 436: fdecl.write("\n#endif\n");
! 437:
! 438: if not middle_mode:
! 439: ret = gen_registry(commands)
! 440: fdef.write(ret)
1.1 root 441:
442: fdef.flush()
443: fdef.close()
444: fdecl.flush()
445: fdecl.close()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.