blob: bc5ca4ad119aa9354b30528b1d4ef66f4dfb3c41 [file] [log] [blame]
Wenchao Xia21cd70d2014-06-18 08:43:28 +02001#
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 *
Wenchao Xia21cd70d2014-06-18 08:43:28 +020014import os
Wenchao Xia21cd70d2014-06-18 08:43:28 +020015import errno
16
17def _generate_event_api_name(event_name, params):
Eric Blake18df5152015-05-14 06:50:48 -060018 api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
Wenchao Xia21cd70d2014-06-18 08:43:28 +020019 l = len(api_name)
20
21 if params:
Eric Blake6b5abc72015-05-04 09:05:33 -060022 for argname, argentry, optional in parse_args(params):
Wenchao Xia21cd70d2014-06-18 08:43:28 +020023 if optional:
Eric Blake18df5152015-05-14 06:50:48 -060024 api_name += "bool has_%s,\n" % c_name(argname)
Wenchao Xia21cd70d2014-06-18 08:43:28 +020025 api_name += "".ljust(l)
26
Wenchao Xiad6f9c822014-06-24 16:33:59 -070027 api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
Eric Blake18df5152015-05-14 06:50:48 -060028 c_name(argname))
Wenchao Xia21cd70d2014-06-18 08:43:28 +020029 api_name += "".ljust(l)
30
31 api_name += "Error **errp)"
32 return api_name;
33
34
35# Following are the core functions that generate C APIs to emit event.
36
37def generate_event_declaration(api_name):
38 return mcgen('''
39
40%(api_name)s;
41''',
42 api_name = api_name)
43
44def generate_event_implement(api_name, event_name, params):
45 # step 1: declare any variables
46 ret = mcgen("""
47
48%(api_name)s
49{
50 QDict *qmp;
51 Error *local_err = NULL;
52 QMPEventFuncEmit emit;
53""",
54 api_name = api_name)
55
56 if params:
57 ret += mcgen("""
58 QmpOutputVisitor *qov;
59 Visitor *v;
60 QObject *obj;
61
62""")
63
64 # step 2: check emit function, create a dict
65 ret += mcgen("""
66 emit = qmp_event_get_func_emit();
67 if (!emit) {
68 return;
69 }
70
71 qmp = qmp_event_build_dict("%(event_name)s");
72
73""",
74 event_name = event_name)
75
76 # step 3: visit the params if params != None
77 if params:
78 ret += mcgen("""
79 qov = qmp_output_visitor_new();
80 g_assert(qov);
81
82 v = qmp_output_get_visitor(qov);
83 g_assert(v);
84
85 /* Fake visit, as if all members are under a structure */
86 visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
87 if (local_err) {
88 goto clean;
89 }
90
91""",
92 event_name = event_name)
93
Eric Blake6b5abc72015-05-04 09:05:33 -060094 for argname, argentry, optional in parse_args(params):
Wenchao Xia21cd70d2014-06-18 08:43:28 +020095 if optional:
96 ret += mcgen("""
97 if (has_%(var)s) {
98""",
Eric Blake18df5152015-05-14 06:50:48 -060099 var = c_name(argname))
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200100 push_indent()
101
102 if argentry == "str":
103 var_type = "(char **)"
104 else:
105 var_type = ""
106
107 ret += mcgen("""
108 visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
109 if (local_err) {
110 goto clean;
111 }
112""",
113 var_type = var_type,
Eric Blake18df5152015-05-14 06:50:48 -0600114 var = c_name(argname),
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200115 type = type_name(argentry),
116 name = argname)
117
118 if optional:
119 pop_indent()
120 ret += mcgen("""
121 }
122""")
123
124 ret += mcgen("""
125
126 visit_end_struct(v, &local_err);
127 if (local_err) {
128 goto clean;
129 }
130
131 obj = qmp_output_get_qobject(qov);
132 g_assert(obj != NULL);
133
134 qdict_put_obj(qmp, "data", obj);
135""")
136
137 # step 4: call qmp event api
138 ret += mcgen("""
139 emit(%(event_enum_value)s, qmp, &local_err);
140
141""",
142 event_enum_value = event_enum_value)
143
144 # step 5: clean up
145 if params:
146 ret += mcgen("""
147 clean:
148 qmp_output_visitor_cleanup(qov);
149""")
150 ret += mcgen("""
151 error_propagate(errp, local_err);
152 QDECREF(qmp);
153}
154""")
155
156 return ret
157
158
159# Following are the functions that generate an enum type for all defined
160# events, similar to qapi-types.py. Here we already have enum name and
161# values which were generated before and recorded in event_enum_*. It also
162# works around the issue that "import qapi-types" can't work.
163
164def generate_event_enum_decl(event_enum_name, event_enum_values):
165 lookup_decl = mcgen('''
166
167extern const char *%(event_enum_name)s_lookup[];
168''',
169 event_enum_name = event_enum_name)
170
171 enum_decl = mcgen('''
172typedef enum %(event_enum_name)s
173{
174''',
175 event_enum_name = event_enum_name)
176
177 # append automatically generated _MAX value
Markus Armbruster7c81c612015-05-14 06:50:50 -0600178 enum_max_value = c_enum_const(event_enum_name, "MAX")
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200179 enum_values = event_enum_values + [ enum_max_value ]
180
181 i = 0
182 for value in enum_values:
183 enum_decl += mcgen('''
184 %(value)s = %(i)d,
185''',
186 value = value,
187 i = i)
188 i += 1
189
190 enum_decl += mcgen('''
191} %(event_enum_name)s;
192''',
193 event_enum_name = event_enum_name)
194
195 return lookup_decl + enum_decl
196
197def generate_event_enum_lookup(event_enum_name, event_enum_strings):
198 ret = mcgen('''
199
200const char *%(event_enum_name)s_lookup[] = {
201''',
202 event_enum_name = event_enum_name)
203
204 i = 0
205 for string in event_enum_strings:
206 ret += mcgen('''
207 "%(string)s",
208''',
209 string = string)
210
211 ret += mcgen('''
212 NULL,
213};
214''')
215 return ret
216
217
218# Start the real job
219
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200220c_file = 'qapi-event.c'
221h_file = 'qapi-event.h'
222
Markus Armbruster2114f5a2015-04-02 13:12:21 +0200223(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200224
225c_file = output_dir + prefix + c_file
226h_file = output_dir + prefix + h_file
227
228try:
229 os.makedirs(output_dir)
230except os.error, e:
231 if e.errno != errno.EEXIST:
232 raise
233
234def maybe_open(really, name, opt):
235 if really:
236 return open(name, opt)
237 else:
238 import StringIO
239 return StringIO.StringIO()
240
241fdef = maybe_open(do_c, c_file, 'w')
242fdecl = maybe_open(do_h, h_file, 'w')
243
244fdef.write(mcgen('''
245/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
246
247/*
248 * schema-defined QAPI event functions
249 *
250 * Copyright (c) 2014 Wenchao Xia
251 *
252 * Authors:
253 * Wenchao Xia <wenchaoqemu@gmail.com>
254 *
255 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
256 * See the COPYING.LIB file in the top-level directory.
257 *
258 */
259
260#include "qemu-common.h"
261#include "%(header)s"
262#include "%(prefix)sqapi-visit.h"
263#include "qapi/qmp-output-visitor.h"
264#include "qapi/qmp-event.h"
265
266''',
267 prefix=prefix, header=basename(h_file)))
268
269fdecl.write(mcgen('''
270/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
271
272/*
273 * schema-defined QAPI event functions
274 *
275 * Copyright (c) 2014 Wenchao Xia
276 *
277 * Authors:
278 * Wenchao Xia <wenchaoqemu@gmail.com>
279 *
280 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
281 * See the COPYING.LIB file in the top-level directory.
282 *
283 */
284
285#ifndef %(guard)s
286#define %(guard)s
287
288#include "qapi/error.h"
289#include "qapi/qmp/qdict.h"
290#include "%(prefix)sqapi-types.h"
291
292''',
293 prefix=prefix, guard=guardname(h_file)))
294
295exprs = parse_schema(input_file)
296
297event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
298event_enum_values = []
299event_enum_strings = []
300
301for expr in exprs:
302 if expr.has_key('event'):
303 event_name = expr['event']
304 params = expr.get('data')
305 if params and len(params) == 0:
306 params = None
307
308 api_name = _generate_event_api_name(event_name, params)
309 ret = generate_event_declaration(api_name)
310 fdecl.write(ret)
311
312 # We need an enum value per event
Markus Armbruster7c81c612015-05-14 06:50:50 -0600313 event_enum_value = c_enum_const(event_enum_name, event_name)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200314 ret = generate_event_implement(api_name, event_name, params)
315 fdef.write(ret)
316
317 # Record it, and generate enum later
318 event_enum_values.append(event_enum_value)
319 event_enum_strings.append(event_name)
320
321ret = generate_event_enum_decl(event_enum_name, event_enum_values)
322fdecl.write(ret)
323ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
324fdef.write(ret)
325
326fdecl.write('''
327#endif
328''')
329
330fdecl.flush()
331fdecl.close()
332
333fdef.flush()
334fdef.close()