]>
Commit | Line | Data |
---|---|---|
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_body(field_prefix, name, members): | |
21 | ret = mcgen(''' | |
22 | if (!error_is_set(errp)) { | |
23 | ''') | |
24 | push_indent() | |
25 | ||
26 | if len(field_prefix): | |
27 | field_prefix = field_prefix + "." | |
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() | |
48 | for argname, argentry, optional, structured in parse_args(members): | |
49 | if optional: | |
50 | ret += mcgen(''' | |
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) { | |
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: | |
59 | ret += generate_visit_struct_body(field_prefix + argname, argname, argentry) | |
60 | else: | |
61 | ret += mcgen(''' | |
62 | visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err); | |
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 | } | |
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 | } | |
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 | { | |
99 | ''', | |
100 | name=name) | |
101 | ||
102 | push_indent() | |
103 | ret += generate_visit_struct_body("", name, members) | |
104 | pop_indent() | |
105 | ||
106 | ret += mcgen(''' | |
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 | { | |
116 | GenericList *i, **prev = (GenericList **)obj; | |
117 | Error *err = NULL; | |
118 | ||
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); | |
133 | } | |
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 | { | |
155 | Error *err = NULL; | |
156 | ||
157 | if (!error_is_set(errp)) { | |
158 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); | |
159 | if (!err) { | |
160 | if (obj && *obj) { | |
161 | visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); | |
162 | if (!err) { | |
163 | switch ((*obj)->kind) { | |
164 | ''', | |
165 | name=name) | |
166 | ||
167 | push_indent() | |
168 | push_indent() | |
169 | for key in members: | |
170 | ret += mcgen(''' | |
171 | case %(abbrev)s_KIND_%(enum)s: | |
172 | visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err); | |
173 | break; | |
174 | ''', | |
175 | abbrev = de_camel_case(name).upper(), | |
176 | enum = c_fun(de_camel_case(key),False).upper(), | |
177 | c_type=members[key], | |
178 | c_name=c_fun(key)) | |
179 | ||
180 | ret += mcgen(''' | |
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); | |
193 | } | |
194 | error_propagate(errp, err); | |
195 | } | |
196 | ''') | |
197 | ||
198 | pop_indent(); | |
199 | ret += mcgen(''' | |
200 | } | |
201 | ''') | |
202 | ||
203 | return ret | |
204 | ||
205 | def generate_declaration(name, members, genlist=True): | |
206 | ret = mcgen(''' | |
207 | ||
208 | void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp); | |
209 | ''', | |
210 | name=name) | |
211 | ||
212 | if genlist: | |
213 | ret += mcgen(''' | |
214 | void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); | |
215 | ''', | |
216 | name=name) | |
217 | ||
218 | return ret | |
219 | ||
220 | def generate_enum_declaration(name, members, genlist=True): | |
221 | ret = "" | |
222 | if genlist: | |
223 | ret += mcgen(''' | |
224 | void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); | |
225 | ''', | |
226 | name=name) | |
227 | ||
228 | return ret | |
229 | ||
230 | def generate_decl_enum(name, members, genlist=True): | |
231 | return mcgen(''' | |
232 | ||
233 | void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp); | |
234 | ''', | |
235 | name=name) | |
236 | ||
237 | try: | |
238 | opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", | |
239 | ["source", "header", "prefix=", "output-dir="]) | |
240 | except getopt.GetoptError, err: | |
241 | print str(err) | |
242 | sys.exit(1) | |
243 | ||
244 | output_dir = "" | |
245 | prefix = "" | |
246 | c_file = 'qapi-visit.c' | |
247 | h_file = 'qapi-visit.h' | |
248 | ||
249 | do_c = False | |
250 | do_h = False | |
251 | ||
252 | for o, a in opts: | |
253 | if o in ("-p", "--prefix"): | |
254 | prefix = a | |
255 | elif o in ("-o", "--output-dir"): | |
256 | output_dir = a + "/" | |
257 | elif o in ("-c", "--source"): | |
258 | do_c = True | |
259 | elif o in ("-h", "--header"): | |
260 | do_h = True | |
261 | ||
262 | if not do_c and not do_h: | |
263 | do_c = True | |
264 | do_h = True | |
265 | ||
266 | c_file = output_dir + prefix + c_file | |
267 | h_file = output_dir + prefix + h_file | |
268 | ||
269 | try: | |
270 | os.makedirs(output_dir) | |
271 | except os.error, e: | |
272 | if e.errno != errno.EEXIST: | |
273 | raise | |
274 | ||
275 | def maybe_open(really, name, opt): | |
276 | if really: | |
277 | return open(name, opt) | |
278 | else: | |
279 | import StringIO | |
280 | return StringIO.StringIO() | |
281 | ||
282 | fdef = maybe_open(do_c, c_file, 'w') | |
283 | fdecl = maybe_open(do_h, h_file, 'w') | |
284 | ||
285 | fdef.write(mcgen(''' | |
286 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
287 | ||
288 | /* | |
289 | * schema-defined QAPI visitor functions | |
290 | * | |
291 | * Copyright IBM, Corp. 2011 | |
292 | * | |
293 | * Authors: | |
294 | * Anthony Liguori <aliguori@us.ibm.com> | |
295 | * | |
296 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
297 | * See the COPYING.LIB file in the top-level directory. | |
298 | * | |
299 | */ | |
300 | ||
301 | #include "qemu-common.h" | |
302 | #include "%(header)s" | |
303 | ''', | |
304 | header=basename(h_file))) | |
305 | ||
306 | fdecl.write(mcgen(''' | |
307 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
308 | ||
309 | /* | |
310 | * schema-defined QAPI visitor function | |
311 | * | |
312 | * Copyright IBM, Corp. 2011 | |
313 | * | |
314 | * Authors: | |
315 | * Anthony Liguori <aliguori@us.ibm.com> | |
316 | * | |
317 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
318 | * See the COPYING.LIB file in the top-level directory. | |
319 | * | |
320 | */ | |
321 | ||
322 | #ifndef %(guard)s | |
323 | #define %(guard)s | |
324 | ||
325 | #include "qapi/visitor.h" | |
326 | #include "%(prefix)sqapi-types.h" | |
327 | ''', | |
328 | prefix=prefix, guard=guardname(h_file))) | |
329 | ||
330 | exprs = parse_schema(sys.stdin) | |
331 | ||
332 | for expr in exprs: | |
333 | if expr.has_key('type'): | |
334 | ret = generate_visit_struct(expr['type'], expr['data']) | |
335 | ret += generate_visit_list(expr['type'], expr['data']) | |
336 | fdef.write(ret) | |
337 | ||
338 | ret = generate_declaration(expr['type'], expr['data']) | |
339 | fdecl.write(ret) | |
340 | elif expr.has_key('union'): | |
341 | ret = generate_visit_union(expr['union'], expr['data']) | |
342 | ret += generate_visit_list(expr['union'], expr['data']) | |
343 | fdef.write(ret) | |
344 | ||
345 | ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys()) | |
346 | ret += generate_declaration(expr['union'], expr['data']) | |
347 | fdecl.write(ret) | |
348 | elif expr.has_key('enum'): | |
349 | ret = generate_visit_list(expr['enum'], expr['data']) | |
350 | ret += generate_visit_enum(expr['enum'], expr['data']) | |
351 | fdef.write(ret) | |
352 | ||
353 | ret = generate_decl_enum(expr['enum'], expr['data']) | |
354 | ret += generate_enum_declaration(expr['enum'], expr['data']) | |
355 | fdecl.write(ret) | |
356 | ||
357 | fdecl.write(''' | |
358 | #endif | |
359 | ''') | |
360 | ||
361 | fdecl.flush() | |
362 | fdecl.close() | |
363 | ||
364 | fdef.flush() | |
365 | fdef.close() |