Merge remote-tracking branch 'afaerber/qom-cpu' into staging
[sdk/emulator/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 GPLv2.
10 # See the COPYING.LIB 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):
20     return mcgen('''
21 typedef struct %(name)s %(name)s;
22
23 typedef struct %(name)sList
24 {
25     %(name)s *value;
26     struct %(name)sList *next;
27 } %(name)sList;
28 ''',
29                  name=name)
30
31 def generate_fwd_enum_struct(name, members):
32     return mcgen('''
33 typedef struct %(name)sList
34 {
35     %(name)s value;
36     struct %(name)sList *next;
37 } %(name)sList;
38 ''',
39                  name=name)
40
41 def generate_struct(structname, fieldname, members):
42     ret = mcgen('''
43 struct %(name)s
44 {
45 ''',
46           name=structname)
47
48     for argname, argentry, optional, structured in parse_args(members):
49         if optional:
50             ret += mcgen('''
51     bool has_%(c_name)s;
52 ''',
53                          c_name=c_var(argname))
54         if structured:
55             push_indent()
56             ret += generate_struct("", argname, argentry)
57             pop_indent()
58         else:
59             ret += mcgen('''
60     %(c_type)s %(c_name)s;
61 ''',
62                      c_type=c_type(argentry), c_name=c_var(argname))
63
64     if len(fieldname):
65         fieldname = " " + fieldname
66     ret += mcgen('''
67 }%(field)s;
68 ''',
69             field=fieldname)
70
71     return ret
72
73 def generate_enum_lookup(name, values):
74     ret = mcgen('''
75 const char *%(name)s_lookup[] = {
76 ''',
77                          name=name)
78     i = 0
79     for value in values:
80         ret += mcgen('''
81     "%(value)s",
82 ''',
83                      value=value)
84
85     ret += mcgen('''
86     NULL,
87 };
88
89 ''')
90     return ret
91
92 def generate_enum_name(name):
93     if name.isupper():
94         return c_fun(name, False)
95     new_name = ''
96     for c in c_fun(name, False):
97         if c.isupper():
98             new_name += '_'
99         new_name += c
100     return new_name.lstrip('_').upper()
101
102 def generate_enum(name, values):
103     lookup_decl = mcgen('''
104 extern const char *%(name)s_lookup[];
105 ''',
106                 name=name)
107
108     enum_decl = mcgen('''
109 typedef enum %(name)s
110 {
111 ''',
112                 name=name)
113
114     # append automatically generated _MAX value
115     enum_values = values + [ 'MAX' ]
116
117     i = 0
118     for value in enum_values:
119         enum_decl += mcgen('''
120     %(abbrev)s_%(value)s = %(i)d,
121 ''',
122                      abbrev=de_camel_case(name).upper(),
123                      value=generate_enum_name(value),
124                      i=i)
125         i += 1
126
127     enum_decl += mcgen('''
128 } %(name)s;
129 ''',
130                  name=name)
131
132     return lookup_decl + enum_decl
133
134 def generate_union(name, typeinfo):
135     ret = mcgen('''
136 struct %(name)s
137 {
138     %(name)sKind kind;
139     union {
140         void *data;
141 ''',
142                 name=name)
143
144     for key in typeinfo:
145         ret += mcgen('''
146         %(c_type)s %(c_name)s;
147 ''',
148                      c_type=c_type(typeinfo[key]),
149                      c_name=c_fun(key))
150
151     ret += mcgen('''
152     };
153 };
154 ''')
155
156     return ret
157
158 def generate_type_cleanup_decl(name):
159     ret = mcgen('''
160 void qapi_free_%(type)s(%(c_type)s obj);
161 ''',
162                 c_type=c_type(name),type=name)
163     return ret
164
165 def generate_type_cleanup(name):
166     ret = mcgen('''
167 void qapi_free_%(type)s(%(c_type)s obj)
168 {
169     QapiDeallocVisitor *md;
170     Visitor *v;
171
172     if (!obj) {
173         return;
174     }
175
176     md = qapi_dealloc_visitor_new();
177     v = qapi_dealloc_get_visitor(md);
178     visit_type_%(type)s(v, &obj, NULL, NULL);
179     qapi_dealloc_visitor_cleanup(md);
180 }
181 ''',
182                 c_type=c_type(name),type=name)
183     return ret
184
185
186 try:
187     opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
188                                    ["source", "header", "prefix=", "output-dir="])
189 except getopt.GetoptError, err:
190     print str(err)
191     sys.exit(1)
192
193 output_dir = ""
194 prefix = ""
195 c_file = 'qapi-types.c'
196 h_file = 'qapi-types.h'
197
198 do_c = False
199 do_h = False
200
201 for o, a in opts:
202     if o in ("-p", "--prefix"):
203         prefix = a
204     elif o in ("-o", "--output-dir"):
205         output_dir = a + "/"
206     elif o in ("-c", "--source"):
207         do_c = True
208     elif o in ("-h", "--header"):
209         do_h = True
210
211 if not do_c and not do_h:
212     do_c = True
213     do_h = True
214
215 c_file = output_dir + prefix + c_file
216 h_file = output_dir + prefix + h_file
217
218 try:
219     os.makedirs(output_dir)
220 except os.error, e:
221     if e.errno != errno.EEXIST:
222         raise
223
224 def maybe_open(really, name, opt):
225     if really:
226         return open(name, opt)
227     else:
228         import StringIO
229         return StringIO.StringIO()
230
231 fdef = maybe_open(do_c, c_file, 'w')
232 fdecl = maybe_open(do_h, h_file, 'w')
233
234 fdef.write(mcgen('''
235 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
236
237 /*
238  * deallocation functions for schema-defined QAPI types
239  *
240  * Copyright IBM, Corp. 2011
241  *
242  * Authors:
243  *  Anthony Liguori   <aliguori@us.ibm.com>
244  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
245  *
246  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
247  * See the COPYING.LIB file in the top-level directory.
248  *
249  */
250
251 #include "qapi/qapi-dealloc-visitor.h"
252 #include "%(prefix)sqapi-types.h"
253 #include "%(prefix)sqapi-visit.h"
254
255 ''',             prefix=prefix))
256
257 fdecl.write(mcgen('''
258 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
259
260 /*
261  * schema-defined QAPI types
262  *
263  * Copyright IBM, Corp. 2011
264  *
265  * Authors:
266  *  Anthony Liguori   <aliguori@us.ibm.com>
267  *
268  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
269  * See the COPYING.LIB file in the top-level directory.
270  *
271  */
272
273 #ifndef %(guard)s
274 #define %(guard)s
275
276 #include <stdbool.h>
277 #include <stdint.h>
278
279 ''',
280                   guard=guardname(h_file)))
281
282 exprs = parse_schema(sys.stdin)
283 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
284
285 for expr in exprs:
286     ret = "\n"
287     if expr.has_key('type'):
288         ret += generate_fwd_struct(expr['type'], expr['data'])
289     elif expr.has_key('enum'):
290         ret += generate_enum(expr['enum'], expr['data']) + "\n"
291         ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
292         fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
293     elif expr.has_key('union'):
294         ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
295         ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
296         fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
297     else:
298         continue
299     fdecl.write(ret)
300
301 for expr in exprs:
302     ret = "\n"
303     if expr.has_key('type'):
304         ret += generate_struct(expr['type'], "", expr['data']) + "\n"
305         ret += generate_type_cleanup_decl(expr['type'] + "List")
306         fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
307         ret += generate_type_cleanup_decl(expr['type'])
308         fdef.write(generate_type_cleanup(expr['type']) + "\n")
309     elif expr.has_key('union'):
310         ret += generate_union(expr['union'], expr['data'])
311         ret += generate_type_cleanup_decl(expr['union'] + "List")
312         fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
313         ret += generate_type_cleanup_decl(expr['union'])
314         fdef.write(generate_type_cleanup(expr['union']) + "\n")
315     elif expr.has_key('enum'):
316         ret += generate_type_cleanup_decl(expr['enum'] + "List")
317         fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
318     else:
319         continue
320     fdecl.write(ret)
321
322 fdecl.write('''
323 #endif
324 ''')
325
326 fdecl.flush()
327 fdecl.close()
328
329 fdef.flush()
330 fdef.close()