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