qapi: Factor parse_command_line() out of the generators
[qemu.git] / scripts / qapi-types.py
blob62044c11cb06eaad02434e28fc78d7848febaf23
2 # QAPI types generator
4 # Copyright IBM, Corp. 2011
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
9 # This work is licensed under the terms of the GNU GPL, version 2.
10 # See the COPYING file in the top-level directory.
12 from ordereddict import OrderedDict
13 from qapi import *
14 import os
15 import errno
17 def generate_fwd_struct(name, members, builtin_type=False):
18 if builtin_type:
19 return mcgen('''
21 typedef struct %(name)sList
23 union {
24 %(type)s value;
25 uint64_t padding;
27 struct %(name)sList *next;
28 } %(name)sList;
29 ''',
30 type=c_type(name),
31 name=name)
33 return mcgen('''
35 typedef struct %(name)s %(name)s;
37 typedef struct %(name)sList
39 union {
40 %(name)s *value;
41 uint64_t padding;
43 struct %(name)sList *next;
44 } %(name)sList;
45 ''',
46 name=c_name(name))
48 def generate_fwd_enum_struct(name, members):
49 return mcgen('''
50 typedef struct %(name)sList
52 union {
53 %(name)s value;
54 uint64_t padding;
56 struct %(name)sList *next;
57 } %(name)sList;
58 ''',
59 name=c_name(name))
61 def generate_struct_fields(members):
62 ret = ''
64 for argname, argentry, optional in parse_args(members):
65 if optional:
66 ret += mcgen('''
67 bool has_%(c_name)s;
68 ''',
69 c_name=c_name(argname))
70 ret += mcgen('''
71 %(c_type)s %(c_name)s;
72 ''',
73 c_type=c_type(argentry), c_name=c_name(argname))
75 return ret
77 def generate_struct(expr):
79 structname = expr.get('struct', "")
80 fieldname = expr.get('field', "")
81 members = expr['data']
82 base = expr.get('base')
84 ret = mcgen('''
85 struct %(name)s
87 ''',
88 name=c_name(structname))
90 if base:
91 ret += generate_struct_fields({'base': base})
93 ret += generate_struct_fields(members)
95 # Make sure that all structs have at least one field; this avoids
96 # potential issues with attempting to malloc space for zero-length structs
97 # in C, and also incompatibility with C++ (where an empty struct is size 1).
98 if not base and not members:
99 ret += mcgen('''
100 char qapi_dummy_field_for_empty_struct;
101 ''')
103 if len(fieldname):
104 fieldname = " " + fieldname
105 ret += mcgen('''
106 }%(field)s;
107 ''',
108 field=fieldname)
110 return ret
112 def generate_enum_lookup(name, values):
113 ret = mcgen('''
114 const char *%(name)s_lookup[] = {
115 ''',
116 name=c_name(name))
117 i = 0
118 for value in values:
119 index = c_enum_const(name, value)
120 ret += mcgen('''
121 [%(index)s] = "%(value)s",
122 ''',
123 index = index, value = value)
125 max_index = c_enum_const(name, 'MAX')
126 ret += mcgen('''
127 [%(max_index)s] = NULL,
130 ''',
131 max_index=max_index)
132 return ret
134 def generate_enum(name, values):
135 name = c_name(name)
136 lookup_decl = mcgen('''
137 extern const char *%(name)s_lookup[];
138 ''',
139 name=name)
141 enum_decl = mcgen('''
142 typedef enum %(name)s
144 ''',
145 name=name)
147 # append automatically generated _MAX value
148 enum_values = values + [ 'MAX' ]
150 i = 0
151 for value in enum_values:
152 enum_full_value = c_enum_const(name, value)
153 enum_decl += mcgen('''
154 %(enum_full_value)s = %(i)d,
155 ''',
156 enum_full_value = enum_full_value,
157 i=i)
158 i += 1
160 enum_decl += mcgen('''
161 } %(name)s;
162 ''',
163 name=name)
165 return lookup_decl + enum_decl
167 def generate_alternate_qtypes(expr):
169 name = expr['alternate']
170 members = expr['data']
172 ret = mcgen('''
173 const int %(name)s_qtypes[QTYPE_MAX] = {
174 ''',
175 name=c_name(name))
177 for key in members:
178 qtype = find_alternate_member_qtype(members[key])
179 assert qtype, "Invalid alternate member"
181 ret += mcgen('''
182 [%(qtype)s] = %(enum_const)s,
183 ''',
184 qtype = qtype,
185 enum_const = c_enum_const(name + 'Kind', key))
187 ret += mcgen('''
189 ''')
190 return ret
193 def generate_union(expr, meta):
195 name = c_name(expr[meta])
196 typeinfo = expr['data']
198 base = expr.get('base')
199 discriminator = expr.get('discriminator')
201 enum_define = discriminator_find_enum_define(expr)
202 if enum_define:
203 discriminator_type_name = enum_define['enum_name']
204 else:
205 discriminator_type_name = '%sKind' % (name)
207 ret = mcgen('''
208 struct %(name)s
210 %(discriminator_type_name)s kind;
211 union {
212 void *data;
213 ''',
214 name=name,
215 discriminator_type_name=c_name(discriminator_type_name))
217 for key in typeinfo:
218 ret += mcgen('''
219 %(c_type)s %(c_name)s;
220 ''',
221 c_type=c_type(typeinfo[key]),
222 c_name=c_name(key))
224 ret += mcgen('''
226 ''')
228 if base:
229 assert discriminator
230 base_fields = find_struct(base)['data'].copy()
231 del base_fields[discriminator]
232 ret += generate_struct_fields(base_fields)
233 else:
234 assert not discriminator
236 ret += mcgen('''
238 ''')
239 if meta == 'alternate':
240 ret += mcgen('''
241 extern const int %(name)s_qtypes[];
242 ''',
243 name=name)
246 return ret
248 def generate_type_cleanup_decl(name):
249 ret = mcgen('''
250 void qapi_free_%(name)s(%(c_type)s obj);
251 ''',
252 c_type=c_type(name), name=c_name(name))
253 return ret
255 def generate_type_cleanup(name):
256 ret = mcgen('''
258 void qapi_free_%(name)s(%(c_type)s obj)
260 QapiDeallocVisitor *md;
261 Visitor *v;
263 if (!obj) {
264 return;
267 md = qapi_dealloc_visitor_new();
268 v = qapi_dealloc_get_visitor(md);
269 visit_type_%(name)s(v, &obj, NULL, NULL);
270 qapi_dealloc_visitor_cleanup(md);
272 ''',
273 c_type=c_type(name), name=c_name(name))
274 return ret
276 c_file = 'qapi-types.c'
277 h_file = 'qapi-types.h'
278 do_builtins = False
280 (input_file, output_dir, do_c, do_h, prefix, opts) = \
281 parse_command_line("b", ["builtins"])
283 for o, a in opts:
284 if o in ("-b", "--builtins"):
285 do_builtins = True
287 c_file = output_dir + prefix + c_file
288 h_file = output_dir + prefix + h_file
290 try:
291 os.makedirs(output_dir)
292 except os.error, e:
293 if e.errno != errno.EEXIST:
294 raise
296 def maybe_open(really, name, opt):
297 if really:
298 return open(name, opt)
299 else:
300 import StringIO
301 return StringIO.StringIO()
303 fdef = maybe_open(do_c, c_file, 'w')
304 fdecl = maybe_open(do_h, h_file, 'w')
306 fdef.write(mcgen('''
307 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
310 * deallocation functions for schema-defined QAPI types
312 * Copyright IBM, Corp. 2011
314 * Authors:
315 * Anthony Liguori <aliguori@us.ibm.com>
316 * Michael Roth <mdroth@linux.vnet.ibm.com>
318 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
319 * See the COPYING.LIB file in the top-level directory.
323 #include "qapi/dealloc-visitor.h"
324 #include "%(prefix)sqapi-types.h"
325 #include "%(prefix)sqapi-visit.h"
327 ''', prefix=prefix))
329 fdecl.write(mcgen('''
330 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
333 * schema-defined QAPI types
335 * Copyright IBM, Corp. 2011
337 * Authors:
338 * Anthony Liguori <aliguori@us.ibm.com>
340 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
341 * See the COPYING.LIB file in the top-level directory.
345 #ifndef %(guard)s
346 #define %(guard)s
348 #include <stdbool.h>
349 #include <stdint.h>
351 ''',
352 guard=guardname(h_file)))
354 exprs = parse_schema(input_file)
355 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
357 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
358 for typename in builtin_types.keys():
359 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
360 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
362 for expr in exprs:
363 ret = "\n"
364 if expr.has_key('struct'):
365 ret += generate_fwd_struct(expr['struct'], expr['data'])
366 elif expr.has_key('enum'):
367 ret += generate_enum(expr['enum'], expr['data']) + "\n"
368 ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
369 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
370 elif expr.has_key('union'):
371 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
372 enum_define = discriminator_find_enum_define(expr)
373 if not enum_define:
374 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
375 fdef.write(generate_enum_lookup('%sKind' % expr['union'],
376 expr['data'].keys()))
377 elif expr.has_key('alternate'):
378 ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
379 ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
380 fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
381 expr['data'].keys()))
382 fdef.write(generate_alternate_qtypes(expr))
383 else:
384 continue
385 fdecl.write(ret)
387 # to avoid header dependency hell, we always generate declarations
388 # for built-in types in our header files and simply guard them
389 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
390 for typename in builtin_types.keys():
391 fdecl.write(generate_type_cleanup_decl(typename + "List"))
392 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
394 # ...this doesn't work for cases where we link in multiple objects that
395 # have the functions defined, so we use -b option to provide control
396 # over these cases
397 if do_builtins:
398 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
399 for typename in builtin_types.keys():
400 fdef.write(generate_type_cleanup(typename + "List"))
401 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
403 for expr in exprs:
404 ret = "\n"
405 if expr.has_key('struct'):
406 ret += generate_struct(expr) + "\n"
407 ret += generate_type_cleanup_decl(expr['struct'] + "List")
408 fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
409 ret += generate_type_cleanup_decl(expr['struct'])
410 fdef.write(generate_type_cleanup(expr['struct']) + "\n")
411 elif expr.has_key('union'):
412 ret += generate_union(expr, 'union')
413 ret += generate_type_cleanup_decl(expr['union'] + "List")
414 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
415 ret += generate_type_cleanup_decl(expr['union'])
416 fdef.write(generate_type_cleanup(expr['union']) + "\n")
417 elif expr.has_key('alternate'):
418 ret += generate_union(expr, 'alternate')
419 ret += generate_type_cleanup_decl(expr['alternate'] + "List")
420 fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
421 ret += generate_type_cleanup_decl(expr['alternate'])
422 fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
423 elif expr.has_key('enum'):
424 ret += generate_type_cleanup_decl(expr['enum'] + "List")
425 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
426 else:
427 continue
428 fdecl.write(ret)
430 fdecl.write('''
431 #endif
432 ''')
434 fdecl.flush()
435 fdecl.close()
437 fdef.flush()
438 fdef.close()