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