]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi-visit.py
qapi: qapi-commands.py option --type is unused, drop it
[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
MR
14
15from ordereddict import OrderedDict
16from qapi import *
297a3646 17import re
06d64c62
MR
18import sys
19import os
20import getopt
21import errno
22
be3c7717
MA
23implicit_structs = []
24
25def generate_visit_implicit_struct(type):
26 global implicit_structs
27 if type in implicit_structs:
28 return ''
29 implicit_structs.append(type)
30 return mcgen('''
31
32static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
33{
34 Error *err = NULL;
35
36 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
37 if (!err) {
297a3646 38 visit_type_%(c_type)s_fields(m, obj, errp);
be3c7717
MA
39 visit_end_implicit_struct(m, &err);
40 }
41 error_propagate(errp, err);
42}
43''',
44 c_type=type_name(type))
45
a82b982e 46def generate_visit_struct_fields(name, members, base = None):
50f2bdc7 47 substructs = []
d131c897 48 ret = ''
50f2bdc7 49
be3c7717
MA
50 if base:
51 ret += generate_visit_implicit_struct(base)
52
50f2bdc7
KW
53 ret += mcgen('''
54
a82b982e 55static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
50f2bdc7
KW
56{
57 Error *err = NULL;
58''',
83a02706 59 name=c_name(name))
50f2bdc7 60 push_indent()
d195325b 61
622f557f
KW
62 if base:
63 ret += mcgen('''
a82b982e 64visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
297a3646
MA
65if (err) {
66 goto out;
67}
622f557f 68''',
18df515e 69 type=type_name(base), c_name=c_name('base'))
622f557f 70
6b5abc7d 71 for argname, argentry, optional in parse_args(members):
06d64c62
MR
72 if optional:
73 ret += mcgen('''
a82b982e
EB
74visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
75if (!err && (*obj)->has_%(c_name)s) {
06d64c62 76''',
18df515e 77 c_name=c_name(argname), name=argname)
06d64c62
MR
78 push_indent()
79
6b5abc7d 80 ret += mcgen('''
a82b982e 81visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
06d64c62 82''',
18df515e 83 type=type_name(argentry), c_name=c_name(argname),
6b5abc7d 84 name=argname)
06d64c62
MR
85
86 if optional:
87 pop_indent()
88 ret += mcgen('''
89}
297a3646
MA
90''')
91 ret += mcgen('''
92if (err) {
93 goto out;
94}
d195325b
PB
95''')
96
50f2bdc7 97 pop_indent()
297a3646
MA
98 if re.search('^ *goto out\\;', ret, re.MULTILINE):
99 ret += mcgen('''
50f2bdc7 100
297a3646
MA
101out:
102''')
103 ret += mcgen('''
50f2bdc7
KW
104 error_propagate(errp, err);
105}
106''')
d131c897
KW
107 return ret
108
109
a82b982e 110def generate_visit_struct_body(name, members):
d131c897 111 ret = mcgen('''
297a3646
MA
112 Error *err = NULL;
113
83a02706 114 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
115 if (!err) {
116 if (*obj) {
83a02706 117 visit_type_%(c_name)s_fields(m, obj, errp);
297a3646
MA
118 }
119 visit_end_struct(m, &err);
50f2bdc7 120 }
297a3646 121 error_propagate(errp, err);
50f2bdc7 122''',
83a02706 123 name=name, c_name=c_name(name))
d195325b 124
06d64c62
MR
125 return ret
126
14d36307
KW
127def generate_visit_struct(expr):
128
fd41dd4e 129 name = expr['struct']
14d36307 130 members = expr['data']
622f557f 131 base = expr.get('base')
14d36307 132
a82b982e 133 ret = generate_visit_struct_fields(name, members, base)
50f2bdc7
KW
134
135 ret += mcgen('''
06d64c62 136
638ca8ad 137void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 138{
06d64c62 139''',
83a02706 140 name=c_name(name))
d195325b 141
a82b982e 142 ret += generate_visit_struct_body(name, members)
06d64c62
MR
143
144 ret += mcgen('''
06d64c62
MR
145}
146''')
147 return ret
148
149def generate_visit_list(name, members):
150 return mcgen('''
151
638ca8ad 152void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
06d64c62 153{
d195325b 154 Error *err = NULL;
297a3646 155 GenericList *i, **prev;
06d64c62 156
297a3646
MA
157 visit_start_list(m, name, &err);
158 if (err) {
159 goto out;
160 }
161
162 for (prev = (GenericList **)obj;
163 !err && (i = visit_next_list(m, prev, &err)) != NULL;
164 prev = &i) {
165 %(name)sList *native_i = (%(name)sList *)i;
166 visit_type_%(name)s(m, &native_i->value, NULL, &err);
06d64c62 167 }
297a3646
MA
168
169 error_propagate(errp, err);
170 err = NULL;
171 visit_end_list(m, &err);
172out:
173 error_propagate(errp, err);
06d64c62
MR
174}
175''',
fce384b8 176 name=type_name(name))
06d64c62
MR
177
178def generate_visit_enum(name, members):
179 return mcgen('''
180
638ca8ad 181void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
06d64c62
MR
182{
183 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
184}
185''',
fce384b8 186 name=c_name(name))
06d64c62 187
811d04fd 188def generate_visit_alternate(name, members):
69dd62df
KW
189 ret = mcgen('''
190
638ca8ad 191void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
69dd62df
KW
192{
193 Error *err = NULL;
194
297a3646
MA
195 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
196 if (err) {
197 goto out;
198 }
199 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
200 if (err) {
201 goto out_end;
202 }
203 switch ((*obj)->kind) {
69dd62df 204''',
d1f07c86 205 name=c_name(name))
69dd62df 206
ab916fad 207 # For alternate, always use the default enum type automatically generated
d1f07c86
EB
208 # as name + 'Kind'
209 disc_type = c_name(name) + 'Kind'
b0b58195 210
69dd62df 211 for key in members:
b52c4b9c 212 assert (members[key] in builtin_types.keys()
69dd62df 213 or find_struct(members[key])
e775ba77 214 or find_union(members[key])
ab916fad 215 or find_enum(members[key])), "Invalid alternate member"
69dd62df 216
7c81c61f 217 enum_full_value = c_enum_const(disc_type, key)
69dd62df 218 ret += mcgen('''
297a3646
MA
219 case %(enum_full_value)s:
220 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
221 break;
69dd62df 222''',
b0b58195 223 enum_full_value = enum_full_value,
69dd62df 224 c_type = type_name(members[key]),
18df515e 225 c_name = c_name(key))
69dd62df
KW
226
227 ret += mcgen('''
297a3646
MA
228 default:
229 abort();
69dd62df 230 }
297a3646
MA
231out_end:
232 error_propagate(errp, err);
233 err = NULL;
234 visit_end_implicit_struct(m, &err);
235out:
236 error_propagate(errp, err);
69dd62df
KW
237}
238''')
239
240 return ret
241
242
0aef92b9
KW
243def generate_visit_union(expr):
244
245 name = expr['union']
246 members = expr['data']
247
248 base = expr.get('base')
50f2bdc7 249 discriminator = expr.get('discriminator')
0aef92b9 250
bceae769
WX
251 enum_define = discriminator_find_enum_define(expr)
252 if enum_define:
253 # Use the enum type as discriminator
254 ret = ""
857af5f0 255 disc_type = c_name(enum_define['enum_name'])
bceae769 256 else:
a8d4a2e4 257 # There will always be a discriminator in the C switch code, by default
bb337290
EB
258 # it is an enum type generated silently
259 ret = generate_visit_enum(name + 'Kind', members.keys())
260 disc_type = c_name(name) + 'Kind'
06d64c62 261
50f2bdc7 262 if base:
a8d4a2e4
EB
263 assert discriminator
264 base_fields = find_struct(base)['data'].copy()
265 del base_fields[discriminator]
a82b982e 266 ret += generate_visit_struct_fields(name, base_fields)
50f2bdc7 267
be3c7717
MA
268 if discriminator:
269 for key in members:
270 ret += generate_visit_implicit_struct(members[key])
271
06d64c62
MR
272 ret += mcgen('''
273
638ca8ad 274void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 275{
dc8fb6df
PB
276 Error *err = NULL;
277
297a3646
MA
278 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
279 if (err) {
280 goto out;
281 }
282 if (*obj) {
06d64c62 283''',
bb337290 284 name=c_name(name))
06d64c62 285
0aef92b9 286 if base:
50f2bdc7 287 ret += mcgen('''
468866b8 288 visit_type_%(name)s_fields(m, obj, &err);
297a3646
MA
289 if (err) {
290 goto out_obj;
291 }
50f2bdc7 292''',
857af5f0 293 name=c_name(name))
0aef92b9 294
7b75d9d6 295 if not discriminator:
bceae769 296 disc_key = "type"
7b75d9d6 297 else:
bceae769 298 disc_key = discriminator
0aef92b9 299 ret += mcgen('''
bceae769 300 visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
297a3646
MA
301 if (err) {
302 goto out_obj;
303 }
cee2dedb
MR
304 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
305 goto out_obj;
306 }
297a3646 307 switch ((*obj)->kind) {
0aef92b9 308''',
bceae769
WX
309 disc_type = disc_type,
310 disc_key = disc_key)
0aef92b9 311
dc8fb6df 312 for key in members:
50f2bdc7
KW
313 if not discriminator:
314 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
315 else:
be3c7717 316 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
50f2bdc7 317
7c81c61f 318 enum_full_value = c_enum_const(disc_type, key)
dc8fb6df 319 ret += mcgen('''
297a3646
MA
320 case %(enum_full_value)s:
321 ''' + fmt + '''
322 break;
dc8fb6df 323''',
b0b58195 324 enum_full_value = enum_full_value,
c664aef5 325 c_type=type_name(members[key]),
18df515e 326 c_name=c_name(key))
dc8fb6df
PB
327
328 ret += mcgen('''
297a3646
MA
329 default:
330 abort();
d195325b 331 }
297a3646 332out_obj:
d195325b
PB
333 error_propagate(errp, err);
334 err = NULL;
cee2dedb
MR
335 visit_end_union(m, !!(*obj)->data, &err);
336 error_propagate(errp, err);
337 err = NULL;
468866b8 338 }
297a3646
MA
339 visit_end_struct(m, &err);
340out:
341 error_propagate(errp, err);
dc8fb6df
PB
342}
343''')
344
06d64c62
MR
345 return ret
346
6540e9f3 347def generate_declaration(name, members, builtin_type=False):
7c946bc4
MR
348 ret = ""
349 if not builtin_type:
83a02706 350 name = c_name(name)
7c946bc4 351 ret += mcgen('''
06d64c62 352
638ca8ad 353void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
06d64c62 354''',
6540e9f3 355 name=name)
06d64c62 356
6540e9f3 357 ret += mcgen('''
638ca8ad 358void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
06d64c62
MR
359''',
360 name=name)
361
362 return ret
363
6540e9f3
EB
364def generate_enum_declaration(name, members):
365 ret = mcgen('''
638ca8ad 366void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
b9c4b48d 367''',
fce384b8 368 name=c_name(name))
b9c4b48d
AK
369
370 return ret
371
6540e9f3 372def generate_decl_enum(name, members):
06d64c62
MR
373 return mcgen('''
374
638ca8ad 375void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
06d64c62 376''',
fce384b8 377 name=c_name(name))
06d64c62
MR
378
379try:
33aaad52 380 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
7c946bc4 381 ["source", "header", "builtins", "prefix=",
33aaad52 382 "input-file=", "output-dir="])
06d64c62
MR
383except getopt.GetoptError, err:
384 print str(err)
385 sys.exit(1)
386
33aaad52 387input_file = ""
06d64c62
MR
388output_dir = ""
389prefix = ""
390c_file = 'qapi-visit.c'
391h_file = 'qapi-visit.h'
392
8d3bc517
AK
393do_c = False
394do_h = False
7c946bc4 395do_builtins = False
8d3bc517 396
06d64c62
MR
397for o, a in opts:
398 if o in ("-p", "--prefix"):
399 prefix = a
33aaad52
LV
400 elif o in ("-i", "--input-file"):
401 input_file = a
06d64c62
MR
402 elif o in ("-o", "--output-dir"):
403 output_dir = a + "/"
8d3bc517 404 elif o in ("-c", "--source"):
8d3bc517 405 do_c = True
19bf7c87
AK
406 elif o in ("-h", "--header"):
407 do_h = True
7c946bc4
MR
408 elif o in ("-b", "--builtins"):
409 do_builtins = True
8d3bc517
AK
410
411if not do_c and not do_h:
412 do_c = True
413 do_h = True
06d64c62
MR
414
415c_file = output_dir + prefix + c_file
416h_file = output_dir + prefix + h_file
417
418try:
419 os.makedirs(output_dir)
420except os.error, e:
421 if e.errno != errno.EEXIST:
422 raise
423
8d3bc517 424def maybe_open(really, name, opt):
8d3bc517
AK
425 if really:
426 return open(name, opt)
19bf7c87
AK
427 else:
428 import StringIO
429 return StringIO.StringIO()
8d3bc517
AK
430
431fdef = maybe_open(do_c, c_file, 'w')
432fdecl = maybe_open(do_h, h_file, 'w')
06d64c62
MR
433
434fdef.write(mcgen('''
435/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
436
437/*
438 * schema-defined QAPI visitor functions
439 *
440 * Copyright IBM, Corp. 2011
441 *
442 * Authors:
443 * Anthony Liguori <aliguori@us.ibm.com>
444 *
445 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
446 * See the COPYING.LIB file in the top-level directory.
447 *
448 */
449
79ee7df8 450#include "qemu-common.h"
06d64c62
MR
451#include "%(header)s"
452''',
453 header=basename(h_file)))
454
455fdecl.write(mcgen('''
456/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
457
458/*
297a3646 459 * schema-defined QAPI visitor functions
06d64c62
MR
460 *
461 * Copyright IBM, Corp. 2011
462 *
463 * Authors:
464 * Anthony Liguori <aliguori@us.ibm.com>
465 *
466 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
467 * See the COPYING.LIB file in the top-level directory.
468 *
469 */
470
471#ifndef %(guard)s
472#define %(guard)s
473
7b1b5d19 474#include "qapi/visitor.h"
06d64c62 475#include "%(prefix)sqapi-types.h"
7c946bc4 476
06d64c62
MR
477''',
478 prefix=prefix, guard=guardname(h_file)))
479
33aaad52 480exprs = parse_schema(input_file)
06d64c62 481
7c946bc4
MR
482# to avoid header dependency hell, we always generate declarations
483# for built-in types in our header files and simply guard them
484fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
b52c4b9c 485for typename in builtin_types.keys():
6540e9f3 486 fdecl.write(generate_declaration(typename, None, builtin_type=True))
7c946bc4
MR
487fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
488
489# ...this doesn't work for cases where we link in multiple objects that
490# have the functions defined, so we use -b option to provide control
491# over these cases
492if do_builtins:
b52c4b9c 493 for typename in builtin_types.keys():
7c946bc4 494 fdef.write(generate_visit_list(typename, None))
7c946bc4 495
06d64c62 496for expr in exprs:
fd41dd4e 497 if expr.has_key('struct'):
14d36307 498 ret = generate_visit_struct(expr)
fd41dd4e 499 ret += generate_visit_list(expr['struct'], expr['data'])
06d64c62
MR
500 fdef.write(ret)
501
fd41dd4e 502 ret = generate_declaration(expr['struct'], expr['data'])
06d64c62
MR
503 fdecl.write(ret)
504 elif expr.has_key('union'):
0aef92b9 505 ret = generate_visit_union(expr)
dc8fb6df 506 ret += generate_visit_list(expr['union'], expr['data'])
06d64c62
MR
507 fdef.write(ret)
508
bceae769
WX
509 enum_define = discriminator_find_enum_define(expr)
510 ret = ""
511 if not enum_define:
512 ret = generate_decl_enum('%sKind' % expr['union'],
513 expr['data'].keys())
06d64c62
MR
514 ret += generate_declaration(expr['union'], expr['data'])
515 fdecl.write(ret)
ab916fad
EB
516 elif expr.has_key('alternate'):
517 ret = generate_visit_alternate(expr['alternate'], expr['data'])
518 ret += generate_visit_list(expr['alternate'], expr['data'])
519 fdef.write(ret)
520
521 ret = generate_decl_enum('%sKind' % expr['alternate'],
522 expr['data'].keys())
523 ret += generate_declaration(expr['alternate'], expr['data'])
524 fdecl.write(ret)
06d64c62 525 elif expr.has_key('enum'):
b9c4b48d
AK
526 ret = generate_visit_list(expr['enum'], expr['data'])
527 ret += generate_visit_enum(expr['enum'], expr['data'])
06d64c62
MR
528 fdef.write(ret)
529
530 ret = generate_decl_enum(expr['enum'], expr['data'])
b9c4b48d 531 ret += generate_enum_declaration(expr['enum'], expr['data'])
06d64c62
MR
532 fdecl.write(ret)
533
534fdecl.write('''
535#endif
536''')
537
538fdecl.flush()
539fdecl.close()
540
541fdef.flush()
542fdef.close()