qapi: Factor parse_command_line() out of the generators
[qemu.git] / scripts / qapi-event.py
blobbc5ca4ad119aa9354b30528b1d4ef66f4dfb3c41
2 # QAPI event generator
4 # Copyright (c) 2014 Wenchao Xia
6 # Authors:
7 # Wenchao Xia <wenchaoqemu@gmail.com>
9 # This work is licensed under the terms of the GNU GPL, version 2.
10 # See the COPYING file in the top-level directory.
12 from ordereddict import OrderedDict
13 from qapi import *
14 import os
15 import errno
17 def _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)
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)
27 api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
28 c_name(argname))
29 api_name += "".ljust(l)
31 api_name += "Error **errp)"
32 return api_name;
35 # Following are the core functions that generate C APIs to emit event.
37 def generate_event_declaration(api_name):
38 return mcgen('''
40 %(api_name)s;
41 ''',
42 api_name = api_name)
44 def generate_event_implement(api_name, event_name, params):
45 # step 1: declare any variables
46 ret = mcgen("""
48 %(api_name)s
50 QDict *qmp;
51 Error *local_err = NULL;
52 QMPEventFuncEmit emit;
53 """,
54 api_name = api_name)
56 if params:
57 ret += mcgen("""
58 QmpOutputVisitor *qov;
59 Visitor *v;
60 QObject *obj;
62 """)
64 # step 2: check emit function, create a dict
65 ret += mcgen("""
66 emit = qmp_event_get_func_emit();
67 if (!emit) {
68 return;
71 qmp = qmp_event_build_dict("%(event_name)s");
73 """,
74 event_name = event_name)
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);
82 v = qmp_output_get_visitor(qov);
83 g_assert(v);
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;
91 """,
92 event_name = event_name)
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()
102 if argentry == "str":
103 var_type = "(char **)"
104 else:
105 var_type = ""
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;
112 """,
113 var_type = var_type,
114 var = c_name(argname),
115 type = type_name(argentry),
116 name = argname)
118 if optional:
119 pop_indent()
120 ret += mcgen("""
122 """)
124 ret += mcgen("""
126 visit_end_struct(v, &local_err);
127 if (local_err) {
128 goto clean;
131 obj = qmp_output_get_qobject(qov);
132 g_assert(obj != NULL);
134 qdict_put_obj(qmp, "data", obj);
135 """)
137 # step 4: call qmp event api
138 ret += mcgen("""
139 emit(%(event_enum_value)s, qmp, &local_err);
141 """,
142 event_enum_value = event_enum_value)
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);
154 """)
156 return ret
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.
164 def generate_event_enum_decl(event_enum_name, event_enum_values):
165 lookup_decl = mcgen('''
167 extern const char *%(event_enum_name)s_lookup[];
168 ''',
169 event_enum_name = event_enum_name)
171 enum_decl = mcgen('''
172 typedef enum %(event_enum_name)s
174 ''',
175 event_enum_name = event_enum_name)
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 ]
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
190 enum_decl += mcgen('''
191 } %(event_enum_name)s;
192 ''',
193 event_enum_name = event_enum_name)
195 return lookup_decl + enum_decl
197 def generate_event_enum_lookup(event_enum_name, event_enum_strings):
198 ret = mcgen('''
200 const char *%(event_enum_name)s_lookup[] = {
201 ''',
202 event_enum_name = event_enum_name)
204 i = 0
205 for string in event_enum_strings:
206 ret += mcgen('''
207 "%(string)s",
208 ''',
209 string = string)
211 ret += mcgen('''
212 NULL,
214 ''')
215 return ret
218 # Start the real job
220 c_file = 'qapi-event.c'
221 h_file = 'qapi-event.h'
223 (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
225 c_file = output_dir + prefix + c_file
226 h_file = output_dir + prefix + h_file
228 try:
229 os.makedirs(output_dir)
230 except os.error, e:
231 if e.errno != errno.EEXIST:
232 raise
234 def maybe_open(really, name, opt):
235 if really:
236 return open(name, opt)
237 else:
238 import StringIO
239 return StringIO.StringIO()
241 fdef = maybe_open(do_c, c_file, 'w')
242 fdecl = maybe_open(do_h, h_file, 'w')
244 fdef.write(mcgen('''
245 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
248 * schema-defined QAPI event functions
250 * Copyright (c) 2014 Wenchao Xia
252 * Authors:
253 * Wenchao Xia <wenchaoqemu@gmail.com>
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.
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"
266 ''',
267 prefix=prefix, header=basename(h_file)))
269 fdecl.write(mcgen('''
270 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
273 * schema-defined QAPI event functions
275 * Copyright (c) 2014 Wenchao Xia
277 * Authors:
278 * Wenchao Xia <wenchaoqemu@gmail.com>
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.
285 #ifndef %(guard)s
286 #define %(guard)s
288 #include "qapi/error.h"
289 #include "qapi/qmp/qdict.h"
290 #include "%(prefix)sqapi-types.h"
292 ''',
293 prefix=prefix, guard=guardname(h_file)))
295 exprs = parse_schema(input_file)
297 event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
298 event_enum_values = []
299 event_enum_strings = []
301 for 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
308 api_name = _generate_event_api_name(event_name, params)
309 ret = generate_event_declaration(api_name)
310 fdecl.write(ret)
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)
317 # Record it, and generate enum later
318 event_enum_values.append(event_enum_value)
319 event_enum_strings.append(event_name)
321 ret = generate_event_enum_decl(event_enum_name, event_enum_values)
322 fdecl.write(ret)
323 ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
324 fdef.write(ret)
326 fdecl.write('''
327 #endif
328 ''')
330 fdecl.flush()
331 fdecl.close()
333 fdef.flush()
334 fdef.close()