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