Statistics
| Branch: | Revision:

root / scripts / qapi-types.py @ 69dd62df

History | View | Annotate | Download (10.1 kB)

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, 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
    %(name)s value;
55
    struct %(name)sList *next;
56
} %(name)sList;
57
''',
58
                 name=name)
59

    
60
def generate_struct(structname, fieldname, members):
61
    ret = mcgen('''
62
struct %(name)s
63
{
64
''',
65
          name=structname)
66

    
67
    for argname, argentry, optional, structured in parse_args(members):
68
        if optional:
69
            ret += mcgen('''
70
    bool has_%(c_name)s;
71
''',
72
                         c_name=c_var(argname))
73
        if structured:
74
            push_indent()
75
            ret += generate_struct("", argname, argentry)
76
            pop_indent()
77
        else:
78
            ret += mcgen('''
79
    %(c_type)s %(c_name)s;
80
''',
81
                     c_type=c_type(argentry), c_name=c_var(argname))
82

    
83
    if len(fieldname):
84
        fieldname = " " + fieldname
85
    ret += mcgen('''
86
}%(field)s;
87
''',
88
            field=fieldname)
89

    
90
    return ret
91

    
92
def generate_enum_lookup(name, values):
93
    ret = mcgen('''
94
const char *%(name)s_lookup[] = {
95
''',
96
                         name=name)
97
    i = 0
98
    for value in values:
99
        ret += mcgen('''
100
    "%(value)s",
101
''',
102
                     value=value)
103

    
104
    ret += mcgen('''
105
    NULL,
106
};
107

108
''')
109
    return ret
110

    
111
def generate_enum_name(name):
112
    if name.isupper():
113
        return c_fun(name, False)
114
    new_name = ''
115
    for c in c_fun(name, False):
116
        if c.isupper():
117
            new_name += '_'
118
        new_name += c
119
    return new_name.lstrip('_').upper()
120

    
121
def generate_enum(name, values):
122
    lookup_decl = mcgen('''
123
extern const char *%(name)s_lookup[];
124
''',
125
                name=name)
126

    
127
    enum_decl = mcgen('''
128
typedef enum %(name)s
129
{
130
''',
131
                name=name)
132

    
133
    # append automatically generated _MAX value
134
    enum_values = values + [ 'MAX' ]
135

    
136
    i = 0
137
    for value in enum_values:
138
        enum_decl += mcgen('''
139
    %(abbrev)s_%(value)s = %(i)d,
140
''',
141
                     abbrev=de_camel_case(name).upper(),
142
                     value=generate_enum_name(value),
143
                     i=i)
144
        i += 1
145

    
146
    enum_decl += mcgen('''
147
} %(name)s;
148
''',
149
                 name=name)
150

    
151
    return lookup_decl + enum_decl
152

    
153
def generate_anon_union_qtypes(expr):
154

    
155
    name = expr['union']
156
    members = expr['data']
157

    
158
    ret = mcgen('''
