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