2011-07-20 03:50:40 +08:00
|
|
|
#
|
|
|
|
# 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
|
|
|
|
|
2013-05-11 06:46:00 +08:00
|
|
|
def generate_fwd_struct(name, members, builtin_type=False):
|
|
|
|
if builtin_type:
|
|
|
|
return mcgen('''
|
|
|
|
|
|
|
|
typedef struct %(name)sList
|
|
|
|
{
|
2013-05-27 11:20:58 +08:00
|
|
|
union {
|
|
|
|
%(type)s value;
|
|
|
|
uint64_t padding;
|
|
|
|
};
|
2013-05-11 06:46:00 +08:00
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
|
|
|
type=c_type(name),
|
|
|
|
name=name)
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
return mcgen('''
|
2013-05-11 06:46:00 +08:00
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
typedef struct %(name)s %(name)s;
|
|
|
|
|
|
|
|
typedef struct %(name)sList
|
|
|
|
{
|
2013-05-27 11:20:58 +08:00
|
|
|
union {
|
|
|
|
%(name)s *value;
|
|
|
|
uint64_t padding;
|
|
|
|
};
|
2011-07-20 03:50:40 +08:00
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 10:56:23 +08:00
|
|
|
def generate_fwd_enum_struct(name, members):
|
|
|
|
return mcgen('''
|
|
|
|
typedef struct %(name)sList
|
|
|
|
{
|
|
|
|
%(name)s value;
|
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
def generate_struct(structname, fieldname, members):
|
|
|
|
ret = mcgen('''
|
|
|
|
struct %(name)s
|
|
|
|
{
|
|
|
|
''',
|
|
|
|
name=structname)
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
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",
|
|
|
|
''',
|
2012-07-27 20:38:05 +08:00
|
|
|
value=value)
|
2011-07-20 03:50:40 +08:00
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
''')
|
|
|
|
return ret
|
|
|
|
|
2012-07-28 02:44:25 +08:00
|
|
|
def generate_enum_name(name):
|
|
|
|
if name.isupper():
|
2012-09-19 22:31:06 +08:00
|
|
|
return c_fun(name, False)
|
2012-07-28 02:44:25 +08:00
|
|
|
new_name = ''
|
2012-09-19 22:31:06 +08:00
|
|
|
for c in c_fun(name, False):
|
2012-07-28 02:44:25 +08:00
|
|
|
if c.isupper():
|
|
|
|
new_name += '_'
|
|
|
|
new_name += c
|
|
|
|
return new_name.lstrip('_').upper()
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
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)
|
|
|
|
|
2011-09-30 23:43:27 +08:00
|
|
|
# append automatically generated _MAX value
|
|
|
|
enum_values = values + [ 'MAX' ]
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
i = 0
|
2011-09-30 23:43:27 +08:00
|
|
|
for value in enum_values:
|
2011-07-20 03:50:40 +08:00
|
|
|
enum_decl += mcgen('''
|
|
|
|
%(abbrev)s_%(value)s = %(i)d,
|
|
|
|
''',
|
|
|
|
abbrev=de_camel_case(name).upper(),
|
2012-07-28 02:44:25 +08:00
|
|
|
value=generate_enum_name(value),
|
2011-07-20 03:50:40 +08:00
|
|
|
i=i)
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
enum_decl += mcgen('''
|
|
|
|
} %(name)s;
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
return lookup_decl + enum_decl
|
|
|
|
|
2013-07-02 18:18:47 +08:00
|
|
|
def generate_union(expr):
|
|
|
|
|
|
|
|
name = expr['union']
|
|
|
|
typeinfo = expr['data']
|
2013-07-03 21:58:57 +08:00
|
|
|
|
2013-07-02 18:18:47 +08:00
|
|
|
base = expr.get('base')
|
2013-07-03 21:58:57 +08:00
|
|
|
discriminator = expr.get('discriminator')
|
2013-07-02 18:18:47 +08:00
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
ret = mcgen('''
|
|
|
|
struct %(name)s
|
|
|
|
{
|
|
|
|
%(name)sKind kind;
|
|
|
|
union {
|
2012-03-07 01:55:56 +08:00
|
|
|
void *data;
|
2011-07-20 03:50:40 +08:00
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
for key in typeinfo:
|
|
|
|
ret += mcgen('''
|
|
|
|
%(c_type)s %(c_name)s;
|
|
|
|
''',
|
|
|
|
c_type=c_type(typeinfo[key]),
|
2012-03-20 21:54:35 +08:00
|
|
|
c_name=c_fun(key))
|
2011-07-20 03:50:40 +08:00
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
};
|
2013-07-02 18:18:47 +08:00
|
|
|
''')
|
|
|
|
|
|
|
|
if base:
|
2013-07-03 21:58:57 +08:00
|
|
|
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
|
2013-07-02 18:18:47 +08:00
|
|
|
|
|
|
|
ret += mcgen('''
|
2011-07-20 03:50:40 +08:00
|
|
|
};
|
|
|
|
''')
|
|
|
|
|
|
|
|
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('''
|
2013-05-11 06:46:00 +08:00
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
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:
|
2013-05-11 06:46:00 +08:00
|
|
|
opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
|
|
|
|
["source", "header", "builtins",
|
|
|
|
"prefix=", "output-dir="])
|
2011-07-20 03:50:40 +08:00
|
|
|
except getopt.GetoptError, err:
|
|
|
|
print str(err)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
output_dir = ""
|
|
|
|
prefix = ""
|
|
|
|
c_file = 'qapi-types.c'
|
|
|
|
h_file = 'qapi-types.h'
|
|
|
|
|
2011-12-27 22:02:16 +08:00
|
|
|
do_c = False
|
|
|
|
do_h = False
|
2013-05-11 06:46:00 +08:00
|
|
|
do_builtins = False
|
2011-12-27 22:02:16 +08:00
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
for o, a in opts:
|
|
|
|
if o in ("-p", "--prefix"):
|
|
|
|
prefix = a
|
|
|
|
elif o in ("-o", "--output-dir"):
|
|
|
|
output_dir = a + "/"
|
2011-12-27 22:02:16 +08:00
|
|
|
elif o in ("-c", "--source"):
|
|
|
|
do_c = True
|
2011-12-28 18:26:58 +08:00
|
|
|
elif o in ("-h", "--header"):
|
|
|
|
do_h = True
|
2013-05-11 06:46:00 +08:00
|
|
|
elif o in ("-b", "--builtins"):
|
|
|
|
do_builtins = True
|
2011-12-27 22:02:16 +08:00
|
|
|
|
|
|
|
if not do_c and not do_h:
|
|
|
|
do_c = True
|
|
|
|
do_h = True
|
2011-07-20 03:50:40 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-12-27 22:02:16 +08:00
|
|
|
def maybe_open(really, name, opt):
|
|
|
|
if really:
|
|
|
|
return open(name, opt)
|
2011-12-28 18:26:58 +08:00
|
|
|
else:
|
|
|
|
import StringIO
|
|
|
|
return StringIO.StringIO()
|
2011-12-27 22:02:16 +08:00
|
|
|
|
|
|
|
fdef = maybe_open(do_c, c_file, 'w')
|
|
|
|
fdecl = maybe_open(do_h, h_file, 'w')
|
2011-07-20 03:50:40 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-12-18 01:19:43 +08:00
|
|
|
#include "qapi/dealloc-visitor.h"
|
2011-07-20 03:50:40 +08:00
|
|
|
#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
|
|
|
|
|
2012-08-20 07:39:37 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2012-07-27 21:56:33 +08:00
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
''',
|
|
|
|
guard=guardname(h_file)))
|
|
|
|
|
|
|
|
exprs = parse_schema(sys.stdin)
|
2011-12-13 04:29:33 +08:00
|
|
|
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
|
2011-07-20 03:50:40 +08:00
|
|
|
|
2013-05-11 06:46:00 +08:00
|
|
|
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"))
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
for expr in exprs:
|
|
|
|
ret = "\n"
|
|
|
|
if expr.has_key('type'):
|
|
|
|
ret += generate_fwd_struct(expr['type'], expr['data'])
|
|
|
|
elif expr.has_key('enum'):
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 10:56:23 +08:00
|
|
|
ret += generate_enum(expr['enum'], expr['data']) + "\n"
|
|
|
|
ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
|
2011-07-20 03:50:40 +08:00
|
|
|
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())
|
2012-03-07 01:55:56 +08:00
|
|
|
fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
|
2011-07-20 03:50:40 +08:00
|
|
|
else:
|
|
|
|
continue
|
|
|
|
fdecl.write(ret)
|
|
|
|
|
2013-05-11 06:46:00 +08:00
|
|
|
# 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"))
|
|
|
|
|
2011-07-20 03:50:40 +08:00
|
|
|
for expr in exprs:
|
|
|
|
ret = "\n"
|
|
|
|
if expr.has_key('type'):
|
|
|
|
ret += generate_struct(expr['type'], "", expr['data']) + "\n"
|
2011-09-16 03:39:53 +08:00
|
|
|
ret += generate_type_cleanup_decl(expr['type'] + "List")
|
|
|
|
fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
|
2011-07-20 03:50:40 +08:00
|
|
|
ret += generate_type_cleanup_decl(expr['type'])
|
|
|
|
fdef.write(generate_type_cleanup(expr['type']) + "\n")
|
|
|
|
elif expr.has_key('union'):
|
2013-07-02 18:18:47 +08:00
|
|
|
ret += generate_union(expr)
|
2012-03-07 01:55:56 +08:00
|
|
|
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")
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 10:56:23 +08:00
|
|
|
elif expr.has_key('enum'):
|
|
|
|
ret += generate_type_cleanup_decl(expr['enum'] + "List")
|
|
|
|
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
|
2011-07-20 03:50:40 +08:00
|
|
|
else:
|
|
|
|
continue
|
|
|
|
fdecl.write(ret)
|
|
|
|
|
|
|
|
fdecl.write('''
|
|
|
|
#endif
|
|
|
|
''')
|
|
|
|
|
|
|
|
fdecl.flush()
|
|
|
|
fdecl.close()
|
2011-09-03 01:34:46 +08:00
|
|
|
|
|
|
|
fdef.flush()
|
|
|
|
fdef.close()
|