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