159
const int %(name)s_qtypes[QTYPE_MAX] = {
160
''',
161
    name=name)
162

    
163
    for key in members:
164
        qapi_type = members[key]
165
        if builtin_type_qtypes.has_key(qapi_type):
166
            qtype = builtin_type_qtypes[qapi_type]
167
        elif find_struct(qapi_type):
168
            qtype = "QTYPE_QDICT"
169
        elif find_union(qapi_type):
170
            qtype = "QTYPE_QDICT"
171
        else:
172
            assert False, "Invalid anonymous union member"
173

    
174
        ret += mcgen('''
175
    [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
176
''',
177
        qtype = qtype,
178
        abbrev = de_camel_case(name).upper(),
179
        enum = c_fun(de_camel_case(key),False).upper())
180

    
181
    ret += mcgen('''
182
};
183
''')
184
    return ret
185

    
186

    
187
def generate_union(expr):
188

    
189
    name = expr['union']
190
    typeinfo = expr['data']
191

    
192
    base = expr.get('base')
193
    discriminator = expr.get('discriminator')
194

    
195
    ret = mcgen('''
196
struct %(name)s
197
{
198
    %(name)sKind kind;
199
    union {
200
        void *data;
201
''',
202
                name=name)
203

    
204
    for key in typeinfo:
205
        ret += mcgen('''
206
        %(c_type)s %(c_name)s;
207
''',
208
                     c_type=c_type(typeinfo[key]),
209
                     c_name=c_fun(key))
210

    
211
    ret += mcgen('''
212
    };
213
''')
214

    
215
    if base:
216
        base_fields = find_struct(base)['data']
217
        if discriminator:
218
            base_fields = base_fields.copy()
219
            del base_fields[discriminator]
220
        ret += generate_struct_fields(base_fields)
221
    else:
222
        assert not discriminator
223

    
224
    ret += mcgen('''
225
};
226
''')
227
    if discriminator == {}:
228
        ret += mcgen('''
229
extern const int %(name)s_qtypes[];
230
''',
231
            name=name)
232

    
233

    
234
    return ret
235

    
236
def generate_type_cleanup_decl(name):
237
    ret = mcgen('''
238
void qapi_free_%(type)s(%(c_type)s obj);
239
''',
240
                c_type=c_type(name),type=name)
241
    return ret
242

    
243
def generate_type_cleanup(name):
244
    ret = mcgen('''
245

246
void qapi_free_%(type)s(%(c_type)s obj)
247
{
248
    QapiDeallocVisitor *md;
249
    Visitor *v;
250

251
    if (!obj) {
252
        return;
253
    }
254

255
    md = qapi_dealloc_visitor_new();
256
    v = qapi_dealloc_get_visitor(md);
257
    visit_type_%(type)s(v, &obj, NULL, NULL);
258
    qapi_dealloc_visitor_cleanup(md);
259
}
260
''',
261
                c_type=c_type(name),type=name)
262
    return ret
263

    
264

    
265
try:
266
    opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
267
                                   ["source", "header", "builtins",
268
                                    "prefix=", "output-dir="])
269
except getopt.GetoptError, err:
270
    print str(err)
271
    sys.exit(1)
272

    
273
output_dir = ""
274
prefix = ""
275
c_file = 'qapi-types.c'
276
h_file = 'qapi-types.h'
277

    
278
do_c = False
279
do_h = False
280
do_builtins = False
281

    
282
for o, a in opts:
283
    if o in ("-p", "--prefix"):
284
        prefix = a
285
    elif o in ("-o", "--output-dir"):
286
        output_dir = a + "/"
287
    elif o in ("-c", "--source"):
288
        do_c = True
289
    elif o in ("-h", "--header"):
290
        do_h = True
291
    elif o in ("-b", "--builtins"):
292
        do_builtins = True
293

    
294
if not do_c and not do_h:
295
    do_c = True
296
    do_h = True
297

    
298
c_file = output_dir + prefix + c_file
299
h_file = output_dir + prefix + h_file
300

    
301
try:
302
    os.makedirs(output_dir)
303
except os.error, e:
304
    if e.errno != errno.EEXIST:
305
        raise
306

    
307
def maybe_open(really, name, opt):
308
    if really:
309
        return open(name, opt)
310
    else:
311
        import StringIO
312
        return StringIO.StringIO()
313

    
314
fdef = maybe_open(do_c, c_file, 'w')
315
fdecl = maybe_open(do_h, h_file, 'w')
316

    
317
fdef.write(mcgen('''
318
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
319

320
/*
321
 * deallocation functions for schema-defined QAPI types
322
 *
323
 * Copyright IBM, Corp. 2011
324
 *
325
 * Authors:
326
 *  Anthony Liguori   <aliguori@us.ibm.com>
327
 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
328
 *
329
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
330
 * See the COPYING.LIB file in the top-level directory.
331
 *
332
 */
333

334
#include "qapi/dealloc-visitor.h"
335
#include "%(prefix)sqapi-types.h"
336
#include "%(prefix)sqapi-visit.h"
337

338
''',             prefix=prefix))
339

    
340
fdecl.write(mcgen('''
341
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
342

343
/*
344
 * schema-defined QAPI types
345
 *
346
 * Copyright IBM, Corp. 2011
347
 *
348
 * Authors:
349
 *  Anthony Liguori   <aliguori@us.ibm.com>
350
 *
351
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
352
 * See the COPYING.LIB file in the top-level directory.
353
 *
354
 */
355

356
#ifndef %(guard)s
357
#define %(guard)s
358

359
#include <stdbool.h>
360
#include <stdint.h>
361

362
''',
363
                  guard=guardname(h_file)))
364

    
365
exprs = parse_schema(sys.stdin)
366
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
367

    
368
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
369
for typename in builtin_types:
370
    fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
371
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
372

    
373
for expr in exprs:
374
    ret = "\n"
375
    if expr.has_key('type'):
376
        ret += generate_fwd_struct(expr['type'], expr['data'])
377
    elif expr.has_key('enum'):
378
        ret += generate_enum(expr['enum'], expr['data']) + "\n"
379
        ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
380
        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
381
    elif expr.has_key('union'):
382
        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
383
        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
384
        fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
385
        if expr.get('discriminator') == {}:
386
            fdef.write(generate_anon_union_qtypes(expr))
387
    else:
388
        continue
389
    fdecl.write(ret)
390

    
391
# to avoid header dependency hell, we always generate declarations
392
# for built-in types in our header files and simply guard them
393
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
394
for typename in builtin_types:
395
    fdecl.write(generate_type_cleanup_decl(typename + "List"))
396
fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
397

    
398
# ...this doesn't work for cases where we link in multiple objects that
399
# have the functions defined, so we use -b option to provide control
400
# over these cases
401
if do_builtins:
402
    fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
403
    for typename in builtin_types:
404
        fdef.write(generate_type_cleanup(typename + "List"))
405
    fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
406

    
407
for expr in exprs:
408
    ret = "\n"
409
    if expr.has_key('type'):
410
        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
411
        ret += generate_type_cleanup_decl(expr['type'] + "List")
412
        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
413
        ret += generate_type_cleanup_decl(expr['type'])
414
        fdef.write(generate_type_cleanup(expr['type']) + "\n")
415
    elif expr.has_key('union'):
416
        ret += generate_union(expr)
417
        ret += generate_type_cleanup_decl(expr['union'] + "List")
418
        fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
419
        ret += generate_type_cleanup_decl(expr['union'])
420
        fdef.write(generate_type_cleanup(expr['union']) + "\n")
421
    elif expr.has_key('enum'):
422
        ret += generate_type_cleanup_decl(expr['enum'] + "List")
423
        fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
424
    else:
425
        continue
426
    fdecl.write(ret)
427

    
428
fdecl.write('''
429
#endif
430
''')
431

    
432
fdecl.flush()
433
fdecl.close()
434

    
435
fdef.flush()
436
fdef.close()