Merge remote-tracking branch 'remotes/kraxel/tags/pull-gtk-20150326-1' into staging
[qemu/ar7.git] / scripts / qapi-types.py
blobdb872180c6591cbb6931bb003a73bba3eafa8054
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 sys
15 import os
16 import getopt
17 import errno
19 def generate_fwd_struct(name, members, builtin_type=False):
20 if builtin_type:
21 return mcgen('''
23 typedef struct %(name)sList
25 union {
26 %(type)s value;
27 uint64_t padding;
29 struct %(name)sList *next;
30 } %(name)sList;
31 ''',
32 type=c_type(name),
33 name=name)
35 return mcgen('''
37 typedef struct %(name)s %(name)s;
39 typedef struct %(name)sList
41 union {
42 %(name)s *value;
43 uint64_t padding;
45 struct %(name)sList *next;
46 } %(name)sList;
47 ''',
48 name=name)
50 def generate_fwd_enum_struct(name, members):
51 return mcgen('''
52 typedef struct %(name)sList
54 union {
55 %(name)s value;
56 uint64_t padding;
58 struct %(name)sList *next;
59 } %(name)sList;
60 ''',
61 name=name)
63 def generate_struct_fields(members):
64 ret = ''
66 for argname, argentry, optional, structured in parse_args(members):
67 if optional:
68 ret += mcgen('''
69 bool has_%(c_name)s;
70 ''',
71 c_name=c_var(argname))
72 if structured:
73 push_indent()
74 ret += generate_struct({ "field": argname, "data": argentry})
75 pop_indent()
76 else:
77 ret += mcgen('''
78 %(c_type)s %(c_name)s;
79 ''',
80 c_type=c_type(argentry), c_name=c_var(argname))
82 return ret
84 def generate_struct(expr):
86 structname = expr.get('type', "")
87 fieldname = expr.get('field', "")
88 members = expr['data']
89 base = expr.get('base')
91 ret = mcgen('''
92 struct %(name)s
94 ''',
95 name=structname)
97 if base:
98 ret += generate_struct_fields({'base': base})
100 ret += generate_struct_fields(members)
102 # Make sure that all structs have at least one field; this avoids
103 # potential issues with attempting to malloc space for zero-length structs
104 # in C, and also incompatibility with C++ (where an empty struct is size 1).
105 if not base and not members:
106 ret += mcgen('''
107 char qapi_dummy_field_for_empty_struct;
108 ''')
110 if len(fieldname):
111 fieldname = " " + fieldname
112 ret += mcgen('''
113 }%(field)s;
114 ''',
115 field=fieldname)
117 return ret
119 def generate_enum_lookup(name, values):
120 ret = mcgen('''
121 const char *%(name)s_lookup[] = {
122 ''',
123 name=name)
124 i = 0
125 for value in values:
126 index = generate_enum_full_value(name, value)
127 ret += mcgen('''
128 [%(index)s] = "%(value)s",
129 ''',
130 index = index, value = value)
132 max_index = generate_enum_full_value(name, 'MAX')
133 ret += mcgen('''
134 [%(max_index)s] = NULL,
137 ''',
138 max_index=max_index)
139 return ret
141 def generate_enum(name, values):
142 lookup_decl = mcgen('''
143 extern const char *%(name)s_lookup[];
144 ''',
145 name=name)
147 enum_decl = mcgen('''
148 typedef enum %(name)s
150 ''',
151 name=name)
153 # append automatically generated _MAX value
154 enum_values = values + [ 'MAX' ]
156 i = 0
157 for value in enum_values:
158 enum_full_value = generate_enum_full_value(name, value)
159 enum_decl += mcgen('''
160 %(enum_full_value)s = %(i)d,
161 ''',
162 enum_full_value = enum_full_value,
163 i=i)
164 i += 1
166 enum_decl += mcgen('''
167 } %(name)s;
168 ''',
169 name=name)
171 return lookup_decl + enum_decl
173 def generate_anon_union_qtypes(expr):
175 name = expr['union']
176 members = expr['data']
178 ret = mcgen('''
179 const int %(name)s_qtypes[QTYPE_MAX] = {
180 ''',
181 name=name)
183 for key in members:
184 qapi_type = members[key]
185 if builtin_type_qtypes.has_key(qapi_type):
186 qtype = builtin_type_qtypes[qapi_type]
187 elif find_struct(qapi_type):
188 qtype = "QTYPE_QDICT"
189 elif find_union(qapi_type):
190 qtype = "QTYPE_QDICT"
191 elif find_enum(qapi_type):
192 qtype = "QTYPE_QSTRING"
193 else:
194 assert False, "Invalid anonymous union member"
196 ret += mcgen('''
197 [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
198 ''',
199 qtype = qtype,
200 abbrev = de_camel_case(name).upper(),
201 enum = c_fun(de_camel_case(key),False).upper())
203 ret += mcgen('''
205 ''')
206 return ret
209 def generate_union(expr):
211 name = expr['union']
212 typeinfo = expr['data']
214 base = expr.get('base')
215 discriminator = expr.get('discriminator')
217 enum_define = discriminator_find_enum_define(expr)
218 if enum_define:
219 discriminator_type_name = enum_define['enum_name']
220 else:
221 discriminator_type_name = '%sKind' % (name)
223 ret = mcgen('''
224 struct %(name)s
226 %(discriminator_type_name)s kind;
227 union {
228 void *data;
229 ''',
230 name=name,
231 discriminator_type_name=discriminator_type_name)
233 for key in typeinfo:
234 ret += mcgen('''
235 %(c_type)s %(c_name)s;
236 ''',
237 c_type=c_type(typeinfo[key]),
238 c_name=c_fun(key))
240 ret += mcgen('''
242 ''')
244 if base:
245 base_fields = find_struct(base)['data']
246 if discriminator:
247 base_fields = base_fields.copy()
248 del base_fields[discriminator]
249 ret += generate_struct_fields(base_fields)
250 else:
251 assert not discriminator
253 ret += mcgen('''
255 ''')
256 if discriminator == {}:
257 ret += mcgen('''
258 extern const int %(name)s_qtypes[];
259 ''',
260 name=name)
263 return ret
265 def generate_type_cleanup_decl(name):
266 ret = mcgen('''
267 void qapi_free_%(type)s(%(c_type)s obj);
268 ''',
269 c_type=c_type(name),type=name)
270 return ret
272 def generate_type_cleanup(name):
273 ret = mcgen('''
275 void qapi_free_%(type)s(%(c_type)s obj)
277 QapiDeallocVisitor *md;
278 Visitor *v;
280 if (!obj) {
281 return;
284 md = qapi_dealloc_visitor_new();
285 v = qapi_dealloc_get_visitor(md);
286 visit_type_%(type)s(v, &obj, NULL, NULL);
287 qapi_dealloc_visitor_cleanup(md);
289 ''',
290 c_type=c_type(name),type=name)
291 return ret
294 try:
295 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
296 ["source", "header", "builtins",
297 "prefix=", "input-file=", "output-dir="])
298 except getopt.GetoptError, err:
299 print str(err)
300 sys.exit(1)
302 output_dir = ""
303 input_file = ""
304 prefix = ""
305 c_file = 'qapi-types.c'
306 h_file = 'qapi-types.h'
308 do_c = False
309 do_h = False
310 do_builtins = False
312 for o, a in opts:
313 if o in ("-p", "--prefix"):
314 prefix = a
315 elif o in ("-i", "--input-file"):
316 input_file = a
317 elif o in ("-o", "--output-dir"):
318 output_dir = a + "/"
319 elif o in ("-c", "--source"):
320 do_c = True
321 elif o in ("-h", "--header"):
322 do_h = True
323 elif o in ("-b", "--builtins"):
324 do_builtins = True
326 if not do_c and not do_h:
327 do_c = True
328 do_h = True
330 c_file = output_dir + prefix + c_file
331 h_file = output_dir + prefix + h_file
333 try:
334 os.makedirs(output_dir)
335 except os.error, e:
336 if e.errno != errno.EEXIST:
337 raise
339 def maybe_open(really, name, opt):
340 if really:
341 return open(name, opt)
342 else:
343 import StringIO
344 return StringIO.StringIO()
346 fdef = maybe_open(do_c, c_file, 'w')
347 fdecl = maybe_open(do_h, h_file, 'w')
349 fdef.write(mcgen('''
350 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
353 * deallocation functions for schema-defined QAPI types
355 * Copyright IBM, Corp. 2011
357 * Authors:
358 * Anthony Liguori <aliguori@us.ibm.com>
359 * Michael Roth <mdroth@linux.vnet.ibm.com>
361 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
362 * See the COPYING.LIB file in the top-level directory.
366 #include "qapi/dealloc-visitor.h"
367 #include "%(prefix)sqapi-types.h"
368 #include "%(prefix)sqapi-visit.h"
370 ''', prefix=prefix))
372 fdecl.write(mcgen('''
373 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
376 * schema-defined QAPI types
378 * Copyright IBM, Corp. 2011
380 * Authors:
381 * Anthony Liguori <aliguori@us.ibm.com>
383 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
384 * See the COPYING.LIB file in the top-level directory.
388 #ifndef %(guard)s
389 #define %(guard)s
391 #include <stdbool.h>
392 #include <stdint.h>
394 ''',
395 guard=guardname(h_file)))
397 exprs = parse_schema(input_file)
398 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
400 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
401 for typename in builtin_types:
402 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
403 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
405 for expr in exprs:
406 ret = "\n"
407 if expr.has_key('type'):
408 ret += generate_fwd_struct(expr['type'], expr['data'])
409 elif expr.has_key('enum'):
410 ret += generate_enum(expr['enum'], expr['data']) + "\n"
411 ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
412 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
413 elif expr.has_key('union'):
414 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
415 enum_define = discriminator_find_enum_define(expr)
416 if not enum_define:
417 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
418 fdef.write(generate_enum_lookup('%sKind' % expr['union'],
419 expr['data'].keys()))
420 if expr.get('discriminator') == {}:
421 fdef.write(generate_anon_union_qtypes(expr))
422 else:
423 continue
424 fdecl.write(ret)
426 # to avoid header dependency hell, we always generate declarations
427 # for built-in types in our header files and simply guard them
428 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
429 for typename in builtin_types:
430 fdecl.write(generate_type_cleanup_decl(typename + "List"))
431 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
433 # ...this doesn't work for cases where we link in multiple objects that
434 # have the functions defined, so we use -b option to provide control
435 # over these cases
436 if do_builtins:
437 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
438 for typename in builtin_types:
439 fdef.write(generate_type_cleanup(typename + "List"))
440 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
442 for expr in exprs:
443 ret = "\n"
444 if expr.has_key('type'):
445 ret += generate_struct(expr) + "\n"
446 ret += generate_type_cleanup_decl(expr['type'] + "List")
447 fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
448 ret += generate_type_cleanup_decl(expr['type'])
449 fdef.write(generate_type_cleanup(expr['type']) + "\n")
450 elif expr.has_key('union'):
451 ret += generate_union(expr)
452 ret += generate_type_cleanup_decl(expr['union'] + "List")
453 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
454 ret += generate_type_cleanup_decl(expr['union'])
455 fdef.write(generate_type_cleanup(expr['union']) + "\n")
456 elif expr.has_key('enum'):
457 ret += generate_type_cleanup_decl(expr['enum'] + "List")
458 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
459 else:
460 continue
461 fdecl.write(ret)
463 fdecl.write('''
464 #endif
465 ''')
467 fdecl.flush()
468 fdecl.close()
470 fdef.flush()
471 fdef.close()