|
|
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: ''',
1.1.1.3 ! root 45: ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
1.1 root 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: ''',
1.1.1.3 ! root 62: name=c_fun(name), args=arglist, retval=retval).rstrip()
1.1 root 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 ""
1.1.1.3 ! root 77: return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name)
1.1 root 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('''
1.1.1.3 ! root 143: mi = qmp_input_visitor_new_strict(%(obj)s);
1.1 root 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.3 ! root 201: c_ret_type=c_type(ret_type), c_name=c_fun(name),
1.1.1.2 root 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:
1.1.1.3 ! root 208: return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name)
1.1.1.2 root 209: else:
1.1.1.3 ! root 210: return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name)
1.1.1.2 root 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:
1.1.1.3 ! root 294: def option_value_matches(opt, val, cmd):
! 295: if opt in cmd and cmd[opt] == val:
! 296: return True
! 297: return False
! 298:
1.1 root 299: def gen_registry(commands):
300: registry=""
301: push_indent()
302: for cmd in commands:
1.1.1.3 ! root 303: options = 'QCO_NO_OPTIONS'
! 304: if option_value_matches('success-response', 'no', cmd):
! 305: options = 'QCO_NO_SUCCESS_RESP'
! 306:
1.1 root 307: registry += mcgen('''
1.1.1.3 ! root 308: qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
1.1 root 309: ''',
1.1.1.3 ! root 310: name=cmd['command'], c_name=c_fun(cmd['command']),
! 311: opts=options)
1.1 root 312: pop_indent()
313: ret = mcgen('''
314: static void qmp_init_marshal(void)
315: {
316: %(registry)s
317: }
318:
319: qapi_init(qmp_init_marshal);
320: ''',
321: registry=registry.rstrip())
322: return ret
323:
324: def gen_command_decl_prologue(header, guard, prefix=""):
325: ret = mcgen('''
326: /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
327:
328: /*
329: * schema-defined QAPI function prototypes
330: *
331: * Copyright IBM, Corp. 2011
332: *
333: * Authors:
334: * Anthony Liguori <[email protected]>
335: *
336: * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
337: * See the COPYING.LIB file in the top-level directory.
338: *
339: */
340:
341: #ifndef %(guard)s
342: #define %(guard)s
343:
344: #include "%(prefix)sqapi-types.h"
345: #include "error.h"
346:
347: ''',
1.1.1.2 root 348: header=basename(header), guard=guardname(header), prefix=prefix)
1.1 root 349: return ret
350:
351: def gen_command_def_prologue(prefix="", proxy=False):
352: ret = mcgen('''
353: /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
354:
355: /*
356: * schema-defined QMP->QAPI command dispatch
357: *
358: * Copyright IBM, Corp. 2011
359: *
360: * Authors:
361: * Anthony Liguori <[email protected]>
362: *
363: * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
364: * See the COPYING.LIB file in the top-level directory.
365: *
366: */
367:
368: #include "qemu-objects.h"
369: #include "qapi/qmp-core.h"
370: #include "qapi/qapi-visit-core.h"
371: #include "qapi/qmp-output-visitor.h"
372: #include "qapi/qmp-input-visitor.h"
373: #include "qapi/qapi-dealloc-visitor.h"
374: #include "%(prefix)sqapi-types.h"
375: #include "%(prefix)sqapi-visit.h"
376:
377: ''',
378: prefix=prefix)
379: if not proxy:
380: ret += '#include "%sqmp-commands.h"' % prefix
1.1.1.2 root 381: return ret + "\n\n"
1.1 root 382:
383:
384: try:
1.1.1.3 ! root 385: opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m",
! 386: ["source", "header", "prefix=",
! 387: "output-dir=", "type=", "middle"])
1.1 root 388: except getopt.GetoptError, err:
389: print str(err)
390: sys.exit(1)
391:
392: output_dir = ""
393: prefix = ""
394: dispatch_type = "sync"
395: c_file = 'qmp-marshal.c'
396: h_file = 'qmp-commands.h'
1.1.1.2 root 397: middle_mode = False
1.1 root 398:
1.1.1.3 ! root 399: do_c = False
! 400: do_h = False
! 401:
1.1 root 402: for o, a in opts:
403: if o in ("-p", "--prefix"):
404: prefix = a
405: elif o in ("-o", "--output-dir"):
406: output_dir = a + "/"
407: elif o in ("-t", "--type"):
408: dispatch_type = a
1.1.1.2 root 409: elif o in ("-m", "--middle"):
410: middle_mode = True
1.1.1.3 ! root 411: elif o in ("-c", "--source"):
! 412: do_c = True
! 413: elif o in ("-h", "--header"):
! 414: do_h = True
! 415:
! 416: if not do_c and not do_h:
! 417: do_c = True
! 418: do_h = True
1.1 root 419:
420: c_file = output_dir + prefix + c_file
421: h_file = output_dir + prefix + h_file
422:
1.1.1.3 ! root 423: def maybe_open(really, name, opt):
! 424: if really:
! 425: return open(name, opt)
! 426: else:
! 427: import StringIO
! 428: return StringIO.StringIO()
! 429:
1.1 root 430: try:
431: os.makedirs(output_dir)
432: except os.error, e:
433: if e.errno != errno.EEXIST:
434: raise
435:
436: exprs = parse_schema(sys.stdin)
437: commands = filter(lambda expr: expr.has_key('command'), exprs)
1.1.1.3 ! root 438: commands = filter(lambda expr: not expr.has_key('gen'), commands)
1.1 root 439:
440: if dispatch_type == "sync":
1.1.1.3 ! root 441: fdecl = maybe_open(do_h, h_file, 'w')
! 442: fdef = maybe_open(do_c, c_file, 'w')
1.1 root 443: ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
444: fdecl.write(ret)
445: ret = gen_command_def_prologue(prefix=prefix)
446: fdef.write(ret)
447:
448: for cmd in commands:
449: arglist = []
450: ret_type = None
451: if cmd.has_key('data'):
452: arglist = cmd['data']
453: if cmd.has_key('returns'):
454: ret_type = cmd['returns']
455: ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
456: fdecl.write(ret)
457: if ret_type:
1.1.1.2 root 458: ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
1.1 root 459: fdef.write(ret)
1.1.1.2 root 460:
461: if middle_mode:
462: fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
463:
464: ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
1.1 root 465: fdef.write(ret)
466:
1.1.1.2 root 467: fdecl.write("\n#endif\n");
468:
469: if not middle_mode:
470: ret = gen_registry(commands)
471: fdef.write(ret)
1.1 root 472:
473: fdef.flush()
474: fdef.close()
475: fdecl.flush()
476: fdecl.close()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.