1# 2# QAPI event generator 3# 4# Copyright (c) 2014 Wenchao Xia 5# Copyright (c) 2015-2016 Red Hat Inc. 6# 7# Authors: 8# Wenchao Xia <wenchaoqemu@gmail.com> 9# Markus Armbruster <armbru@redhat.com> 10# 11# This work is licensed under the terms of the GNU GPL, version 2. 12# See the COPYING file in the top-level directory. 13 14from qapi import * 15 16 17def build_event_send_proto(name, arg_type, boxed): 18 return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 19 'c_name': c_name(name.lower()), 20 'param': build_params(arg_type, boxed, 'Error **errp')} 21 22 23def gen_event_send_decl(name, arg_type, boxed): 24 return mcgen(''' 25 26%(proto)s; 27''', 28 proto=build_event_send_proto(name, arg_type, boxed)) 29 30 31# Declare and initialize an object 'qapi' using parameters from build_params() 32def gen_param_var(typ): 33 assert not typ.variants 34 ret = mcgen(''' 35 %(c_name)s param = { 36''', 37 c_name=typ.c_name()) 38 sep = ' ' 39 for memb in typ.members: 40 ret += sep 41 sep = ', ' 42 if memb.optional: 43 ret += 'has_' + c_name(memb.name) + sep 44 if memb.type.name == 'str': 45 # Cast away const added in build_params() 46 ret += '(char *)' 47 ret += c_name(memb.name) 48 ret += mcgen(''' 49 50 }; 51''') 52 if not typ.is_implicit(): 53 ret += mcgen(''' 54 %(c_name)s *arg = ¶m; 55''', 56 c_name=typ.c_name()) 57 return ret 58 59 60def gen_event_send(name, arg_type, boxed): 61 # FIXME: Our declaration of local variables (and of 'errp' in the 62 # parameter list) can collide with exploded members of the event's 63 # data type passed in as parameters. If this collision ever hits in 64 # practice, we can rename our local variables with a leading _ prefix, 65 # or split the code into a wrapper function that creates a boxed 66 # 'param' object then calls another to do the real work. 67 ret = mcgen(''' 68 69%(proto)s 70{ 71 QDict *qmp; 72 Error *err = NULL; 73 QMPEventFuncEmit emit; 74''', 75 proto=build_event_send_proto(name, arg_type, boxed)) 76 77 if arg_type and not arg_type.is_empty(): 78 ret += mcgen(''' 79 QObject *obj; 80 Visitor *v; 81''') 82 if not boxed: 83 ret += gen_param_var(arg_type) 84 else: 85 assert not boxed 86 87 ret += mcgen(''' 88 89 emit = qmp_event_get_func_emit(); 90 if (!emit) { 91 return; 92 } 93 94 qmp = qmp_event_build_dict("%(name)s"); 95 96''', 97 name=name) 98 99 if arg_type and not arg_type.is_empty(): 100 ret += mcgen(''' 101 v = qobject_output_visitor_new(&obj); 102''') 103 if not arg_type.is_implicit(): 104 ret += mcgen(''' 105 visit_type_%(c_name)s(v, "%(name)s", &arg, &err); 106''', 107 name=name, c_name=arg_type.c_name()) 108 else: 109 ret += mcgen(''' 110 111 visit_start_struct(v, "%(name)s", NULL, 0, &err); 112 if (err) { 113 goto out; 114 } 115 visit_type_%(c_name)s_members(v, ¶m, &err); 116 if (!err) { 117 visit_check_struct(v, &err); 118 } 119 visit_end_struct(v, NULL); 120''', 121 name=name, c_name=arg_type.c_name()) 122 ret += mcgen(''' 123 if (err) { 124 goto out; 125 } 126 127 visit_complete(v, &obj); 128 qdict_put_obj(qmp, "data", obj); 129''') 130 131 ret += mcgen(''' 132 emit(%(c_enum)s, qmp, &err); 133 134''', 135 c_enum=c_enum_const(event_enum_name, name)) 136 137 if arg_type and not arg_type.is_empty(): 138 ret += mcgen(''' 139out: 140 visit_free(v); 141''') 142 ret += mcgen(''' 143 error_propagate(errp, err); 144 QDECREF(qmp); 145} 146''') 147 return ret 148 149 150class QAPISchemaGenEventVisitor(QAPISchemaVisitor): 151 def __init__(self): 152 self.decl = None 153 self.defn = None 154 self._event_names = None 155 156 def visit_begin(self, schema): 157 self.decl = '' 158 self.defn = '' 159 self._event_names = [] 160 161 def visit_end(self): 162 self.decl += gen_enum(event_enum_name, self._event_names) 163 self.defn += gen_enum_lookup(event_enum_name, self._event_names) 164 self._event_names = None 165 166 def visit_event(self, name, info, arg_type, boxed): 167 self.decl += gen_event_send_decl(name, arg_type, boxed) 168 self.defn += gen_event_send(name, arg_type, boxed) 169 self._event_names.append(name) 170 171 172(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() 173 174c_comment = ''' 175/* 176 * schema-defined QAPI event functions 177 * 178 * Copyright (c) 2014 Wenchao Xia 179 * 180 * Authors: 181 * Wenchao Xia <wenchaoqemu@gmail.com> 182 * 183 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 184 * See the COPYING.LIB file in the top-level directory. 185 * 186 */ 187''' 188h_comment = ''' 189/* 190 * schema-defined QAPI event functions 191 * 192 * Copyright (c) 2014 Wenchao Xia 193 * 194 * Authors: 195 * Wenchao Xia <wenchaoqemu@gmail.com> 196 * 197 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 198 * See the COPYING.LIB file in the top-level directory. 199 * 200 */ 201''' 202 203(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, 204 'qapi-event.c', 'qapi-event.h', 205 c_comment, h_comment) 206 207fdef.write(mcgen(''' 208#include "qemu/osdep.h" 209#include "qemu-common.h" 210#include "%(prefix)sqapi-event.h" 211#include "%(prefix)sqapi-visit.h" 212#include "qapi/error.h" 213#include "qapi/qobject-output-visitor.h" 214#include "qapi/qmp-event.h" 215 216''', 217 prefix=prefix)) 218 219fdecl.write(mcgen(''' 220#include "qapi/util.h" 221#include "qapi/qmp/qdict.h" 222#include "%(prefix)sqapi-types.h" 223 224''', 225 prefix=prefix)) 226 227event_enum_name = c_name(prefix + 'QAPIEvent', protect=False) 228 229schema = QAPISchema(input_file) 230gen = QAPISchemaGenEventVisitor() 231schema.visit(gen) 232fdef.write(gen.defn) 233fdecl.write(gen.decl) 234 235close_output(fdef, fdecl) 236