]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi-visit.py
qapi: Replace dirty is_c_ptr() by method c_null()
[mirror_qemu.git] / scripts / qapi-visit.py
CommitLineData
06d64c62
MR
1#
2# QAPI visitor generator
3#
4# Copyright IBM, Corp. 2011
6540e9f3 5# Copyright (C) 2014-2015 Red Hat, Inc.
06d64c62
MR
6#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
9# Michael Roth <mdroth@linux.vnet.ibm.com>
297a3646 10# Markus Armbruster <armbru@redhat.com>
06d64c62 11#
678e48a2
MA
12# This work is licensed under the terms of the GNU GPL, version 2.
13# See the COPYING file in the top-level directory.
06d64c62 14
06d64c62 15from qapi import *
297a3646 16import re
06d64c62 17
8c07eddc 18implicit_structs_seen = set()
8c3f8e77 19struct_fields_seen = set()
be3c7717
MA
20
21def generate_visit_implicit_struct(type):
8c07eddc 22 if type in implicit_structs_seen:
be3c7717 23 return ''
8c07eddc 24 implicit_structs_seen.add(type)
8c3f8e77 25 ret = ''
441cbac0 26 if type.name not in struct_fields_seen:
8c3f8e77
MA
27 # Need a forward declaration
28 ret += mcgen('''
29
30static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
31''',
441cbac0 32 c_type=type.c_name())
8c3f8e77
MA
33
34 ret += mcgen('''
be3c7717
MA
35
36static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
37{
38 Error *err = NULL;
39
40 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
41 if (!err) {
297a3646 42 visit_type_%(c_type)s_fields(m, obj, errp);
be3c7717
MA
43 visit_end_implicit_struct(m, &err);
44 }
45 error_propagate(errp, err);
46}
47''',
441cbac0 48 c_type=type.c_name())
8c3f8e77 49 return ret
be3c7717 50
a82b982e 51def generate_visit_struct_fields(name, members, base = None):
8c3f8e77
MA
52 struct_fields_seen.add(name)
53
d131c897 54 ret = ''
50f2bdc7 55
be3c7717
MA
56 if base:
57 ret += generate_visit_implicit_struct(base)
58
50f2bdc7
KW
59 ret += mcgen('''
60
a82b982e 61static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
50f2bdc7
KW
62{
63 Error *err = NULL;
3a864e7c 64
50f2bdc7 65''',
83a02706 66 name=c_name(name))
50f2bdc7 67 push_indent()
d195325b 68
622f557f
KW
69 if base:
70 ret += mcgen('''
a82b982e 71visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
297a3646
MA
72if (err) {
73 goto out;
74}
622f557f 75''',
441cbac0 76 type=base.c_name(), c_name=c_name('base'))
622f557f 77
441cbac0
MA
78 for memb in members:
79 if memb.optional:
06d64c62 80 ret += mcgen('''
a82b982e
EB
81visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
82if (!err && (*obj)->has_%(c_name)s) {
06d64c62 83''',
441cbac0 84 c_name=c_name(memb.name), name=memb.name)
06d64c62
MR
85 push_indent()
86
6b5abc7d 87 ret += mcgen('''
a82b982e 88visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
06d64c62 89''',
441cbac0
MA
90 type=memb.type.c_name(), c_name=c_name(memb.name),
91 name=memb.name)
06d64c62 92
441cbac0 93 if memb.optional:
06d64c62
MR
94 pop_indent()
95 ret += mcgen('''
96}
297a3646
MA
97''')
98 ret += mcgen('''
99if (err) {
100 goto out;
101}
d195325b
PB
102''')
103
50f2bdc7 104 pop_indent()
297a3646
MA
105 if re.search('^ *goto out\\;', ret, re.MULTILINE):
106 ret += mcgen('''
50f2bdc7 107
297a3646
MA
108out:
109''')
110 ret += mcgen('''
50f2bdc7
KW
111 error_propagate(errp, err);
112}
113''')
d131c897
KW
114 return ret
115
116
5aa05d3f 117def generate_visit_struct_body(name):
2f52e205
EB
118 # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
119 # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
120 # rather than leaving it non-NULL. As currently written, the caller must
121 # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
d131c897 122 ret = mcgen('''
297a3646
MA
123 Error *err = NULL;
124
83a02706 125 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
126 if (!err) {
127 if (*obj) {
83a02706 128 visit_type_%(c_name)s_fields(m, obj, errp);
297a3646
MA
129 }
130 visit_end_struct(m, &err);
50f2bdc7 131 }
297a3646 132 error_propagate(errp, err);
50f2bdc7 133''',
83a02706 134 name=name, c_name=c_name(name))
d195325b 135
06d64c62
MR
136 return ret
137
441cbac0 138def gen_visit_struct(name, base, members):
a82b982e 139 ret = generate_visit_struct_fields(name, members, base)
50f2bdc7
KW
140
141 ret += mcgen('''
06d64c62 142
638ca8ad 143void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 144{
06d64c62 145''',
83a02706 146 name=c_name(name))
d195325b 147
5aa05d3f 148 ret += generate_visit_struct_body(name)
06d64c62
MR
149
150 ret += mcgen('''
06d64c62
MR
151}
152''')
153 return ret
154
441cbac0 155def gen_visit_list(name, element_type):
06d64c62
MR
156 return mcgen('''
157
441cbac0 158void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 159{
d195325b 160 Error *err = NULL;
297a3646 161 GenericList *i, **prev;
06d64c62 162
297a3646
MA
163 visit_start_list(m, name, &err);
164 if (err) {
165 goto out;
166 }
167
168 for (prev = (GenericList **)obj;
169 !err && (i = visit_next_list(m, prev, &err)) != NULL;
170 prev = &i) {
441cbac0
MA
171 %(name)s *native_i = (%(name)s *)i;
172 visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
06d64c62 173 }
297a3646
MA
174
175 error_propagate(errp, err);
176 err = NULL;
177 visit_end_list(m, &err);
178out:
179 error_propagate(errp, err);
06d64c62
MR
180}
181''',
441cbac0
MA
182 name=c_name(name),
183 c_elt_type=element_type.c_name())
06d64c62 184
5aa05d3f 185def generate_visit_enum(name):
06d64c62
MR
186 return mcgen('''
187
40b3adec 188void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
06d64c62 189{
40b3adec 190 visit_type_enum(m, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
06d64c62
MR
191}
192''',
40b3adec 193 c_name=c_name(name), name=name)
06d64c62 194
441cbac0 195def gen_visit_alternate(name, variants):
69dd62df
KW
196 ret = mcgen('''
197
638ca8ad 198void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
69dd62df
KW
199{
200 Error *err = NULL;
201
297a3646
MA
202 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
203 if (err) {
204 goto out;
205 }
206 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
207 if (err) {
208 goto out_end;
209 }
210 switch ((*obj)->kind) {
69dd62df 211''',
d1f07c86 212 name=c_name(name))
69dd62df 213
441cbac0
MA
214 for var in variants.variants:
215 enum_full_value = c_enum_const(variants.tag_member.type.name,
216 var.name)
69dd62df 217 ret += mcgen('''
297a3646
MA
218 case %(enum_full_value)s:
219 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
220 break;
69dd62df 221''',
b0b58195 222 enum_full_value = enum_full_value,
441cbac0
MA
223 c_type=var.type.c_name(),
224 c_name=c_name(var.name))
69dd62df
KW
225
226 ret += mcgen('''
297a3646
MA
227 default:
228 abort();
69dd62df 229 }
297a3646
MA
230out_end:
231 error_propagate(errp, err);
232 err = NULL;
233 visit_end_implicit_struct(m, &err);
234out:
235 error_propagate(errp, err);
69dd62df
KW
236}
237''')
238
239 return ret
240
441cbac0
MA
241def gen_visit_union(name, base, variants):
242 ret = ''
06d64c62 243
50f2bdc7 244 if base:
441cbac0
MA
245 members = [m for m in base.members if m != variants.tag_member]
246 ret += generate_visit_struct_fields(name, members)
50f2bdc7 247
441cbac0
MA
248 for var in variants.variants:
249 # Ugly special case for simple union TODO get rid of it
250 if not var.simple_union_type():
251 ret += generate_visit_implicit_struct(var.type)
be3c7717 252
06d64c62
MR
253 ret += mcgen('''
254
40b3adec 255void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
06d64c62 256{
dc8fb6df
PB
257 Error *err = NULL;
258
40b3adec 259 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
260 if (err) {
261 goto out;
262 }
263 if (*obj) {
06d64c62 264''',
40b3adec 265 c_name=c_name(name), name=name)
06d64c62 266
0aef92b9 267 if base:
50f2bdc7 268 ret += mcgen('''
468866b8 269 visit_type_%(name)s_fields(m, obj, &err);
297a3646
MA
270 if (err) {
271 goto out_obj;
272 }
50f2bdc7 273''',
857af5f0 274 name=c_name(name))
0aef92b9 275
441cbac0
MA
276 disc_key = variants.tag_member.name
277 if not variants.tag_name:
278 # we pointlessly use a different key for simple unions
279 disc_key = 'type'
0aef92b9 280 ret += mcgen('''
441cbac0 281 visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err);
297a3646
MA
282 if (err) {
283 goto out_obj;
284 }
cee2dedb
MR
285 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
286 goto out_obj;
287 }
441cbac0 288 switch ((*obj)->%(c_name)s) {
0aef92b9 289''',
441cbac0
MA
290 disc_type=variants.tag_member.type.c_name(),
291 # TODO ugly special case for simple union
292 # Use same tag name in C as on the wire to get rid of
293 # it, then: c_name=c_name(variants.tag_member.name)
294 c_name=c_name(variants.tag_name or 'kind'),
bceae769 295 disc_key = disc_key)
0aef92b9 296
441cbac0
MA
297 for var in variants.variants:
298 # TODO ugly special case for simple union
299 simple_union_type = var.simple_union_type()
300 if simple_union_type:
50f2bdc7
KW
301 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
302 else:
be3c7717 303 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
50f2bdc7 304
441cbac0 305 enum_full_value = c_enum_const(variants.tag_member.type.name, var.name)
dc8fb6df 306 ret += mcgen('''
297a3646
MA
307 case %(enum_full_value)s:
308 ''' + fmt + '''
309 break;
dc8fb6df 310''',
b0b58195 311 enum_full_value = enum_full_value,
441cbac0
MA
312 c_type=(simple_union_type or var.type).c_name(),
313 c_name=c_name(var.name))
dc8fb6df
PB
314
315 ret += mcgen('''
297a3646
MA
316 default:
317 abort();
d195325b 318 }
297a3646 319out_obj:
d195325b
PB
320 error_propagate(errp, err);
321 err = NULL;
cee2dedb
MR
322 visit_end_union(m, !!(*obj)->data, &err);
323 error_propagate(errp, err);
324 err = NULL;
468866b8 325 }
297a3646
MA
326 visit_end_struct(m, &err);
327out:
328 error_propagate(errp, err);
dc8fb6df
PB
329}
330''')
331
06d64c62
MR
332 return ret
333
441cbac0
MA
334def gen_visit_decl(name, scalar=False):
335 c_type = c_name(name) + ' *'
336 if not scalar:
337 c_type += '*'
06d64c62 338 return mcgen('''
441cbac0 339void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
06d64c62 340''',
441cbac0
MA
341 c_name=c_name(name), c_type=c_type)
342
343
344class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
345 def __init__(self):
346 self.decl = None
347 self.defn = None
348 self._btin = None
349
350 def visit_begin(self, schema):
351 self.decl = ''
352 self.defn = ''
353 self._btin = guardstart('QAPI_VISIT_BUILTIN')
354
355 def visit_end(self):
356 # To avoid header dependency hell, we always generate
357 # declarations for built-in types in our header files and
358 # simply guard them. See also do_builtins (command line
359 # option -b).
360 self._btin += guardend('QAPI_VISIT_BUILTIN')
361 self.decl = self._btin + self.decl
362 self._btin = None
363
364 def visit_enum_type(self, name, info, values, prefix):
365 self.decl += gen_visit_decl(name, scalar=True)
366 self.defn += generate_visit_enum(name)
367
368 def visit_array_type(self, name, info, element_type):
369 decl = gen_visit_decl(name)
370 defn = gen_visit_list(name, element_type)
371 if isinstance(element_type, QAPISchemaBuiltinType):
372 self._btin += decl
373 if do_builtins:
374 self.defn += defn
375 else:
376 self.decl += decl
377 self.defn += defn
378
379 def visit_object_type(self, name, info, base, members, variants):
380 if info:
381 self.decl += gen_visit_decl(name)
382 if variants:
383 assert not members # not implemented
384 self.defn += gen_visit_union(name, base, variants)
385 else:
386 self.defn += gen_visit_struct(name, base, members)
387
388 def visit_alternate_type(self, name, info, variants):
389 self.decl += gen_visit_decl(name)
390 self.defn += gen_visit_alternate(name, variants)
391
392# If you link code generated from multiple schemata, you want only one
393# instance of the code for built-in types. Generate it only when
394# do_builtins, enabled by command line option -b. See also
395# QAPISchemaGenVisitVisitor.visit_end().
7c946bc4 396do_builtins = False
8d3bc517 397
2114f5a9
MA
398(input_file, output_dir, do_c, do_h, prefix, opts) = \
399 parse_command_line("b", ["builtins"])
400
06d64c62 401for o, a in opts:
2114f5a9 402 if o in ("-b", "--builtins"):
7c946bc4 403 do_builtins = True
8d3bc517 404
12f8e1b9 405c_comment = '''
06d64c62
MR
406/*
407 * schema-defined QAPI visitor functions
408 *
409 * Copyright IBM, Corp. 2011
410 *
411 * Authors:
412 * Anthony Liguori <aliguori@us.ibm.com>
413 *
414 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
415 * See the COPYING.LIB file in the top-level directory.
416 *
417 */
12f8e1b9
MA
418'''
419h_comment = '''
06d64c62 420/*
297a3646 421 * schema-defined QAPI visitor functions
06d64c62
MR
422 *
423 * Copyright IBM, Corp. 2011
424 *
425 * Authors:
426 * Anthony Liguori <aliguori@us.ibm.com>
427 *
428 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
429 * See the COPYING.LIB file in the top-level directory.
430 *
431 */
12f8e1b9
MA
432'''
433
434(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
435 'qapi-visit.c', 'qapi-visit.h',
436 c_comment, h_comment)
06d64c62 437
12f8e1b9
MA
438fdef.write(mcgen('''
439#include "qemu-common.h"
440#include "%(prefix)sqapi-visit.h"
441''',
442 prefix = prefix))
06d64c62 443
12f8e1b9 444fdecl.write(mcgen('''
7b1b5d19 445#include "qapi/visitor.h"
06d64c62 446#include "%(prefix)sqapi-types.h"
7c946bc4 447
06d64c62 448''',
12f8e1b9 449 prefix=prefix))
06d64c62 450
441cbac0
MA
451schema = QAPISchema(input_file)
452gen = QAPISchemaGenVisitVisitor()
453schema.visit(gen)
454fdef.write(gen.defn)
455fdecl.write(gen.decl)
06d64c62 456
12f8e1b9 457close_output(fdef, fdecl)