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