]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/qapi-types.py
qapi: Rename _generate_enum_string() to camel_to_upper()
[mirror_qemu.git] / scripts / qapi-types.py
1 #
2 # QAPI types generator
3 #
4 # Copyright IBM, Corp. 2011
5 #
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
8 #
9 # This work is licensed under the terms of the GNU GPL, version 2.
10 # See the COPYING file in the top-level directory.
11
12 from ordereddict import OrderedDict
13 from qapi import *
14 import sys
15 import os
16 import getopt
17 import errno
18
19 def generate_fwd_struct(name, members, builtin_type=False):
20 if builtin_type:
21 return mcgen('''
22
23 typedef struct %(name)sList
24 {
25 union {
26 %(type)s value;
27 uint64_t padding;
28 };
29 struct %(name)sList *next;
30 } %(name)sList;
31 ''',
32 type=c_type(name),
33 name=name)
34
35 return mcgen('''
36
37 typedef struct %(name)s %(name)s;
38
39 typedef struct %(name)sList
40 {
41 union {
42 %(name)s *value;
43 uint64_t padding;
44 };
45 struct %(name)sList *next;
46 } %(name)sList;
47 ''',
48 name=name)
49
50 def generate_fwd_enum_struct(name, members):
51 return mcgen('''
52 typedef struct %(name)sList
53 {
54 union {
55 %(name)s value;
56 uint64_t padding;
57 };
58 struct %(name)sList *next;
59 } %(name)sList;
60 ''',
61 name=name)
62
63 def generate_struct_fields(members):
64 ret = ''
65
66 for argname, argentry, optional in parse_args(members):
67 if optional:
68 ret += mcgen('''
69 bool has_%(c_name)s;
70 ''',
71 c_name=c_name(argname))
72 ret += mcgen('''
73 %(c_type)s %(c_name)s;
74 ''',
75 c_type=c_type(argentry), c_name=c_name(argname))
76
77 return ret
78
79 def generate_struct(expr):
80
81 structname = expr.get('struct', "")
82 fieldname = expr.get('field', "")
83 members = expr['data']
84 base = expr.get('base')
85
86 ret = mcgen('''
87 struct %(name)s
88 {
89 ''',
90 name=structname)
91
92 if base:
93 ret += generate_struct_fields({'base': base})
94
95 ret += generate_struct_fields(members)
96
97 # Make sure that all structs have at least one field; this avoids
98 # potential issues with attempting to malloc space for zero-length structs
99 # in C, and also incompatibility with C++ (where an empty struct is size 1).
100 if not base and not members:
101 ret += mcgen('''
102 char qapi_dummy_field_for_empty_struct;
103 ''')
104
105 if len(fieldname):
106 fieldname = " " + fieldname
107 ret += mcgen('''
108 }%(field)s;
109 ''',
110 field=fieldname)
111
112 return ret
113
114 def generate_enum_lookup(name, values):
115 ret = mcgen('''
116 const char *%(name)s_lookup[] = {
117 ''',
118 name=name)
119 i = 0
120 for value in values:
121 index = generate_enum_full_value(name, value)
122 ret += mcgen('''
123 [%(index)s] = "%(value)s",
124 ''',
125 index = index, value = value)
126
127 max_index = generate_enum_full_value(name, 'MAX')
128 ret += mcgen('''
129 [%(max_index)s] = NULL,
130 };
131
132 ''',
133 max_index=max_index)
134 return ret
135
136 def generate_enum(name, values):
137 lookup_decl = mcgen('''
138 extern const char *%(name)s_lookup[];
139 ''',
140 name=name)
141
142 enum_decl = mcgen('''
143 typedef enum %(name)s
144 {
145 ''',
146 name=name)
147
148 # append automatically generated _MAX value
149 enum_values = values + [ 'MAX' ]
150
151 i = 0
152 for value in enum_values:
153 enum_full_value = generate_enum_full_value(name, value)
154 enum_decl += mcgen('''
155 %(enum_full_value)s = %(i)d,
156 ''',
157 enum_full_value = enum_full_value,
158 i=i)
159 i += 1
160
161 enum_decl += mcgen('''
162 } %(name)s;
163 ''',
164 name=name)
165
166 return lookup_decl + enum_decl
167
168 def generate_alternate_qtypes(expr):
169
170 name = expr['alternate']
171 members = expr['data']
172
173 ret = mcgen('''
174 const int %(name)s_qtypes[QTYPE_MAX] = {
175 ''',
176 name=name)
177
178 for key in members:
179 qtype = find_alternate_member_qtype(members[key])
180 assert qtype, "Invalid alternate member"
181
182 ret += mcgen('''
183 [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
184 ''',
185 qtype = qtype,
186 abbrev = de_camel_case(name).upper(),
187 enum = c_name(de_camel_case(key),False).upper())
188
189 ret += mcgen('''
190 };
191 ''')
192 return ret
193
194
195 def generate_union(expr, meta):
196
197 name = expr[meta]
198 typeinfo = expr['data']
199
200 base = expr.get('base')
201 discriminator = expr.get('discriminator')
202
203 enum_define = discriminator_find_enum_define(expr)
204 if enum_define:
205 discriminator_type_name = enum_define['enum_name']
206 else:
207 discriminator_type_name = '%sKind' % (name)
208
209 ret = mcgen('''
210 struct %(name)s
211 {
212 %(discriminator_type_name)s kind;
213 union {
214 void *data;
215 ''',
216 name=name,
217 discriminator_type_name=discriminator_type_name)
218
219 for key in typeinfo:
220 ret += mcgen('''
221 %(c_type)s %(c_name)s;
222 ''',
223 c_type=c_type(typeinfo[key]),
224 c_name=c_name(key))
225
226 ret += mcgen('''
227 };
228 ''')
229
230 if base:
231 assert discriminator
232 base_fields = find_struct(base)['data'].copy()
233 del base_fields[discriminator]
234 ret += generate_struct_fields(base_fields)
235 else:
236 assert not discriminator
237
238 ret += mcgen('''
239 };
240 ''')
241 if meta == 'alternate':
242 ret += mcgen('''
243 extern const int %(name)s_qtypes[];
244 ''',
245 name=name)
246
247
248 return ret
249
250 def generate_type_cleanup_decl(name):
251 ret = mcgen('''
252 void qapi_free_%(type)s(%(c_type)s obj);
253 ''',
254 c_type=c_type(name),type=name)
255 return ret
256
257 def generate_type_cleanup(name):
258 ret = mcgen('''
259
260 void qapi_free_%(type)s(%(c_type)s obj)
261 {
262 QapiDeallocVisitor *md;
263 Visitor *v;
264
265 if (!obj) {
266 return;
267 }
268
269 md = qapi_dealloc_visitor_new();
270 v = qapi_dealloc_get_visitor(md);
271 visit_type_%(type)s(v, &obj, NULL, NULL);
272 qapi_dealloc_visitor_cleanup(md);
273 }
274 ''',
275 c_type=c_type(name),type=name)
276 return ret
277
278
279 try:
280 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
281 ["source", "header", "builtins",
282 "prefix=", "input-file=", "output-dir="])
283 except getopt.GetoptError, err:
284 print str(err)
285 sys.exit(1)
286
287 output_dir = ""
288 input_file = ""
289 prefix = ""
290 c_file = 'qapi-types.c'
291 h_file = 'qapi-types.h'
292
293 do_c = False
294 do_h = False
295 do_builtins = False
296
297 for o, a in opts:
298 if o in ("-p", "--prefix"):
299 prefix = a
300 elif o in ("-i", "--input-file"):
301 input_file = a
302 elif o in ("-o", "--output-dir"):
303 output_dir = a + "/"
304 elif o in ("-c", "--source"):
305 do_c = True
306 elif o in ("-h", "--header"):
307 do_h = True
308 elif o in ("-b", "--builtins"):
309 do_builtins = True
310
311 if not do_c and not do_h:
312 do_c = True
313 do_h = True
314
315 c_file = output_dir + prefix + c_file
316 h_file = output_dir + prefix + h_file
317
318 try:
319 os.makedirs(output_dir)
320 except os.error, e:
321 if e.errno != errno.EEXIST:
322 raise
323
324 def maybe_open(really, name, opt):
325 if really:
326 return open(name, opt)
327 else:
328 import StringIO
329 return StringIO.StringIO()
330
331 fdef = maybe_open(do_c, c_file, 'w')
332 fdecl = maybe_open(do_h, h_file, 'w')
333
334 fdef.write(mcgen('''
335 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
336
337 /*
338 * deallocation functions for schema-defined QAPI types
339 *
340 * Copyright IBM, Corp. 2011
341 *
342 * Authors:
343 * Anthony Liguori <aliguori@us.ibm.com>
344 * Michael Roth <mdroth@linux.vnet.ibm.com>
345 *
346 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
347 * See the COPYING.LIB file in the top-level directory.
348 *
349 */
350
351 #include "qapi/dealloc-visitor.h"
352 #include "%(prefix)sqapi-types.h"
353 #include "%(prefix)sqapi-visit.h"
354
355 ''', prefix=prefix))
356
357 fdecl.write(mcgen('''
358 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
359
360 /*
361 * schema-defined QAPI types
362 *
363 * Copyright IBM, Corp. 2011
364 *
365 * Authors:
366 * Anthony Liguori <aliguori@us.ibm.com>
367 *
368 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
369 * See the COPYING.LIB file in the top-level directory.
370 *
371 */
372
373 #ifndef %(guard)s
374 #define %(guard)s
375
376 #include <stdbool.h>
377 #include <stdint.h>
378
379 ''',
380 guard=guardname(h_file)))
381
382 exprs = parse_schema(input_file)
383 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
384
385 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
386 for typename in builtin_types.keys():
387 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
388 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
389
390 for expr in exprs:
391 ret = "\n"
392 if expr.has_key('struct'):
393 ret += generate_fwd_struct(expr['struct'], expr['data'])
394 elif expr.has_key('enum'):
395 ret += generate_enum(expr['enum'], expr['data']) + "\n"
396 ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
397 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
398 elif expr.has_key('union'):
399 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
400 enum_define = discriminator_find_enum_define(expr)
401 if not enum_define:
402 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
403 fdef.write(generate_enum_lookup('%sKind' % expr['union'],
404 expr['data'].keys()))
405 elif expr.has_key('alternate'):
406 ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
407 ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
408 fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
409 expr['data'].keys()))
410 fdef.write(generate_alternate_qtypes(expr))
411 else:
412 continue
413 fdecl.write(ret)
414
415 # to avoid header dependency hell, we always generate declarations
416 # for built-in types in our header files and simply guard them
417 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
418 for typename in builtin_types.keys():
419 fdecl.write(generate_type_cleanup_decl(typename + "List"))
420 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
421
422 # ...this doesn't work for cases where we link in multiple objects that
423 # have the functions defined, so we use -b option to provide control
424 # over these cases
425 if do_builtins:
426 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
427 for typename in builtin_types.keys():
428 fdef.write(generate_type_cleanup(typename + "List"))
429 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
430
431 for expr in exprs:
432 ret = "\n"
433 if expr.has_key('struct'):
434 ret += generate_struct(expr) + "\n"
435 ret += generate_type_cleanup_decl(expr['struct'] + "List")
436 fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
437 ret += generate_type_cleanup_decl(expr['struct'])
438 fdef.write(generate_type_cleanup(expr['struct']) + "\n")
439 elif expr.has_key('union'):
440 ret += generate_union(expr, 'union')
441 ret += generate_type_cleanup_decl(expr['union'] + "List")
442 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
443 ret += generate_type_cleanup_decl(expr['union'])
444 fdef.write(generate_type_cleanup(expr['union']) + "\n")
445 elif expr.has_key('alternate'):
446 ret += generate_union(expr, 'alternate')
447 ret += generate_type_cleanup_decl(expr['alternate'] + "List")
448 fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
449 ret += generate_type_cleanup_decl(expr['alternate'])
450 fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
451 elif expr.has_key('enum'):
452 ret += generate_type_cleanup_decl(expr['enum'] + "List")
453 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
454 else:
455 continue
456 fdecl.write(ret)
457
458 fdecl.write('''
459 #endif
460 ''')
461
462 fdecl.flush()
463 fdecl.close()
464
465 fdef.flush()
466 fdef.close()