xref: /qemu/scripts/qapi/events.py (revision 2114f5a98d0d80774306279e1694de074ca86aa0)
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 *
14import os
15import errno
16
17def _generate_event_api_name(event_name, params):
18    api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
19    l = len(api_name)
20
21    if params:
22        for argname, argentry, optional in parse_args(params):
23            if optional:
24                api_name += "bool has_%s,\n" % c_name(argname)
25                api_name += "".ljust(l)
26
27            api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
28                                      c_name(argname))
29            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
94        for argname, argentry, optional in parse_args(params):
95            if optional:
96                ret += mcgen("""
97    if (has_%(var)s) {
98""",
99                             var = c_name(argname))
100                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,
114                         var = c_name(argname),
115                         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
178    enum_max_value = c_enum_const(event_enum_name, "MAX")
179    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
220c_file = 'qapi-event.c'
221h_file = 'qapi-event.h'
222
223(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
224
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
313        event_enum_value = c_enum_const(event_enum_name, event_name)
314        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()
335