1fb0bc835SMarkus Armbruster""" 2fb0bc835SMarkus ArmbrusterQAPI command marshaller generator 3fb0bc835SMarkus Armbruster 4fb0bc835SMarkus ArmbrusterCopyright IBM, Corp. 2011 5fb0bc835SMarkus ArmbrusterCopyright (C) 2014-2018 Red Hat, Inc. 6fb0bc835SMarkus Armbruster 7fb0bc835SMarkus ArmbrusterAuthors: 8fb0bc835SMarkus Armbruster Anthony Liguori <aliguori@us.ibm.com> 9fb0bc835SMarkus Armbruster Michael Roth <mdroth@linux.vnet.ibm.com> 10fb0bc835SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 11fb0bc835SMarkus Armbruster 12fb0bc835SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 13fb0bc835SMarkus ArmbrusterSee the COPYING file in the top-level directory. 14fb0bc835SMarkus Armbruster""" 15fb0bc835SMarkus Armbruster 16fb0bc835SMarkus Armbrusterfrom qapi.common import * 17fb0bc835SMarkus Armbruster 18fb0bc835SMarkus Armbruster 19fb0bc835SMarkus Armbrusterdef gen_command_decl(name, arg_type, boxed, ret_type): 20fb0bc835SMarkus Armbruster return mcgen(''' 21fb0bc835SMarkus Armbruster%(c_type)s qmp_%(c_name)s(%(params)s); 22fb0bc835SMarkus Armbruster''', 23fb0bc835SMarkus Armbruster c_type=(ret_type and ret_type.c_type()) or 'void', 24fb0bc835SMarkus Armbruster c_name=c_name(name), 25fb0bc835SMarkus Armbruster params=build_params(arg_type, boxed, 'Error **errp')) 26fb0bc835SMarkus Armbruster 27fb0bc835SMarkus Armbruster 28fb0bc835SMarkus Armbrusterdef gen_call(name, arg_type, boxed, ret_type): 29fb0bc835SMarkus Armbruster ret = '' 30fb0bc835SMarkus Armbruster 31fb0bc835SMarkus Armbruster argstr = '' 32fb0bc835SMarkus Armbruster if boxed: 33fb0bc835SMarkus Armbruster assert arg_type and not arg_type.is_empty() 34fb0bc835SMarkus Armbruster argstr = '&arg, ' 35fb0bc835SMarkus Armbruster elif arg_type: 36fb0bc835SMarkus Armbruster assert not arg_type.variants 37fb0bc835SMarkus Armbruster for memb in arg_type.members: 38fb0bc835SMarkus Armbruster if memb.optional: 39fb0bc835SMarkus Armbruster argstr += 'arg.has_%s, ' % c_name(memb.name) 40fb0bc835SMarkus Armbruster argstr += 'arg.%s, ' % c_name(memb.name) 41fb0bc835SMarkus Armbruster 42fb0bc835SMarkus Armbruster lhs = '' 43fb0bc835SMarkus Armbruster if ret_type: 44fb0bc835SMarkus Armbruster lhs = 'retval = ' 45fb0bc835SMarkus Armbruster 46fb0bc835SMarkus Armbruster ret = mcgen(''' 47fb0bc835SMarkus Armbruster 48fb0bc835SMarkus Armbruster %(lhs)sqmp_%(c_name)s(%(args)s&err); 49fb0bc835SMarkus Armbruster''', 50fb0bc835SMarkus Armbruster c_name=c_name(name), args=argstr, lhs=lhs) 51fb0bc835SMarkus Armbruster if ret_type: 52fb0bc835SMarkus Armbruster ret += mcgen(''' 53fb0bc835SMarkus Armbruster if (err) { 54fb0bc835SMarkus Armbruster goto out; 55fb0bc835SMarkus Armbruster } 56fb0bc835SMarkus Armbruster 57fb0bc835SMarkus Armbruster qmp_marshal_output_%(c_name)s(retval, ret, &err); 58fb0bc835SMarkus Armbruster''', 59fb0bc835SMarkus Armbruster c_name=ret_type.c_name()) 60fb0bc835SMarkus Armbruster return ret 61fb0bc835SMarkus Armbruster 62fb0bc835SMarkus Armbruster 63fb0bc835SMarkus Armbrusterdef gen_marshal_output(ret_type): 64fb0bc835SMarkus Armbruster return mcgen(''' 65fb0bc835SMarkus Armbruster 66fb0bc835SMarkus Armbrusterstatic void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp) 67fb0bc835SMarkus Armbruster{ 68fb0bc835SMarkus Armbruster Error *err = NULL; 69fb0bc835SMarkus Armbruster Visitor *v; 70fb0bc835SMarkus Armbruster 71fb0bc835SMarkus Armbruster v = qobject_output_visitor_new(ret_out); 72fb0bc835SMarkus Armbruster visit_type_%(c_name)s(v, "unused", &ret_in, &err); 73fb0bc835SMarkus Armbruster if (!err) { 74fb0bc835SMarkus Armbruster visit_complete(v, ret_out); 75fb0bc835SMarkus Armbruster } 76fb0bc835SMarkus Armbruster error_propagate(errp, err); 77fb0bc835SMarkus Armbruster visit_free(v); 78fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 79fb0bc835SMarkus Armbruster visit_type_%(c_name)s(v, "unused", &ret_in, NULL); 80fb0bc835SMarkus Armbruster visit_free(v); 81fb0bc835SMarkus Armbruster} 82fb0bc835SMarkus Armbruster''', 83fb0bc835SMarkus Armbruster c_type=ret_type.c_type(), c_name=ret_type.c_name()) 84fb0bc835SMarkus Armbruster 85fb0bc835SMarkus Armbruster 86fb0bc835SMarkus Armbrusterdef build_marshal_proto(name): 87fb0bc835SMarkus Armbruster return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' 88fb0bc835SMarkus Armbruster % c_name(name)) 89fb0bc835SMarkus Armbruster 90fb0bc835SMarkus Armbruster 91fb0bc835SMarkus Armbrusterdef gen_marshal_decl(name): 92fb0bc835SMarkus Armbruster return mcgen(''' 93fb0bc835SMarkus Armbruster%(proto)s; 94fb0bc835SMarkus Armbruster''', 95fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 96fb0bc835SMarkus Armbruster 97fb0bc835SMarkus Armbruster 98fb0bc835SMarkus Armbrusterdef gen_marshal(name, arg_type, boxed, ret_type): 99fb0bc835SMarkus Armbruster have_args = arg_type and not arg_type.is_empty() 100fb0bc835SMarkus Armbruster 101fb0bc835SMarkus Armbruster ret = mcgen(''' 102fb0bc835SMarkus Armbruster 103fb0bc835SMarkus Armbruster%(proto)s 104fb0bc835SMarkus Armbruster{ 105fb0bc835SMarkus Armbruster Error *err = NULL; 106fb0bc835SMarkus Armbruster''', 107fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 108fb0bc835SMarkus Armbruster 109fb0bc835SMarkus Armbruster if ret_type: 110fb0bc835SMarkus Armbruster ret += mcgen(''' 111fb0bc835SMarkus Armbruster %(c_type)s retval; 112fb0bc835SMarkus Armbruster''', 113fb0bc835SMarkus Armbruster c_type=ret_type.c_type()) 114fb0bc835SMarkus Armbruster 115fb0bc835SMarkus Armbruster if have_args: 116fb0bc835SMarkus Armbruster visit_members = ('visit_type_%s_members(v, &arg, &err);' 117fb0bc835SMarkus Armbruster % arg_type.c_name()) 118fb0bc835SMarkus Armbruster ret += mcgen(''' 119fb0bc835SMarkus Armbruster Visitor *v; 120fb0bc835SMarkus Armbruster %(c_name)s arg = {0}; 121fb0bc835SMarkus Armbruster 122fb0bc835SMarkus Armbruster''', 123fb0bc835SMarkus Armbruster c_name=arg_type.c_name()) 124fb0bc835SMarkus Armbruster else: 125fb0bc835SMarkus Armbruster visit_members = '' 126fb0bc835SMarkus Armbruster ret += mcgen(''' 127fb0bc835SMarkus Armbruster Visitor *v = NULL; 128fb0bc835SMarkus Armbruster 129fb0bc835SMarkus Armbruster if (args) { 130fb0bc835SMarkus Armbruster''') 131fb0bc835SMarkus Armbruster push_indent() 132fb0bc835SMarkus Armbruster 133fb0bc835SMarkus Armbruster ret += mcgen(''' 134fb0bc835SMarkus Armbruster v = qobject_input_visitor_new(QOBJECT(args)); 135fb0bc835SMarkus Armbruster visit_start_struct(v, NULL, NULL, 0, &err); 136fb0bc835SMarkus Armbruster if (err) { 137fb0bc835SMarkus Armbruster goto out; 138fb0bc835SMarkus Armbruster } 139fb0bc835SMarkus Armbruster %(visit_members)s 140fb0bc835SMarkus Armbruster if (!err) { 141fb0bc835SMarkus Armbruster visit_check_struct(v, &err); 142fb0bc835SMarkus Armbruster } 143fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 144fb0bc835SMarkus Armbruster if (err) { 145fb0bc835SMarkus Armbruster goto out; 146fb0bc835SMarkus Armbruster } 147fb0bc835SMarkus Armbruster''', 148fb0bc835SMarkus Armbruster visit_members=visit_members) 149fb0bc835SMarkus Armbruster 150fb0bc835SMarkus Armbruster if not have_args: 151fb0bc835SMarkus Armbruster pop_indent() 152fb0bc835SMarkus Armbruster ret += mcgen(''' 153fb0bc835SMarkus Armbruster } 154fb0bc835SMarkus Armbruster''') 155fb0bc835SMarkus Armbruster 156fb0bc835SMarkus Armbruster ret += gen_call(name, arg_type, boxed, ret_type) 157fb0bc835SMarkus Armbruster 158fb0bc835SMarkus Armbruster ret += mcgen(''' 159fb0bc835SMarkus Armbruster 160fb0bc835SMarkus Armbrusterout: 161fb0bc835SMarkus Armbruster error_propagate(errp, err); 162fb0bc835SMarkus Armbruster visit_free(v); 163fb0bc835SMarkus Armbruster''') 164fb0bc835SMarkus Armbruster 165fb0bc835SMarkus Armbruster if have_args: 166fb0bc835SMarkus Armbruster visit_members = ('visit_type_%s_members(v, &arg, NULL);' 167fb0bc835SMarkus Armbruster % arg_type.c_name()) 168fb0bc835SMarkus Armbruster else: 169fb0bc835SMarkus Armbruster visit_members = '' 170fb0bc835SMarkus Armbruster ret += mcgen(''' 171fb0bc835SMarkus Armbruster if (args) { 172fb0bc835SMarkus Armbruster''') 173fb0bc835SMarkus Armbruster push_indent() 174fb0bc835SMarkus Armbruster 175fb0bc835SMarkus Armbruster ret += mcgen(''' 176fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 177fb0bc835SMarkus Armbruster visit_start_struct(v, NULL, NULL, 0, NULL); 178fb0bc835SMarkus Armbruster %(visit_members)s 179fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 180fb0bc835SMarkus Armbruster visit_free(v); 181fb0bc835SMarkus Armbruster''', 182fb0bc835SMarkus Armbruster visit_members=visit_members) 183fb0bc835SMarkus Armbruster 184fb0bc835SMarkus Armbruster if not have_args: 185fb0bc835SMarkus Armbruster pop_indent() 186fb0bc835SMarkus Armbruster ret += mcgen(''' 187fb0bc835SMarkus Armbruster } 188fb0bc835SMarkus Armbruster''') 189fb0bc835SMarkus Armbruster 190fb0bc835SMarkus Armbruster ret += mcgen(''' 191fb0bc835SMarkus Armbruster} 192fb0bc835SMarkus Armbruster''') 193fb0bc835SMarkus Armbruster return ret 194fb0bc835SMarkus Armbruster 195fb0bc835SMarkus Armbruster 196fb0bc835SMarkus Armbrusterdef gen_register_command(name, success_response): 197fb0bc835SMarkus Armbruster options = 'QCO_NO_OPTIONS' 198fb0bc835SMarkus Armbruster if not success_response: 199fb0bc835SMarkus Armbruster options = 'QCO_NO_SUCCESS_RESP' 200fb0bc835SMarkus Armbruster 201fb0bc835SMarkus Armbruster ret = mcgen(''' 202fb0bc835SMarkus Armbruster qmp_register_command(cmds, "%(name)s", 203fb0bc835SMarkus Armbruster qmp_marshal_%(c_name)s, %(opts)s); 204fb0bc835SMarkus Armbruster''', 205fb0bc835SMarkus Armbruster name=name, c_name=c_name(name), 206fb0bc835SMarkus Armbruster opts=options) 207fb0bc835SMarkus Armbruster return ret 208fb0bc835SMarkus Armbruster 209fb0bc835SMarkus Armbruster 210fb0bc835SMarkus Armbrusterdef gen_registry(registry, prefix): 211fb0bc835SMarkus Armbruster ret = mcgen(''' 212fb0bc835SMarkus Armbruster 213fb0bc835SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds) 214fb0bc835SMarkus Armbruster{ 215fb0bc835SMarkus Armbruster QTAILQ_INIT(cmds); 216fb0bc835SMarkus Armbruster 217fb0bc835SMarkus Armbruster''', 218fb0bc835SMarkus Armbruster c_prefix=c_name(prefix, protect=False)) 219fb0bc835SMarkus Armbruster ret += registry 220fb0bc835SMarkus Armbruster ret += mcgen(''' 221fb0bc835SMarkus Armbruster} 222fb0bc835SMarkus Armbruster''') 223fb0bc835SMarkus Armbruster return ret 224fb0bc835SMarkus Armbruster 225fb0bc835SMarkus Armbruster 226*252dc310SMarkus Armbrusterclass QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): 227fb0bc835SMarkus Armbruster 22871b3f045SMarkus Armbruster def __init__(self, prefix): 229*252dc310SMarkus Armbruster QAPISchemaModularCVisitor.__init__( 230*252dc310SMarkus Armbruster self, prefix, 'qapi-commands', 23171b3f045SMarkus Armbruster ' * Schema-defined QAPI/QMP commands', __doc__) 232fb0bc835SMarkus Armbruster self._regy = '' 233*252dc310SMarkus Armbruster self._visited_ret_types = {} 234*252dc310SMarkus Armbruster 235*252dc310SMarkus Armbruster # Temporary HACK: 236*252dc310SMarkus Armbruster def _module_basename(self, what, name): 237*252dc310SMarkus Armbruster basename = QAPISchemaModularCVisitor._module_basename(self, what, name) 238*252dc310SMarkus Armbruster if name == self._main_module: 239*252dc310SMarkus Armbruster return re.sub(r'qapi-commands', 'qmp-commands', basename) 240*252dc310SMarkus Armbruster return basename 241*252dc310SMarkus Armbruster 242*252dc310SMarkus Armbruster def _begin_module(self, name): 243*252dc310SMarkus Armbruster self._visited_ret_types[self._genc] = set() 24471b3f045SMarkus Armbruster self._genc.add(mcgen(''' 245fb0bc835SMarkus Armbruster#include "qemu/osdep.h" 246fb0bc835SMarkus Armbruster#include "qemu-common.h" 247fb0bc835SMarkus Armbruster#include "qemu/module.h" 248fb0bc835SMarkus Armbruster#include "qapi/visitor.h" 249fb0bc835SMarkus Armbruster#include "qapi/qmp/qdict.h" 250fb0bc835SMarkus Armbruster#include "qapi/qobject-output-visitor.h" 251fb0bc835SMarkus Armbruster#include "qapi/qobject-input-visitor.h" 252fb0bc835SMarkus Armbruster#include "qapi/dealloc-visitor.h" 253fb0bc835SMarkus Armbruster#include "qapi/error.h" 254fb0bc835SMarkus Armbruster#include "%(prefix)sqapi-types.h" 255fb0bc835SMarkus Armbruster#include "%(prefix)sqapi-visit.h" 256fb0bc835SMarkus Armbruster#include "%(prefix)sqmp-commands.h" 257fb0bc835SMarkus Armbruster 258fb0bc835SMarkus Armbruster''', 259*252dc310SMarkus Armbruster prefix=self._prefix)) 26071b3f045SMarkus Armbruster self._genh.add(mcgen(''' 261fb0bc835SMarkus Armbruster#include "%(prefix)sqapi-types.h" 262fb0bc835SMarkus Armbruster#include "qapi/qmp/dispatch.h" 263fb0bc835SMarkus Armbruster 264fb0bc835SMarkus Armbruster''', 265*252dc310SMarkus Armbruster prefix=self._prefix)) 266fb0bc835SMarkus Armbruster 26771b3f045SMarkus Armbruster def visit_end(self): 268*252dc310SMarkus Armbruster (genc, genh) = self._module[self._main_module] 269*252dc310SMarkus Armbruster genh.add(mcgen(''' 270*252dc310SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); 271*252dc310SMarkus Armbruster''', 272*252dc310SMarkus Armbruster c_prefix=c_name(self._prefix, protect=False))) 273*252dc310SMarkus Armbruster genc.add(gen_registry(self._regy, self._prefix)) 27471b3f045SMarkus Armbruster 27571b3f045SMarkus Armbruster def visit_command(self, name, info, arg_type, ret_type, 27671b3f045SMarkus Armbruster gen, success_response, boxed): 27771b3f045SMarkus Armbruster if not gen: 27871b3f045SMarkus Armbruster return 27971b3f045SMarkus Armbruster self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) 280*252dc310SMarkus Armbruster if ret_type and ret_type not in self._visited_ret_types[self._genc]: 281*252dc310SMarkus Armbruster self._visited_ret_types[self._genc].add(ret_type) 28271b3f045SMarkus Armbruster self._genc.add(gen_marshal_output(ret_type)) 28371b3f045SMarkus Armbruster self._genh.add(gen_marshal_decl(name)) 28471b3f045SMarkus Armbruster self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) 28571b3f045SMarkus Armbruster self._regy += gen_register_command(name, success_response) 28671b3f045SMarkus Armbruster 28771b3f045SMarkus Armbruster 28871b3f045SMarkus Armbrusterdef gen_commands(schema, output_dir, prefix): 289fb0bc835SMarkus Armbruster vis = QAPISchemaGenCommandVisitor(prefix) 290fb0bc835SMarkus Armbruster schema.visit(vis) 29171b3f045SMarkus Armbruster vis.write(output_dir) 292