2011-07-19 23:50:40 +04:00
|
|
|
#
|
|
|
|
# QAPI types generator
|
|
|
|
#
|
|
|
|
# Copyright IBM, Corp. 2011
|
|
|
|
#
|
|
|
|
# Authors:
|
|
|
|
# Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
#
|
2014-03-01 11:40:34 +04:00
|
|
|
# This work is licensed under the terms of the GNU GPL, version 2.
|
|
|
|
# See the COPYING file in the top-level directory.
|
2011-07-19 23:50:40 +04:00
|
|
|
|
|
|
|
from ordereddict import OrderedDict
|
|
|
|
from qapi import *
|
|
|
|
|
2015-06-12 10:22:32 +03:00
|
|
|
def generate_fwd_builtin(name):
|
|
|
|
return mcgen('''
|
2013-05-11 02:46:00 +04:00
|
|
|
|
2015-07-01 17:55:15 +03:00
|
|
|
typedef struct %(name)sList {
|
2013-05-27 07:20:58 +04:00
|
|
|
union {
|
|
|
|
%(type)s value;
|
|
|
|
uint64_t padding;
|
|
|
|
};
|
2013-05-11 02:46:00 +04:00
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
2015-06-12 10:22:32 +03:00
|
|
|
type=c_type(name),
|
|
|
|
name=name)
|
2013-05-11 02:46:00 +04:00
|
|
|
|
2015-06-12 10:22:32 +03:00
|
|
|
def generate_fwd_struct(name):
|
2011-07-19 23:50:40 +04:00
|
|
|
return mcgen('''
|
2013-05-11 02:46:00 +04:00
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
typedef struct %(name)s %(name)s;
|
|
|
|
|
2015-07-01 17:55:15 +03:00
|
|
|
typedef struct %(name)sList {
|
2013-05-27 07:20:58 +04:00
|
|
|
union {
|
|
|
|
%(name)s *value;
|
|
|
|
uint64_t padding;
|
|
|
|
};
|
2011-07-19 23:50:40 +04:00
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
2015-05-14 15:50:57 +03:00
|
|
|
name=c_name(name))
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-06-12 11:40:17 +03:00
|
|
|
def generate_fwd_enum_struct(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 06:56:23 +04:00
|
|
|
return mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
typedef struct %(name)sList {
|
2013-09-01 02:36:17 +04:00
|
|
|
union {
|
|
|
|
%(name)s value;
|
|
|
|
uint64_t padding;
|
|
|
|
};
|
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 06:56:23 +04:00
|
|
|
struct %(name)sList *next;
|
|
|
|
} %(name)sList;
|
|
|
|
''',
|
2015-05-14 15:50:56 +03:00
|
|
|
name=c_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 06:56:23 +04:00
|
|
|
|
2013-07-02 14:18:18 +04:00
|
|
|
def generate_struct_fields(members):
|
|
|
|
ret = ''
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-05-04 18:05:33 +03:00
|
|
|
for argname, argentry, optional in parse_args(members):
|
2011-07-19 23:50:40 +04:00
|
|
|
if optional:
|
|
|
|
ret += mcgen('''
|
|
|
|
bool has_%(c_name)s;
|
|
|
|
''',
|
2015-05-14 15:50:48 +03:00
|
|
|
c_name=c_name(argname))
|
2015-05-04 18:05:33 +03:00
|
|
|
ret += mcgen('''
|
2011-07-19 23:50:40 +04:00
|
|
|
%(c_type)s %(c_name)s;
|
|
|
|
''',
|
2015-05-14 15:50:48 +03:00
|
|
|
c_type=c_type(argentry), c_name=c_name(argname))
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2013-07-02 14:18:18 +04:00
|
|
|
return ret
|
|
|
|
|
2013-09-18 19:22:02 +04:00
|
|
|
def generate_struct(expr):
|
|
|
|
|
2015-05-04 18:05:25 +03:00
|
|
|
structname = expr.get('struct', "")
|
2013-09-18 19:22:02 +04:00
|
|
|
members = expr['data']
|
2013-09-19 13:56:36 +04:00
|
|
|
base = expr.get('base')
|
2013-09-18 19:22:02 +04:00
|
|
|
|
2013-07-02 14:18:18 +04:00
|
|
|
ret = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
struct %(name)s {
|
2013-07-02 14:18:18 +04:00
|
|
|
''',
|
2015-05-14 15:50:57 +03:00
|
|
|
name=c_name(structname))
|
2013-07-02 14:18:18 +04:00
|
|
|
|
2013-09-19 13:56:36 +04:00
|
|
|
if base:
|
|
|
|
ret += generate_struct_fields({'base': base})
|
|
|
|
|
2013-07-02 14:18:18 +04:00
|
|
|
ret += generate_struct_fields(members)
|
|
|
|
|
2015-01-20 18:19:32 +03:00
|
|
|
# Make sure that all structs have at least one field; this avoids
|
|
|
|
# potential issues with attempting to malloc space for zero-length structs
|
|
|
|
# in C, and also incompatibility with C++ (where an empty struct is size 1).
|
|
|
|
if not base and not members:
|
|
|
|
ret += mcgen('''
|
|
|
|
char qapi_dummy_field_for_empty_struct;
|
|
|
|
''')
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
ret += mcgen('''
|
2015-06-12 10:45:55 +03:00
|
|
|
};
|
|
|
|
''')
|
2011-07-19 23:50:40 +04:00
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_enum_lookup(name, values):
|
|
|
|
ret = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
const char *const %(name)s_lookup[] = {
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
2015-05-14 15:50:56 +03:00
|
|
|
name=c_name(name))
|
2011-07-19 23:50:40 +04:00
|
|
|
for value in values:
|
2015-05-14 15:50:50 +03:00
|
|
|
index = c_enum_const(name, value)
|
2011-07-19 23:50:40 +04:00
|
|
|
ret += mcgen('''
|
qapi-types: add C99 index names to arrays
It's not easy to figure out how monitor translates
strings: most QEMU code deals with translated indexes,
these are translated using _lookup arrays,
so you need to find the array name, and find the
appropriate offset.
This patch adds C99 indexes to lookup arrays, which makes it possible to
find the correct key using simple grep, and see that the matching is
correct at a glance.
Example:
Before:
const char *MigrationCapability_lookup[] = {
"xbzrle",
"rdma-pin-all",
"auto-converge",
"zero-blocks",
NULL,
};
After:
const char *MigrationCapability_lookup[] = {
[MIGRATION_CAPABILITY_XBZRLE] = "xbzrle",
[MIGRATION_CAPABILITY_RDMA_PIN_ALL] = "rdma-pin-all",
[MIGRATION_CAPABILITY_AUTO_CONVERGE] = "auto-converge",
[MIGRATION_CAPABILITY_ZERO_BLOCKS] = "zero-blocks",
[MIGRATION_CAPABILITY_MAX] = NULL,
};
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-19 13:13:10 +03:00
|
|
|
[%(index)s] = "%(value)s",
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
qapi-types: add C99 index names to arrays
It's not easy to figure out how monitor translates
strings: most QEMU code deals with translated indexes,
these are translated using _lookup arrays,
so you need to find the array name, and find the
appropriate offset.
This patch adds C99 indexes to lookup arrays, which makes it possible to
find the correct key using simple grep, and see that the matching is
correct at a glance.
Example:
Before:
const char *MigrationCapability_lookup[] = {
"xbzrle",
"rdma-pin-all",
"auto-converge",
"zero-blocks",
NULL,
};
After:
const char *MigrationCapability_lookup[] = {
[MIGRATION_CAPABILITY_XBZRLE] = "xbzrle",
[MIGRATION_CAPABILITY_RDMA_PIN_ALL] = "rdma-pin-all",
[MIGRATION_CAPABILITY_AUTO_CONVERGE] = "auto-converge",
[MIGRATION_CAPABILITY_ZERO_BLOCKS] = "zero-blocks",
[MIGRATION_CAPABILITY_MAX] = NULL,
};
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-19 13:13:10 +03:00
|
|
|
index = index, value = value)
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-05-14 15:50:50 +03:00
|
|
|
max_index = c_enum_const(name, 'MAX')
|
2011-07-19 23:50:40 +04:00
|
|
|
ret += mcgen('''
|
qapi-types: add C99 index names to arrays
It's not easy to figure out how monitor translates
strings: most QEMU code deals with translated indexes,
these are translated using _lookup arrays,
so you need to find the array name, and find the
appropriate offset.
This patch adds C99 indexes to lookup arrays, which makes it possible to
find the correct key using simple grep, and see that the matching is
correct at a glance.
Example:
Before:
const char *MigrationCapability_lookup[] = {
"xbzrle",
"rdma-pin-all",
"auto-converge",
"zero-blocks",
NULL,
};
After:
const char *MigrationCapability_lookup[] = {
[MIGRATION_CAPABILITY_XBZRLE] = "xbzrle",
[MIGRATION_CAPABILITY_RDMA_PIN_ALL] = "rdma-pin-all",
[MIGRATION_CAPABILITY_AUTO_CONVERGE] = "auto-converge",
[MIGRATION_CAPABILITY_ZERO_BLOCKS] = "zero-blocks",
[MIGRATION_CAPABILITY_MAX] = NULL,
};
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-19 13:13:10 +03:00
|
|
|
[%(max_index)s] = NULL,
|
2011-07-19 23:50:40 +04:00
|
|
|
};
|
qapi-types: add C99 index names to arrays
It's not easy to figure out how monitor translates
strings: most QEMU code deals with translated indexes,
these are translated using _lookup arrays,
so you need to find the array name, and find the
appropriate offset.
This patch adds C99 indexes to lookup arrays, which makes it possible to
find the correct key using simple grep, and see that the matching is
correct at a glance.
Example:
Before:
const char *MigrationCapability_lookup[] = {
"xbzrle",
"rdma-pin-all",
"auto-converge",
"zero-blocks",
NULL,
};
After:
const char *MigrationCapability_lookup[] = {
[MIGRATION_CAPABILITY_XBZRLE] = "xbzrle",
[MIGRATION_CAPABILITY_RDMA_PIN_ALL] = "rdma-pin-all",
[MIGRATION_CAPABILITY_AUTO_CONVERGE] = "auto-converge",
[MIGRATION_CAPABILITY_ZERO_BLOCKS] = "zero-blocks",
[MIGRATION_CAPABILITY_MAX] = NULL,
};
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-19 13:13:10 +03:00
|
|
|
''',
|
|
|
|
max_index=max_index)
|
2011-07-19 23:50:40 +04:00
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_enum(name, values):
|
2015-05-14 15:50:56 +03:00
|
|
|
name = c_name(name)
|
2011-07-19 23:50:40 +04:00
|
|
|
lookup_decl = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
extern const char *const %(name)s_lookup[];
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
enum_decl = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
typedef enum %(name)s {
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
2011-09-30 19:43:27 +04:00
|
|
|
# append automatically generated _MAX value
|
|
|
|
enum_values = values + [ 'MAX' ]
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
i = 0
|
2011-09-30 19:43:27 +04:00
|
|
|
for value in enum_values:
|
2015-05-14 15:50:50 +03:00
|
|
|
enum_full_value = c_enum_const(name, value)
|
2011-07-19 23:50:40 +04:00
|
|
|
enum_decl += mcgen('''
|
2014-03-05 06:44:36 +04:00
|
|
|
%(enum_full_value)s = %(i)d,
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
2014-03-05 06:44:36 +04:00
|
|
|
enum_full_value = enum_full_value,
|
2011-07-19 23:50:40 +04:00
|
|
|
i=i)
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
enum_decl += mcgen('''
|
|
|
|
} %(name)s;
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
2015-07-01 17:55:15 +03:00
|
|
|
return enum_decl + lookup_decl
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-05-04 18:05:10 +03:00
|
|
|
def generate_alternate_qtypes(expr):
|
2013-07-08 18:14:21 +04:00
|
|
|
|
2015-05-04 18:05:13 +03:00
|
|
|
name = expr['alternate']
|
2013-07-08 18:14:21 +04:00
|
|
|
members = expr['data']
|
|
|
|
|
|
|
|
ret = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
2013-07-08 18:14:21 +04:00
|
|
|
const int %(name)s_qtypes[QTYPE_MAX] = {
|
|
|
|
''',
|
2015-05-14 15:51:00 +03:00
|
|
|
name=c_name(name))
|
2013-07-08 18:14:21 +04:00
|
|
|
|
|
|
|
for key in members:
|
2015-05-04 18:05:10 +03:00
|
|
|
qtype = find_alternate_member_qtype(members[key])
|
2015-05-04 18:05:13 +03:00
|
|
|
assert qtype, "Invalid alternate member"
|
2013-07-08 18:14:21 +04:00
|
|
|
|
|
|
|
ret += mcgen('''
|
2015-05-14 15:51:00 +03:00
|
|
|
[%(qtype)s] = %(enum_const)s,
|
2013-07-08 18:14:21 +04:00
|
|
|
''',
|
2015-05-14 15:51:00 +03:00
|
|
|
qtype = qtype,
|
|
|
|
enum_const = c_enum_const(name + 'Kind', key))
|
2013-07-08 18:14:21 +04:00
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
};
|
|
|
|
''')
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2015-05-04 18:05:13 +03:00
|
|
|
def generate_union(expr, meta):
|
2013-07-02 14:18:47 +04:00
|
|
|
|
2015-05-14 15:50:58 +03:00
|
|
|
name = c_name(expr[meta])
|
2013-07-02 14:18:47 +04:00
|
|
|
typeinfo = expr['data']
|
2013-07-03 17:58:57 +04:00
|
|
|
|
2013-07-02 14:18:47 +04:00
|
|
|
base = expr.get('base')
|
2013-07-03 17:58:57 +04:00
|
|
|
discriminator = expr.get('discriminator')
|
2013-07-02 14:18:47 +04:00
|
|
|
|
2014-03-07 05:08:56 +04:00
|
|
|
enum_define = discriminator_find_enum_define(expr)
|
|
|
|
if enum_define:
|
|
|
|
discriminator_type_name = enum_define['enum_name']
|
|
|
|
else:
|
|
|
|
discriminator_type_name = '%sKind' % (name)
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
ret = mcgen('''
|
2015-07-01 17:55:15 +03:00
|
|
|
|
|
|
|
struct %(name)s {
|
qapi: Generate a nicer struct for flat unions
The struct generated for a flat union is weird: the members of its
base are at the end, except for the union tag, which is at the
beginning.
Example: qapi-schema-test.json has
{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
We generate:
struct UserDefFlatUnion
{
EnumOne enum1;
union {
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
char *string;
};
Change to put all base members at the beginning, unadulterated. Not
only is this easier to understand, it also permits casting the flat
union to its base, if that should become useful.
We now generate:
struct UserDefFlatUnion
{
/* Members inherited from UserDefUnionBase: */
char *string;
EnumOne enum1;
/* Own members: */
union { /* union tag is @enum1 */
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
};
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-28 21:05:53 +03:00
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
if base:
|
|
|
|
ret += mcgen('''
|
|
|
|
/* Members inherited from %(c_name)s: */
|
|
|
|
''',
|
|
|
|
c_name=c_name(base))
|
|
|
|
base_fields = find_struct(base)['data']
|
|
|
|
ret += generate_struct_fields(base_fields)
|
|
|
|
ret += mcgen('''
|
|
|
|
/* Own members: */
|
|
|
|
''')
|
|
|
|
else:
|
|
|
|
assert not discriminator
|
|
|
|
ret += mcgen('''
|
|
|
|
%(discriminator_type_name)s kind;
|
|
|
|
''',
|
|
|
|
discriminator_type_name=c_name(discriminator_type_name))
|
|
|
|
|
2015-07-31 02:07:17 +03:00
|
|
|
# FIXME: What purpose does data serve, besides preventing a union that
|
|
|
|
# has a branch named 'data'? We use it in qapi-visit.py to decide
|
|
|
|
# whether to bypass the switch statement if visiting the discriminator
|
|
|
|
# failed; but since we 0-initialize structs, and cannot tell what
|
|
|
|
# branch of the union is in use if the discriminator is invalid, there
|
|
|
|
# should not be any data leaks even without a data pointer. Or, if
|
|
|
|
# 'data' is merely added to guarantee we don't have an empty union,
|
|
|
|
# shouldn't we enforce that at .json parse time?
|
qapi: Generate a nicer struct for flat unions
The struct generated for a flat union is weird: the members of its
base are at the end, except for the union tag, which is at the
beginning.
Example: qapi-schema-test.json has
{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
We generate:
struct UserDefFlatUnion
{
EnumOne enum1;
union {
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
char *string;
};
Change to put all base members at the beginning, unadulterated. Not
only is this easier to understand, it also permits casting the flat
union to its base, if that should become useful.
We now generate:
struct UserDefFlatUnion
{
/* Members inherited from UserDefUnionBase: */
char *string;
EnumOne enum1;
/* Own members: */
union { /* union tag is @enum1 */
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
};
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-28 21:05:53 +03:00
|
|
|
ret += mcgen('''
|
|
|
|
union { /* union tag is @%(c_name)s */
|
2012-03-06 21:55:56 +04:00
|
|
|
void *data;
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
qapi: Generate a nicer struct for flat unions
The struct generated for a flat union is weird: the members of its
base are at the end, except for the union tag, which is at the
beginning.
Example: qapi-schema-test.json has
{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
We generate:
struct UserDefFlatUnion
{
EnumOne enum1;
union {
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
char *string;
};
Change to put all base members at the beginning, unadulterated. Not
only is this easier to understand, it also permits casting the flat
union to its base, if that should become useful.
We now generate:
struct UserDefFlatUnion
{
/* Members inherited from UserDefUnionBase: */
char *string;
EnumOne enum1;
/* Own members: */
union { /* union tag is @enum1 */
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
};
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-28 21:05:53 +03:00
|
|
|
c_name=c_name(discriminator or 'kind'))
|
2011-07-19 23:50:40 +04:00
|
|
|
|
|
|
|
for key in typeinfo:
|
|
|
|
ret += mcgen('''
|
|
|
|
%(c_type)s %(c_name)s;
|
|
|
|
''',
|
|
|
|
c_type=c_type(typeinfo[key]),
|
2015-05-14 15:50:48 +03:00
|
|
|
c_name=c_name(key))
|
2011-07-19 23:50:40 +04:00
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
};
|
|
|
|
};
|
|
|
|
''')
|
2015-05-04 18:05:13 +03:00
|
|
|
if meta == 'alternate':
|
2013-07-08 18:14:21 +04:00
|
|
|
ret += mcgen('''
|
|
|
|
extern const int %(name)s_qtypes[];
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_type_cleanup_decl(name):
|
|
|
|
ret = mcgen('''
|
2015-05-14 15:50:56 +03:00
|
|
|
void qapi_free_%(name)s(%(c_type)s obj);
|
2011-07-19 23:50:40 +04:00
|
|
|
''',
|
2015-05-14 15:50:56 +03:00
|
|
|
c_type=c_type(name), name=c_name(name))
|
2011-07-19 23:50:40 +04:00
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_type_cleanup(name):
|
|
|
|
ret = mcgen('''
|
2013-05-11 02:46:00 +04:00
|
|
|
|
2015-05-14 15:50:56 +03:00
|
|
|
void qapi_free_%(name)s(%(c_type)s obj)
|
2011-07-19 23:50:40 +04:00
|
|
|
{
|
|
|
|
QapiDeallocVisitor *md;
|
|
|
|
Visitor *v;
|
|
|
|
|
|
|
|
if (!obj) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
md = qapi_dealloc_visitor_new();
|
|
|
|
v = qapi_dealloc_get_visitor(md);
|
2015-05-14 15:50:56 +03:00
|
|
|
visit_type_%(name)s(v, &obj, NULL, NULL);
|
2011-07-19 23:50:40 +04:00
|
|
|
qapi_dealloc_visitor_cleanup(md);
|
|
|
|
}
|
|
|
|
''',
|
2015-05-14 15:50:56 +03:00
|
|
|
c_type=c_type(name), name=c_name(name))
|
2011-07-19 23:50:40 +04:00
|
|
|
return ret
|
|
|
|
|
2013-05-11 02:46:00 +04:00
|
|
|
do_builtins = False
|
2011-12-27 18:02:16 +04:00
|
|
|
|
2015-04-02 14:12:21 +03:00
|
|
|
(input_file, output_dir, do_c, do_h, prefix, opts) = \
|
|
|
|
parse_command_line("b", ["builtins"])
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
for o, a in opts:
|
2015-04-02 14:12:21 +03:00
|
|
|
if o in ("-b", "--builtins"):
|
2013-05-11 02:46:00 +04:00
|
|
|
do_builtins = True
|
2011-12-27 18:02:16 +04:00
|
|
|
|
2015-04-02 15:46:39 +03:00
|
|
|
c_comment = '''
|
2011-07-19 23:50:40 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
2015-04-02 15:46:39 +03:00
|
|
|
'''
|
|
|
|
h_comment = '''
|
2011-07-19 23:50:40 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
2015-04-02 15:46:39 +03:00
|
|
|
'''
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-04-02 15:46:39 +03:00
|
|
|
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
|
|
|
|
'qapi-types.c', 'qapi-types.h',
|
|
|
|
c_comment, h_comment)
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2015-04-02 15:46:39 +03:00
|
|
|
fdef.write(mcgen('''
|
|
|
|
#include "qapi/dealloc-visitor.h"
|
|
|
|
#include "%(prefix)sqapi-types.h"
|
|
|
|
#include "%(prefix)sqapi-visit.h"
|
|
|
|
''',
|
|
|
|
prefix=prefix))
|
|
|
|
|
|
|
|
fdecl.write(mcgen('''
|
2012-08-20 03:39:37 +04:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2015-04-02 15:46:39 +03:00
|
|
|
'''))
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2014-05-02 17:52:35 +04:00
|
|
|
exprs = parse_schema(input_file)
|
2011-07-19 23:50:40 +04:00
|
|
|
|
2013-05-11 02:46:00 +04:00
|
|
|
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
2015-05-04 18:05:00 +03:00
|
|
|
for typename in builtin_types.keys():
|
2015-06-12 10:22:32 +03:00
|
|
|
fdecl.write(generate_fwd_builtin(typename))
|
2013-05-11 02:46:00 +04:00
|
|
|
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
for expr in exprs:
|
2015-07-01 17:55:15 +03:00
|
|
|
ret = ""
|
2015-05-04 18:05:25 +03:00
|
|
|
if expr.has_key('struct'):
|
2015-06-12 11:40:17 +03:00
|
|
|
ret += generate_fwd_struct(expr['struct'])
|
2011-07-19 23:50:40 +04:00
|
|
|
elif expr.has_key('enum'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += generate_enum(expr['enum'], expr['data'])
|
2015-06-12 11:40:17 +03:00
|
|
|
ret += generate_fwd_enum_struct(expr['enum'])
|
2011-07-19 23:50:40 +04:00
|
|
|
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
|
|
|
|
elif expr.has_key('union'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += generate_fwd_struct(expr['union'])
|
2014-03-07 05:08:56 +04:00
|
|
|
enum_define = discriminator_find_enum_define(expr)
|
|
|
|
if not enum_define:
|
|
|
|
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
|
|
|
|
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
|
|
|
|
expr['data'].keys()))
|
2015-05-04 18:05:13 +03:00
|
|
|
elif expr.has_key('alternate'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += generate_fwd_struct(expr['alternate'])
|
2015-05-04 18:05:13 +03:00
|
|
|
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
|
|
|
|
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
|
|
|
|
expr['data'].keys()))
|
|
|
|
fdef.write(generate_alternate_qtypes(expr))
|
2011-07-19 23:50:40 +04:00
|
|
|
else:
|
|
|
|
continue
|
|
|
|
fdecl.write(ret)
|
|
|
|
|
2013-05-11 02:46:00 +04: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"))
|
2015-05-04 18:05:00 +03:00
|
|
|
for typename in builtin_types.keys():
|
2013-05-11 02:46:00 +04:00
|
|
|
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:
|
2015-05-04 18:05:00 +03:00
|
|
|
for typename in builtin_types.keys():
|
2013-05-11 02:46:00 +04:00
|
|
|
fdef.write(generate_type_cleanup(typename + "List"))
|
|
|
|
|
2011-07-19 23:50:40 +04:00
|
|
|
for expr in exprs:
|
2015-07-01 17:55:15 +03:00
|
|
|
ret = ""
|
2015-05-04 18:05:25 +03:00
|
|
|
if expr.has_key('struct'):
|
2013-09-18 19:22:02 +04:00
|
|
|
ret += generate_struct(expr) + "\n"
|
2015-05-04 18:05:25 +03:00
|
|
|
ret += generate_type_cleanup_decl(expr['struct'] + "List")
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['struct'] + "List"))
|
2015-05-04 18:05:25 +03:00
|
|
|
ret += generate_type_cleanup_decl(expr['struct'])
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['struct']))
|
2011-07-19 23:50:40 +04:00
|
|
|
elif expr.has_key('union'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += generate_union(expr, 'union') + "\n"
|
2012-03-06 21:55:56 +04:00
|
|
|
ret += generate_type_cleanup_decl(expr['union'] + "List")
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['union'] + "List"))
|
2012-03-06 21:55:56 +04:00
|
|
|
ret += generate_type_cleanup_decl(expr['union'])
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['union']))
|
2015-05-04 18:05:13 +03:00
|
|
|
elif expr.has_key('alternate'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += generate_union(expr, 'alternate') + "\n"
|
2015-05-04 18:05:13 +03:00
|
|
|
ret += generate_type_cleanup_decl(expr['alternate'] + "List")
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
|
2015-05-04 18:05:13 +03:00
|
|
|
ret += generate_type_cleanup_decl(expr['alternate'])
|
2015-07-01 17:55:15 +03:00
|
|
|
fdef.write(generate_type_cleanup(expr['alternate']))
|
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 06:56:23 +04:00
|
|
|
elif expr.has_key('enum'):
|
2015-07-01 17:55:15 +03:00
|
|
|
ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
|
|
|
|
fdef.write(generate_type_cleanup(expr['enum'] + "List"))
|
2011-07-19 23:50:40 +04:00
|
|
|
else:
|
|
|
|
continue
|
|
|
|
fdecl.write(ret)
|
|
|
|
|
2015-04-02 15:46:39 +03:00
|
|
|
close_output(fdef, fdecl)
|