qapi-types.py 10.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#
# QAPI types generator
#
# Copyright IBM, Corp. 2011
#
# Authors:
#  Anthony Liguori <aliguori@us.ibm.com>
#
# This work is licensed under the terms of the GNU GPLv2.
# See the COPYING.LIB file in the top-level directory.

from ordereddict import OrderedDict
from qapi import *
import sys
import os
import getopt
import errno

19 20 21 22 23 24
def generate_fwd_struct(name, members, builtin_type=False):
    if builtin_type:
        return mcgen('''

typedef struct %(name)sList
{
25 26 27 28
    union {
        %(type)s value;
        uint64_t padding;
    };
29 30 31 32 33 34
    struct %(name)sList *next;
} %(name)sList;
''',
                     type=c_type(name),
                     name=name)

35
    return mcgen('''
36

37 38 39 40
typedef struct %(name)s %(name)s;

typedef struct %(name)sList
{
41 42 43 44
    union {
        %(name)s *value;
        uint64_t padding;
    };
45 46 47 48 49
    struct %(name)sList *next;
} %(name)sList;
''',
                 name=name)

50 51 52 53 54 55 56 57 58 59
def generate_fwd_enum_struct(name, members):
    return mcgen('''
typedef struct %(name)sList
{
    %(name)s value;
    struct %(name)sList *next;
} %(name)sList;
''',
                 name=name)

60 61
def generate_struct_fields(members):
    ret = ''
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

    for argname, argentry, optional, structured in parse_args(members):
        if optional:
            ret += mcgen('''
    bool has_%(c_name)s;
''',
                         c_name=c_var(argname))
        if structured:
            push_indent()
            ret += generate_struct("", argname, argentry)
            pop_indent()
        else:
            ret += mcgen('''
    %(c_type)s %(c_name)s;
''',
                     c_type=c_type(argentry), c_name=c_var(argname))

79 80 81 82 83 84 85 86 87 88 89
    return ret

def generate_struct(structname, fieldname, members):
    ret = mcgen('''
struct %(name)s
{
''',
          name=structname)

    ret += generate_struct_fields(members)

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    if len(fieldname):
        fieldname = " " + fieldname
    ret += mcgen('''
}%(field)s;
''',
            field=fieldname)

    return ret

def generate_enum_lookup(name, values):
    ret = mcgen('''
const char *%(name)s_lookup[] = {
''',
                         name=name)
    i = 0
    for value in values:
        ret += mcgen('''
    "%(value)s",
''',
109
                     value=value)
110 111 112 113 114 115 116 117

    ret += mcgen('''
    NULL,
};

''')
    return ret

118 119
def generate_enum_name(name):
    if name.isupper():
120
        return c_fun(name, False)
121
    new_name = ''
122
    for c in c_fun(name, False):
123 124 125 126 127
        if c.isupper():
            new_name += '_'
        new_name += c
    return new_name.lstrip('_').upper()

128 129 130 131 132 133 134 135 136 137 138 139
def generate_enum(name, values):
    lookup_decl = mcgen('''
extern const char *%(name)s_lookup[];
''',
                name=name)

    enum_decl = mcgen('''
typedef enum %(name)s
{
''',
                name=name)

140 141 142
    # append automatically generated _MAX value
    enum_values = values + [ 'MAX' ]

143
    i = 0
144
    for value in enum_values:
145 146 147 148
        enum_decl += mcgen('''
    %(abbrev)s_%(value)s = %(i)d,
''',
                     abbrev=de_camel_case(name).upper(),
149
                     value=generate_enum_name(value),
150 151 152 153 154 155 156 157 158 159
                     i=i)
        i += 1

    enum_decl += mcgen('''
} %(name)s;
''',
                 name=name)

    return lookup_decl + enum_decl

K
Kevin Wolf 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
def generate_anon_union_qtypes(expr):

    name = expr['union']
    members = expr['data']

    ret = mcgen('''
const int %(name)s_qtypes[QTYPE_MAX] = {
''',
    name=name)

    for key in members:
        qapi_type = members[key]
        if builtin_type_qtypes.has_key(qapi_type):
            qtype = builtin_type_qtypes[qapi_type]
        elif find_struct(qapi_type):
            qtype = "QTYPE_QDICT"
        elif find_union(qapi_type):
            qtype = "QTYPE_QDICT"
        else:
            assert False, "Invalid anonymous union member"

        ret += mcgen('''
    [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
''',
        qtype = qtype,
        abbrev = de_camel_case(name).upper(),
        enum = c_fun(de_camel_case(key),False).upper())

    ret += mcgen('''
};
''')
    return ret


194 195 196 197
def generate_union(expr):

    name = expr['union']
    typeinfo = expr['data']
198

199
    base = expr.get('base')
200
    discriminator = expr.get('discriminator')
201

202 203 204 205 206
    ret = mcgen('''
struct %(name)s
{
    %(name)sKind kind;
    union {
207
        void *data;
208 209 210 211 212 213 214 215
''',
                name=name)

    for key in typeinfo:
        ret += mcgen('''
        %(c_type)s %(c_name)s;
''',
                     c_type=c_type(typeinfo[key]),
216
                     c_name=c_fun(key))
