1# 2# QAPI event generator 3# 4# Copyright (c) 2014 Wenchao Xia 5# 6# Authors: 7# Wenchao Xia <wenchaoqemu@gmail.com> 8# 9# This work is licensed under the terms of the GNU GPL, version 2. 10# See the COPYING file in the top-level directory. 11 12from ordereddict import OrderedDict 13from qapi import * 14 15def _generate_event_api_name(event_name, params): 16 api_name = "void qapi_event_send_%s(" % c_name(event_name).lower(); 17 l = len(api_name) 18 19 if params: 20 for argname, argentry, optional in parse_args(params): 21 if optional: 22 api_name += "bool has_%s,\n" % c_name(argname) 23 api_name += "".ljust(l) 24 25 api_name += "%s %s,\n" % (c_type(argentry, is_param=True), 26 c_name(argname)) 27 api_name += "".ljust(l) 28 29 api_name += "Error **errp)" 30 return api_name; 31 32 33# Following are the core functions that generate C APIs to emit event. 34 35def generate_event_declaration(api_name): 36 return mcgen(''' 37 38%(api_name)s; 39''', 40 api_name = api_name) 41 42def generate_event_implement(api_name, event_name, params): 43 # step 1: declare any variables 44 ret = mcgen(""" 45 46%(api_name)s 47{ 48 QDict *qmp; 49 Error *local_err = NULL; 50 QMPEventFuncEmit emit; 51""", 52 api_name = api_name) 53 54 if params: 55 ret += mcgen(""" 56 QmpOutputVisitor *qov; 57 Visitor *v; 58 QObject *obj; 59 60""") 61 62 # step 2: check emit function, create a dict 63 ret += mcgen(""" 64 emit = qmp_event_get_func_emit(); 65 if (!emit) { 66 return; 67 } 68 69 qmp = qmp_event_build_dict("%(event_name)s"); 70 71""", 72 event_name = event_name) 73 74 # step 3: visit the params if params != None 75 if params: 76 ret += mcgen(""" 77 qov = qmp_output_visitor_new(); 78 g_assert(qov); 79 80 v = qmp_output_get_visitor(qov); 81 g_assert(v); 82 83 /* Fake visit, as if all members are under a structure */ 84 visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err); 85 if (local_err) { 86 goto clean; 87 } 88 89""", 90 event_name = event_name) 91 92 for argname, argentry, optional in parse_args(params): 93 if optional: 94 ret += mcgen(""" 95 if (has_%(var)s) { 96""", 97 var = c_name(argname)) 98 push_indent() 99 100 if argentry == "str": 101 var_type = "(char **)" 102 else: 103 var_type = "" 104 105 ret += mcgen(""" 106 visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err); 107 if (local_err) { 108 goto clean; 109 } 110""", 111 var_type = var_type, 112 var = c_name(argname), 113 type = type_name(argentry), 114 name = argname) 115 116 if optional: 117 pop_indent() 118 ret += mcgen(""" 119 } 120""") 121 122 ret += mcgen(""" 123 124 visit_end_struct(v, &local_err); 125 if (local_err) { 126 goto clean; 127 } 128 129 obj = qmp_output_get_qobject(qov); 130 g_assert(obj != NULL); 131 132 qdict_put_obj(qmp, "data", obj); 133""") 134 135 # step 4: call qmp event api 136 ret += mcgen(""" 137 emit(%(event_enum_value)s, qmp, &local_err); 138 139""", 140 event_enum_value = event_enum_value) 141 142 # step 5: clean up 143 if params: 144 ret += mcgen(""" 145 clean: 146 qmp_output_visitor_cleanup(qov); 147""") 148 ret += mcgen(""" 149 error_propagate(errp, local_err); 150 QDECREF(qmp); 151} 152""") 153 154 return ret 155 156 157# Following are the functions that generate an enum type for all defined 158# events, similar to qapi-types.py. Here we already have enum name and 159# values which were generated before and recorded in event_enum_*. It also 160# works around the issue that "import qapi-types" can't work. 161 162def generate_event_enum_decl(event_enum_name, event_enum_values): 163 lookup_decl = mcgen(''' 164 165extern const char *%(event_enum_name)s_lookup[]; 166''', 167 event_enum_name = event_enum_name) 168 169 enum_decl = mcgen(''' 170typedef enum %(event_enum_name)s 171{ 172''', 173 event_enum_name = event_enum_name) 174 175 # append automatically generated _MAX value 176 enum_max_value = c_enum_const(event_enum_name, "MAX") 177 enum_values = event_enum_values + [ enum_max_value ] 178 179 i = 0 180 for value in enum_values: 181 enum_decl += mcgen(''' 182 %(value)s = %(i)d, 183''', 184 value = value, 185 i = i) 186 i += 1 187 188 enum_decl += mcgen(''' 189} %(event_enum_name)s; 190''', 191 event_enum_name = event_enum_name) 192 193 return lookup_decl + enum_decl 194 195def generate_event_enum_lookup(event_enum_name, event_enum_strings): 196 ret = mcgen(''' 197 198const char *%(event_enum_name)s_lookup[] = { 199''', 200 event_enum_name = event_enum_name) 201 202 i = 0 203 for string in event_enum_strings: 204 ret += mcgen(''' 205 "%(string)s", 206''', 207 string = string) 208 209 ret += mcgen(''' 210 NULL, 211}; 212''') 213 return ret 214 215(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() 216 217c_comment = ''' 218/* 219 * schema-defined QAPI event functions 220 * 221 * Copyright (c) 2014 Wenchao Xia 222 * 223 * Authors: 224 * Wenchao Xia <wenchaoqemu@gmail.com> 225 * 226 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 227 * See the COPYING.LIB file in the top-level directory. 228 * 229 */ 230''' 231h_comment = ''' 232/* 233 * schema-defined QAPI event functions 234 * 235 * Copyright (c) 2014 Wenchao Xia 236 * 237 * Authors: 238 * Wenchao Xia <wenchaoqemu@gmail.com> 239 * 240 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 241 * See the COPYING.LIB file in the top-level directory. 242 * 243 */ 244''' 245 246(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, 247 'qapi-event.c', 'qapi-event.h', 248 c_comment, h_comment) 249 250fdef.write(mcgen(''' 251#include "qemu-common.h" 252#include "%(prefix)sqapi-event.h" 253#include "%(prefix)sqapi-visit.h" 254#include "qapi/qmp-output-visitor.h" 255#include "qapi/qmp-event.h" 256 257''', 258 prefix=prefix)) 259 260fdecl.write(mcgen(''' 261#include "qapi/error.h" 262#include "qapi/qmp/qdict.h" 263#include "%(prefix)sqapi-types.h" 264 265''', 266 prefix=prefix)) 267 268exprs = parse_schema(input_file) 269 270event_enum_name = c_name(prefix + "QAPIEvent", protect=False) 271event_enum_values = [] 272event_enum_strings = [] 273 274for expr in exprs: 275 if expr.has_key('event'): 276 event_name = expr['event'] 277 params = expr.get('data') 278 if params and len(params) == 0: 279 params = None 280 281 api_name = _generate_event_api_name(event_name, params) 282 ret = generate_event_declaration(api_name) 283 fdecl.write(ret) 284 285 # We need an enum value per event 286 event_enum_value = c_enum_const(event_enum_name, event_name) 287 ret = generate_event_implement(api_name, event_name, params) 288 fdef.write(ret) 289 290 # Record it, and generate enum later 291 event_enum_values.append(event_enum_value) 292 event_enum_strings.append(event_name) 293 294ret = generate_event_enum_decl(event_enum_name, event_enum_values) 295fdecl.write(ret) 296ret = generate_event_enum_lookup(event_enum_name, event_enum_strings) 297fdef.write(ret) 298 299close_output(fdef, fdecl) 300