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