217 218 219

    ret += mcgen('''
    };
220 221 222
''')

    if base:
223 224 225 226 227 228 229
        base_fields = find_struct(base)['data']
        if discriminator:
            base_fields = base_fields.copy()
            del base_fields[discriminator]
        ret += generate_struct_fields(base_fields)
    else:
        assert not discriminator
230 231

    ret += mcgen('''
232 233
};
''')
K
Kevin Wolf 已提交
234 235 236 237 238 239
    if discriminator == {}:
        ret += mcgen('''
extern const int %(name)s_qtypes[];
''',
            name=name)

240 241 242 243 244 245 246 247 248 249 250 251

    return ret

def generate_type_cleanup_decl(name):
    ret = mcgen('''
void qapi_free_%(type)s(%(c_type)s obj);
''',
                c_type=c_type(name),type=name)
    return ret

def generate_type_cleanup(name):
    ret = mcgen('''
252

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
void qapi_free_%(type)s(%(c_type)s obj)
{
    QapiDeallocVisitor *md;
    Visitor *v;

    if (!obj) {
        return;
    }

    md = qapi_dealloc_visitor_new();
    v = qapi_dealloc_get_visitor(md);
    visit_type_%(type)s(v, &obj, NULL, NULL);
    qapi_dealloc_visitor_cleanup(md);
}
''',
                c_type=c_type(name),type=name)
    return ret


try:
273 274 275
    opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
                                   ["source", "header", "builtins",
                                    "prefix=", "output-dir="])
276 277 278 279 280 281 282 283 284
except getopt.GetoptError, err:
    print str(err)
    sys.exit(1)

output_dir = ""
prefix = ""
c_file = 'qapi-types.c'
h_file = 'qapi-types.h'

285 286
do_c = False
do_h = False
287
do_builtins = False
288

289 290 291 292 293
for o, a in opts:
    if o in ("-p", "--prefix"):
        prefix = a
    elif o in ("-o", "--output-dir"):
        output_dir = a + "/"
294 295
    elif o in ("-c", "--source"):
        do_c = True
A
Avi Kivity 已提交
296 297
    elif o in ("-h", "--header"):
        do_h = True
298 299
    elif o in ("-b", "--builtins"):
        do_builtins = True
300 301 302 303

if not do_c and not do_h:
    do_c = True
    do_h = True
304 305 306 307 308 309 310 311 312 313

c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file

try:
    os.makedirs(output_dir)
except os.error, e:
    if e.errno != errno.EEXIST:
        raise

314 315 316
def maybe_open(really, name, opt):
    if really:
        return open(name, opt)
A
Avi Kivity 已提交
317 318 319
    else:
        import StringIO
        return StringIO.StringIO()
320 321 322

fdef = maybe_open(do_c, c_file, 'w')
fdecl = maybe_open(do_h, h_file, 'w')
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

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

/*
 * deallocation functions for schema-defined QAPI types
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */

341
#include "qapi/dealloc-visitor.h"
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"

''',             prefix=prefix))

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

/*
 * schema-defined QAPI types
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */

#ifndef %(guard)s
#define %(guard)s

366 367
#include <stdbool.h>
#include <stdint.h>
368

369 370 371 372
''',
                  guard=guardname(h_file)))

exprs = parse_schema(sys.stdin)
373
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
374

375 376 377 378 379
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for typename in builtin_types:
    fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))

380 381 382 383 384
for expr in exprs:
    ret = "\n"
    if expr.has_key('type'):
        ret += generate_fwd_struct(expr['type'], expr['data'])
    elif expr.has_key('enum'):
385 386
        ret += generate_enum(expr['enum'], expr['data']) + "\n"
        ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
387 388 389 390
        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
    elif expr.has_key('union'):
        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
391
        fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
K
Kevin Wolf 已提交
392 393
        if expr.get('discriminator') == {}:
            fdef.write(generate_anon_union_qtypes(expr))
394 395 396 397
    else:
        continue
    fdecl.write(ret)

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
# to avoid header dependency hell, we always generate declarations
# for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
for typename in builtin_types:
    fdecl.write(generate_type_cleanup_decl(typename + "List"))
fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))

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

414 415 416 417
for expr in exprs:
    ret = "\n"
    if expr.has_key('type'):
        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
418 419
        ret += generate_type_cleanup_decl(expr['type'] + "List")
        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
420 421 422
        ret += generate_type_cleanup_decl(expr['type'])
        fdef.write(generate_type_cleanup(expr['type']) + "\n")
    elif expr.has_key('union'):
423
        ret += generate_union(expr)
424 425 426 427
        ret += generate_type_cleanup_decl(expr['union'] + "List")
        fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
        ret += generate_type_cleanup_decl(expr['union'])
        fdef.write(generate_type_cleanup(expr['union']) + "\n")
428 429 430
    elif expr.has_key('enum'):
        ret += generate_type_cleanup_decl(expr['enum'] + "List")
        fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
431 432 433 434 435 436 437 438 439 440
    else:
        continue
    fdecl.write(ret)

fdecl.write('''
#endif
''')

fdecl.flush()
fdecl.close()
441 442 443

fdef.flush()
fdef.close()