mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-03-26 18:22:55 -07:00
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2018-07-03' into staging
QAPI patches for 2018-07-03 # gpg: Signature made Tue 03 Jul 2018 21:52:55 BST # gpg: using RSA key 3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2018-07-03: qapi: add conditions to SPICE type/commands/events on the schema qapi: add conditions to VNC type/commands/events on the schema qapi: add 'If:' section to generated documentation qapi-types: add #if conditions to types & visitors qapi/events: add #if conditions to events qapi/commands: add #if conditions to commands qapi-introspect: add preprocessor conditions to generated QLit qapi-introspect: modify to_qlit() to append ',' on level > 0 qapi: add #if/#endif helpers qapi: mcgen() shouldn't indent # lines qapi: add 'ifcond' to visitor methods qapi: leave the ifcond attribute undefined until check() qapi: pass 'if' condition into QAPISchemaEntity objects qapi: add 'if' to top-level expressions Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -744,6 +744,35 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
|
||||
downstream command __com.redhat_drive-mirror.
|
||||
|
||||
|
||||
=== Configuring the schema ===
|
||||
|
||||
The 'struct', 'enum', 'union', 'alternate', 'command' and 'event'
|
||||
top-level expressions can take an 'if' key. Its value must be a string
|
||||
or a list of strings. A string is shorthand for a list containing just
|
||||
that string. The code generated for the top-level expression will then
|
||||
be guarded by #if COND for each COND in the list.
|
||||
|
||||
Example: a conditional struct
|
||||
|
||||
{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
|
||||
'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }
|
||||
|
||||
gets its generated code guarded like this:
|
||||
|
||||
#if defined(CONFIG_FOO)
|
||||
#if defined(HAVE_BAR)
|
||||
... generated code ...
|
||||
#endif /* defined(HAVE_BAR) */
|
||||
#endif /* defined(CONFIG_FOO) */
|
||||
|
||||
Please note that you are responsible to ensure that the C code will
|
||||
compile with an arbitrary combination of conditions, since the
|
||||
generators are unable to check it at this point.
|
||||
|
||||
The presence of 'if' keys in the schema is reflected through to the
|
||||
introspection output depending on the build configuration.
|
||||
|
||||
|
||||
== Client JSON Protocol introspection ==
|
||||
|
||||
Clients of a Client JSON Protocol commonly need to figure out what
|
||||
|
||||
@@ -426,6 +426,7 @@ STEXI
|
||||
Show which guest mouse is receiving events.
|
||||
ETEXI
|
||||
|
||||
#if defined(CONFIG_VNC)
|
||||
{
|
||||
.name = "vnc",
|
||||
.args_type = "",
|
||||
@@ -433,6 +434,7 @@ ETEXI
|
||||
.help = "show the vnc server status",
|
||||
.cmd = hmp_info_vnc,
|
||||
},
|
||||
#endif
|
||||
|
||||
STEXI
|
||||
@item info vnc
|
||||
|
||||
9
hmp.c
9
hmp.c
@@ -616,6 +616,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
||||
qapi_free_BlockStatsList(stats_list);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
/* Helper for hmp_info_vnc_clients, _servers */
|
||||
static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
|
||||
const char *name)
|
||||
@@ -703,6 +704,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
||||
qapi_free_VncInfo2List(info2l);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPICE
|
||||
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
||||
@@ -1772,12 +1774,14 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
static void hmp_change_read_arg(void *opaque, const char *password,
|
||||
void *readline_opaque)
|
||||
{
|
||||
qmp_change_vnc_password(password, NULL);
|
||||
monitor_read_command(opaque, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void hmp_change(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
@@ -1788,6 +1792,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
|
||||
BlockdevChangeReadOnlyMode read_only_mode = 0;
|
||||
Error *err = NULL;
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
if (strcmp(device, "vnc") == 0) {
|
||||
if (read_only) {
|
||||
monitor_printf(mon,
|
||||
@@ -1802,7 +1807,9 @@ void hmp_change(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
}
|
||||
qmp_change("vnc", target, !!arg, arg, &err);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (read_only) {
|
||||
read_only_mode =
|
||||
qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
|
||||
|
||||
@@ -1191,9 +1191,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
|
||||
*/
|
||||
static void qmp_unregister_commands_hack(void)
|
||||
{
|
||||
#ifndef CONFIG_SPICE
|
||||
qmp_unregister_command(&qmp_commands, "query-spice");
|
||||
#endif
|
||||
#ifndef CONFIG_REPLICATION
|
||||
qmp_unregister_command(&qmp_commands, "xen-set-replication");
|
||||
qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
|
||||
|
||||
@@ -320,6 +320,7 @@
|
||||
##
|
||||
{ 'struct': 'ChardevSpiceChannel', 'data': { 'type' : 'str' },
|
||||
'base': 'ChardevCommon' }
|
||||
# TODO: 'if': 'defined(CONFIG_SPICE)'
|
||||
|
||||
##
|
||||
# @ChardevSpicePort:
|
||||
@@ -332,6 +333,7 @@
|
||||
##
|
||||
{ 'struct': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' },
|
||||
'base': 'ChardevCommon' }
|
||||
# TODO: 'if': 'defined(CONFIG_SPICE)'
|
||||
|
||||
##
|
||||
# @ChardevVC:
|
||||
@@ -385,8 +387,10 @@
|
||||
'testdev': 'ChardevCommon',
|
||||
'stdio' : 'ChardevStdio',
|
||||
'console': 'ChardevCommon',
|
||||
'spicevmc' : 'ChardevSpiceChannel',
|
||||
'spiceport' : 'ChardevSpicePort',
|
||||
'spicevmc': 'ChardevSpiceChannel',
|
||||
# TODO: { 'type': 'ChardevSpiceChannel', 'if': 'defined(CONFIG_SPICE)' },
|
||||
'spiceport': 'ChardevSpicePort',
|
||||
# TODO: { 'type': 'ChardevSpicePort', 'if': 'defined(CONFIG_SPICE)' },
|
||||
'vc' : 'ChardevVC',
|
||||
'ringbuf': 'ChardevRingbuf',
|
||||
# next one is just for compatibility
|
||||
|
||||
75
qapi/ui.json
75
qapi/ui.json
@@ -118,7 +118,8 @@
|
||||
{ 'struct': 'SpiceBasicInfo',
|
||||
'data': { 'host': 'str',
|
||||
'port': 'str',
|
||||
'family': 'NetworkAddressFamily' } }
|
||||
'family': 'NetworkAddressFamily' },
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SpiceServerInfo:
|
||||
@@ -131,7 +132,8 @@
|
||||
##
|
||||
{ 'struct': 'SpiceServerInfo',
|
||||
'base': 'SpiceBasicInfo',
|
||||
'data': { '*auth': 'str' } }
|
||||
'data': { '*auth': 'str' },
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SpiceChannel:
|
||||
@@ -156,7 +158,8 @@
|
||||
{ 'struct': 'SpiceChannel',
|
||||
'base': 'SpiceBasicInfo',
|
||||
'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
|
||||
'tls': 'bool'} }
|
||||
'tls': 'bool'},
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SpiceQueryMouseMode:
|
||||
@@ -175,7 +178,8 @@
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'enum': 'SpiceQueryMouseMode',
|
||||
'data': [ 'client', 'server', 'unknown' ] }
|
||||
'data': [ 'client', 'server', 'unknown' ],
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SpiceInfo:
|
||||
@@ -212,7 +216,8 @@
|
||||
{ 'struct': 'SpiceInfo',
|
||||
'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
|
||||
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
|
||||
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
|
||||
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']},
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @query-spice:
|
||||
@@ -257,7 +262,8 @@
|
||||
# }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
|
||||
{ 'command': 'query-spice', 'returns': 'SpiceInfo',
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SPICE_CONNECTED:
|
||||
@@ -282,7 +288,8 @@
|
||||
##
|
||||
{ 'event': 'SPICE_CONNECTED',
|
||||
'data': { 'server': 'SpiceBasicInfo',
|
||||
'client': 'SpiceBasicInfo' } }
|
||||
'client': 'SpiceBasicInfo' },
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SPICE_INITIALIZED:
|
||||
@@ -310,7 +317,8 @@
|
||||
##
|
||||
{ 'event': 'SPICE_INITIALIZED',
|
||||
'data': { 'server': 'SpiceServerInfo',
|
||||
'client': 'SpiceChannel' } }
|
||||
'client': 'SpiceChannel' },
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SPICE_DISCONNECTED:
|
||||
@@ -335,7 +343,8 @@
|
||||
##
|
||||
{ 'event': 'SPICE_DISCONNECTED',
|
||||
'data': { 'server': 'SpiceBasicInfo',
|
||||
'client': 'SpiceBasicInfo' } }
|
||||
'client': 'SpiceBasicInfo' },
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# @SPICE_MIGRATE_COMPLETED:
|
||||
@@ -350,7 +359,8 @@
|
||||
# "event": "SPICE_MIGRATE_COMPLETED" }
|
||||
#
|
||||
##
|
||||
{ 'event': 'SPICE_MIGRATE_COMPLETED' }
|
||||
{ 'event': 'SPICE_MIGRATE_COMPLETED',
|
||||
'if': 'defined(CONFIG_SPICE)' }
|
||||
|
||||
##
|
||||
# == VNC
|
||||
@@ -377,7 +387,8 @@
|
||||
'data': { 'host': 'str',
|
||||
'service': 'str',
|
||||
'family': 'NetworkAddressFamily',
|
||||
'websocket': 'bool' } }
|
||||
'websocket': 'bool' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncServerInfo:
|
||||
@@ -391,7 +402,8 @@
|
||||
##
|
||||
{ 'struct': 'VncServerInfo',
|
||||
'base': 'VncBasicInfo',
|
||||
'data': { '*auth': 'str' } }
|
||||
'data': { '*auth': 'str' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncClientInfo:
|
||||
@@ -408,7 +420,8 @@
|
||||
##
|
||||
{ 'struct': 'VncClientInfo',
|
||||
'base': 'VncBasicInfo',
|
||||
'data': { '*x509_dname': 'str', '*sasl_username': 'str' } }
|
||||
'data': { '*x509_dname': 'str', '*sasl_username': 'str' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncInfo:
|
||||
@@ -449,7 +462,8 @@
|
||||
{ 'struct': 'VncInfo',
|
||||
'data': {'enabled': 'bool', '*host': 'str',
|
||||
'*family': 'NetworkAddressFamily',
|
||||
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
|
||||
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']},
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncPrimaryAuth:
|
||||
@@ -460,7 +474,8 @@
|
||||
##
|
||||
{ 'enum': 'VncPrimaryAuth',
|
||||
'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
|
||||
'tls', 'vencrypt', 'sasl' ] }
|
||||
'tls', 'vencrypt', 'sasl' ],
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncVencryptSubAuth:
|
||||
@@ -474,8 +489,8 @@
|
||||
'tls-none', 'x509-none',
|
||||
'tls-vnc', 'x509-vnc',
|
||||
'tls-plain', 'x509-plain',
|
||||
'tls-sasl', 'x509-sasl' ] }
|
||||
|
||||
'tls-sasl', 'x509-sasl' ],
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncServerInfo2:
|
||||
@@ -492,8 +507,8 @@
|
||||
{ 'struct': 'VncServerInfo2',
|
||||
'base': 'VncBasicInfo',
|
||||
'data': { 'auth' : 'VncPrimaryAuth',
|
||||
'*vencrypt' : 'VncVencryptSubAuth' } }
|
||||
|
||||
'*vencrypt' : 'VncVencryptSubAuth' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VncInfo2:
|
||||
@@ -525,7 +540,8 @@
|
||||
'clients' : ['VncClientInfo'],
|
||||
'auth' : 'VncPrimaryAuth',
|
||||
'*vencrypt' : 'VncVencryptSubAuth',
|
||||
'*display' : 'str' } }
|
||||
'*display' : 'str' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @query-vnc:
|
||||
@@ -556,8 +572,8 @@
|
||||
# }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-vnc', 'returns': 'VncInfo' }
|
||||
|
||||
{ 'command': 'query-vnc', 'returns': 'VncInfo',
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
##
|
||||
# @query-vnc-servers:
|
||||
#
|
||||
@@ -567,7 +583,8 @@
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
|
||||
{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'],
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @change-vnc-password:
|
||||
@@ -581,7 +598,8 @@
|
||||
# Notes: An empty password in this command will set the password to the empty
|
||||
# string. Existing clients are unaffected by executing this command.
|
||||
##
|
||||
{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
|
||||
{ 'command': 'change-vnc-password', 'data': {'password': 'str'},
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VNC_CONNECTED:
|
||||
@@ -610,7 +628,8 @@
|
||||
##
|
||||
{ 'event': 'VNC_CONNECTED',
|
||||
'data': { 'server': 'VncServerInfo',
|
||||
'client': 'VncBasicInfo' } }
|
||||
'client': 'VncBasicInfo' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VNC_INITIALIZED:
|
||||
@@ -637,7 +656,8 @@
|
||||
##
|
||||
{ 'event': 'VNC_INITIALIZED',
|
||||
'data': { 'server': 'VncServerInfo',
|
||||
'client': 'VncClientInfo' } }
|
||||
'client': 'VncClientInfo' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# @VNC_DISCONNECTED:
|
||||
@@ -663,7 +683,8 @@
|
||||
##
|
||||
{ 'event': 'VNC_DISCONNECTED',
|
||||
'data': { 'server': 'VncServerInfo',
|
||||
'client': 'VncClientInfo' } }
|
||||
'client': 'VncClientInfo' },
|
||||
'if': 'defined(CONFIG_VNC)' }
|
||||
|
||||
##
|
||||
# = Input
|
||||
|
||||
46
qmp.c
46
qmp.c
@@ -129,38 +129,6 @@ void qmp_cpu_add(int64_t id, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_VNC
|
||||
/* If VNC support is enabled, the "true" query-vnc command is
|
||||
defined in the VNC subsystem */
|
||||
VncInfo *qmp_query_vnc(Error **errp)
|
||||
{
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
return NULL;
|
||||
};
|
||||
|
||||
VncInfo2List *qmp_query_vnc_servers(Error **errp)
|
||||
{
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
return NULL;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPICE
|
||||
/*
|
||||
* qmp_unregister_commands_hack() ensures that QMP command query-spice
|
||||
* exists only #ifdef CONFIG_SPICE. Necessary for an accurate
|
||||
* query-commands result. However, the QAPI schema is blissfully
|
||||
* unaware of that, and the QAPI code generator happily generates a
|
||||
* dead qmp_marshal_query_spice() that calls qmp_query_spice().
|
||||
* Provide it one, or else linking fails. FIXME Educate the QAPI
|
||||
* schema on CONFIG_SPICE.
|
||||
*/
|
||||
SpiceInfo *qmp_query_spice(Error **errp)
|
||||
{
|
||||
abort();
|
||||
};
|
||||
#endif
|
||||
|
||||
void qmp_exit_preconfig(Error **errp)
|
||||
{
|
||||
if (!runstate_check(RUN_STATE_PRECONFIG)) {
|
||||
@@ -412,23 +380,17 @@ static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
|
||||
qmp_change_vnc_listen(target, errp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void qmp_change_vnc_password(const char *password, Error **errp)
|
||||
{
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
}
|
||||
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
}
|
||||
#endif /* !CONFIG_VNC */
|
||||
|
||||
void qmp_change(const char *device, const char *target,
|
||||
bool has_arg, const char *arg, Error **errp)
|
||||
{
|
||||
if (strcmp(device, "vnc") == 0) {
|
||||
#ifdef CONFIG_VNC
|
||||
qmp_change_vnc(target, has_arg, arg, errp);
|
||||
#else
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
#endif
|
||||
} else {
|
||||
qmp_blockdev_change_medium(true, device, false, NULL, target,
|
||||
has_arg, arg, false, 0, errp);
|
||||
|
||||
@@ -239,7 +239,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
|
||||
QAPISchemaModularCVisitor.__init__(
|
||||
self, prefix, 'qapi-commands',
|
||||
' * Schema-defined QAPI/QMP commands', __doc__)
|
||||
self._regy = ''
|
||||
self._regy = QAPIGenCCode()
|
||||
self._visited_ret_types = {}
|
||||
|
||||
def _begin_module(self, name):
|
||||
@@ -275,20 +275,28 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
|
||||
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
|
||||
''',
|
||||
c_prefix=c_name(self._prefix, protect=False)))
|
||||
genc.add(gen_registry(self._regy, self._prefix))
|
||||
genc.add(gen_registry(self._regy.get_content(), self._prefix))
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
if not gen:
|
||||
return
|
||||
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
|
||||
# FIXME: If T is a user-defined type, the user is responsible
|
||||
# for making this work, i.e. to make T's condition the
|
||||
# conjunction of the T-returning commands' conditions. If T
|
||||
# is a built-in type, this isn't possible: the
|
||||
# qmp_marshal_output_T() will be generated unconditionally.
|
||||
if ret_type and ret_type not in self._visited_ret_types[self._genc]:
|
||||
self._visited_ret_types[self._genc].add(ret_type)
|
||||
self._genc.add(gen_marshal_output(ret_type))
|
||||
self._genh.add(gen_marshal_decl(name))
|
||||
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
|
||||
self._regy += gen_register_command(name, success_response, allow_oob,
|
||||
allow_preconfig)
|
||||
with ifcontext(ret_type.ifcond,
|
||||
self._genh, self._genc, self._regy):
|
||||
self._genc.add(gen_marshal_output(ret_type))
|
||||
with ifcontext(ifcond, self._genh, self._genc, self._regy):
|
||||
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
|
||||
self._genh.add(gen_marshal_decl(name))
|
||||
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
|
||||
self._regy.add(gen_register_command(name, success_response,
|
||||
allow_oob, allow_preconfig))
|
||||
|
||||
|
||||
def gen_commands(schema, output_dir, prefix):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
32
scripts/qapi/doc.py
Normal file → Executable file
32
scripts/qapi/doc.py
Normal file → Executable file
@@ -174,7 +174,7 @@ def texi_members(doc, what, base, variants, member_func):
|
||||
return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
|
||||
|
||||
|
||||
def texi_sections(doc):
|
||||
def texi_sections(doc, ifcond):
|
||||
"""Format additional sections following arguments"""
|
||||
body = ''
|
||||
for section in doc.sections:
|
||||
@@ -185,14 +185,16 @@ def texi_sections(doc):
|
||||
body += texi_example(section.text)
|
||||
else:
|
||||
body += texi_format(section.text)
|
||||
if ifcond:
|
||||
body += '\n\n@b{If:} @code{%s}' % ", ".join(ifcond)
|
||||
return body
|
||||
|
||||
|
||||
def texi_entity(doc, what, base=None, variants=None,
|
||||
def texi_entity(doc, what, ifcond, base=None, variants=None,
|
||||
member_func=texi_member):
|
||||
return (texi_body(doc)
|
||||
+ texi_members(doc, what, base, variants, member_func)
|
||||
+ texi_sections(doc))
|
||||
+ texi_sections(doc, ifcond))
|
||||
|
||||
|
||||
class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
|
||||
@@ -204,47 +206,47 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
|
||||
def write(self, output_dir):
|
||||
self._gen.write(output_dir, self._prefix + 'qapi-doc.texi')
|
||||
|
||||
def visit_enum_type(self, name, info, values, prefix):
|
||||
def visit_enum_type(self, name, info, ifcond, values, prefix):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(TYPE_FMT(type='Enum',
|
||||
name=doc.symbol,
|
||||
body=texi_entity(doc, 'Values',
|
||||
body=texi_entity(doc, 'Values', ifcond,
|
||||
member_func=texi_enum_value)))
|
||||
|
||||
def visit_object_type(self, name, info, base, members, variants):
|
||||
def visit_object_type(self, name, info, ifcond, base, members, variants):
|
||||
doc = self.cur_doc
|
||||
if base and base.is_implicit():
|
||||
base = None
|
||||
self._gen.add(TYPE_FMT(type='Object',
|
||||
name=doc.symbol,
|
||||
body=texi_entity(doc, 'Members',
|
||||
body=texi_entity(doc, 'Members', ifcond,
|
||||
base, variants)))
|
||||
|
||||
def visit_alternate_type(self, name, info, variants):
|
||||
def visit_alternate_type(self, name, info, ifcond, variants):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(TYPE_FMT(type='Alternate',
|
||||
name=doc.symbol,
|
||||
body=texi_entity(doc, 'Members')))
|
||||
body=texi_entity(doc, 'Members', ifcond)))
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
doc = self.cur_doc
|
||||
if boxed:
|
||||
body = texi_body(doc)
|
||||
body += ('\n@b{Arguments:} the members of @code{%s}\n'
|
||||
% arg_type.name)
|
||||
body += texi_sections(doc)
|
||||
body += texi_sections(doc, ifcond)
|
||||
else:
|
||||
body = texi_entity(doc, 'Arguments')
|
||||
body = texi_entity(doc, 'Arguments', ifcond)
|
||||
self._gen.add(MSG_FMT(type='Command',
|
||||
name=doc.symbol,
|
||||
body=body))
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
def visit_event(self, name, info, ifcond, arg_type, boxed):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(MSG_FMT(type='Event',
|
||||
name=doc.symbol,
|
||||
body=texi_entity(doc, 'Arguments')))
|
||||
body=texi_entity(doc, 'Arguments', ifcond)))
|
||||
|
||||
def symbol(self, doc, entity):
|
||||
if self._gen._body:
|
||||
@@ -257,7 +259,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
|
||||
assert not doc.args
|
||||
if self._gen._body:
|
||||
self._gen.add('\n')
|
||||
self._gen.add(texi_body(doc) + texi_sections(doc))
|
||||
self._gen.add(texi_body(doc) + texi_sections(doc, None))
|
||||
|
||||
|
||||
def gen_doc(schema, output_dir, prefix):
|
||||
|
||||
@@ -184,9 +184,11 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
|
||||
genh.add(gen_enum(self._enum_name, self._event_names))
|
||||
genc.add(gen_enum_lookup(self._enum_name, self._event_names))
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
|
||||
self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name))
|
||||
def visit_event(self, name, info, ifcond, arg_type, boxed):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
|
||||
self._genc.add(gen_event_send(name, arg_type, boxed,
|
||||
self._enum_name))
|
||||
self._event_names.append(name)
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,15 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
|
||||
def indent(level):
|
||||
return level * 4 * ' '
|
||||
|
||||
if isinstance(obj, tuple):
|
||||
ifobj, ifcond = obj
|
||||
ret = gen_if(ifcond)
|
||||
ret += to_qlit(ifobj, level)
|
||||
endif = gen_endif(ifcond)
|
||||
if endif:
|
||||
ret += '\n' + endif
|
||||
return ret
|
||||
|
||||
ret = ''
|
||||
if not suppress_first_indent:
|
||||
ret += indent(level)
|
||||
@@ -26,11 +35,11 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
|
||||
elif isinstance(obj, str):
|
||||
ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
|
||||
elif isinstance(obj, list):
|
||||
elts = [to_qlit(elt, level + 1)
|
||||
elts = [to_qlit(elt, level + 1).strip('\n')
|
||||
for elt in obj]
|
||||
elts.append(indent(level + 1) + "{}")
|
||||
ret += 'QLIT_QLIST(((QLitObject[]) {\n'
|
||||
ret += ',\n'.join(elts) + '\n'
|
||||
ret += '\n'.join(elts) + '\n'
|
||||
ret += indent(level) + '}))'
|
||||
elif isinstance(obj, dict):
|
||||
elts = []
|
||||
@@ -45,6 +54,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
|
||||
ret += 'QLIT_QBOOL(%s)' % ('true' if obj else 'false')
|
||||
else:
|
||||
assert False # not implemented
|
||||
if level > 0:
|
||||
ret += ','
|
||||
return ret
|
||||
|
||||
|
||||
@@ -126,12 +137,12 @@ const QLitObject %(c_name)s = %(c_string)s;
|
||||
return '[' + self._use_type(typ.element_type) + ']'
|
||||
return self._name(typ.name)
|
||||
|
||||
def _gen_qlit(self, name, mtype, obj):
|
||||
def _gen_qlit(self, name, mtype, obj, ifcond):
|
||||
if mtype not in ('command', 'event', 'builtin', 'array'):
|
||||
name = self._name(name)
|
||||
obj['name'] = name
|
||||
obj['meta-type'] = mtype
|
||||
self._qlits.append(obj)
|
||||
self._qlits.append((obj, ifcond))
|
||||
|
||||
def _gen_member(self, member):
|
||||
ret = {'name': member.name, 'type': self._use_type(member.type)}
|
||||
@@ -147,28 +158,29 @@ const QLitObject %(c_name)s = %(c_string)s;
|
||||
return {'case': variant.name, 'type': self._use_type(variant.type)}
|
||||
|
||||
def visit_builtin_type(self, name, info, json_type):
|
||||
self._gen_qlit(name, 'builtin', {'json-type': json_type})
|
||||
self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
|
||||
|
||||
def visit_enum_type(self, name, info, values, prefix):
|
||||
self._gen_qlit(name, 'enum', {'values': values})
|
||||
def visit_enum_type(self, name, info, ifcond, values, prefix):
|
||||
self._gen_qlit(name, 'enum', {'values': values}, ifcond)
|
||||
|
||||
def visit_array_type(self, name, info, element_type):
|
||||
def visit_array_type(self, name, info, ifcond, element_type):
|
||||
element = self._use_type(element_type)
|
||||
self._gen_qlit('[' + element + ']', 'array', {'element-type': element})
|
||||
self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
|
||||
ifcond)
|
||||
|
||||
def visit_object_type_flat(self, name, info, members, variants):
|
||||
def visit_object_type_flat(self, name, info, ifcond, members, variants):
|
||||
obj = {'members': [self._gen_member(m) for m in members]}
|
||||
if variants:
|
||||
obj.update(self._gen_variants(variants.tag_member.name,
|
||||
variants.variants))
|
||||
self._gen_qlit(name, 'object', obj)
|
||||
self._gen_qlit(name, 'object', obj, ifcond)
|
||||
|
||||
def visit_alternate_type(self, name, info, variants):
|
||||
def visit_alternate_type(self, name, info, ifcond, variants):
|
||||
self._gen_qlit(name, 'alternate',
|
||||
{'members': [{'type': self._use_type(m.type)}
|
||||
for m in variants.variants]})
|
||||
for m in variants.variants]}, ifcond)
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
ret_type = ret_type or self._schema.the_empty_object_type
|
||||
@@ -176,11 +188,12 @@ const QLitObject %(c_name)s = %(c_string)s;
|
||||
{'arg-type': self._use_type(arg_type),
|
||||
'ret-type': self._use_type(ret_type),
|
||||
'allow-oob': allow_oob,
|
||||
'allow-preconfig': allow_preconfig})
|
||||
'allow-preconfig': allow_preconfig}, ifcond)
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
def visit_event(self, name, info, ifcond, arg_type, boxed):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)})
|
||||
self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
|
||||
ifcond)
|
||||
|
||||
|
||||
def gen_introspect(schema, output_dir, prefix, opt_unmask):
|
||||
|
||||
@@ -55,7 +55,7 @@ def gen_struct_members(members):
|
||||
return ret
|
||||
|
||||
|
||||
def gen_object(name, base, members, variants):
|
||||
def gen_object(name, ifcond, base, members, variants):
|
||||
if name in objects_seen:
|
||||
return ''
|
||||
objects_seen.add(name)
|
||||
@@ -64,11 +64,14 @@ def gen_object(name, base, members, variants):
|
||||
if variants:
|
||||
for v in variants.variants:
|
||||
if isinstance(v.type, QAPISchemaObjectType):
|
||||
ret += gen_object(v.type.name, v.type.base,
|
||||
ret += gen_object(v.type.name, v.type.ifcond, v.type.base,
|
||||
v.type.local_members, v.type.variants)
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
''')
|
||||
ret += gen_if(ifcond)
|
||||
ret += mcgen('''
|
||||
struct %(c_name)s {
|
||||
''',
|
||||
c_name=c_name(name))
|
||||
@@ -101,6 +104,7 @@ struct %(c_name)s {
|
||||
ret += mcgen('''
|
||||
};
|
||||
''')
|
||||
ret += gen_endif(ifcond)
|
||||
|
||||
return ret
|
||||
|
||||
@@ -208,34 +212,40 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
|
||||
self._genh.add(gen_type_cleanup_decl(name))
|
||||
self._genc.add(gen_type_cleanup(name))
|
||||
|
||||
def visit_enum_type(self, name, info, values, prefix):
|
||||
self._genh.preamble_add(gen_enum(name, values, prefix))
|
||||
self._genc.add(gen_enum_lookup(name, values, prefix))
|
||||
def visit_enum_type(self, name, info, ifcond, values, prefix):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.preamble_add(gen_enum(name, values, prefix))
|
||||
self._genc.add(gen_enum_lookup(name, values, prefix))
|
||||
|
||||
def visit_array_type(self, name, info, element_type):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_array(name, element_type))
|
||||
self._gen_type_cleanup(name)
|
||||
def visit_array_type(self, name, info, ifcond, element_type):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_array(name, element_type))
|
||||
self._gen_type_cleanup(name)
|
||||
|
||||
def visit_object_type(self, name, info, base, members, variants):
|
||||
def visit_object_type(self, name, info, ifcond, base, members, variants):
|
||||
# Nothing to do for the special empty builtin
|
||||
if name == 'q_empty':
|
||||
return
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, base, members, variants))
|
||||
if base and not base.is_implicit():
|
||||
self._genh.add(gen_upcast(name, base))
|
||||
# TODO Worth changing the visitor signature, so we could
|
||||
# directly use rather than repeat type.is_implicit()?
|
||||
if not name.startswith('q_'):
|
||||
# implicit types won't be directly allocated/freed
|
||||
self._gen_type_cleanup(name)
|
||||
with ifcontext(ifcond, self._genh):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, ifcond, base, members, variants))
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
if base and not base.is_implicit():
|
||||
self._genh.add(gen_upcast(name, base))
|
||||
# TODO Worth changing the visitor signature, so we could
|
||||
# directly use rather than repeat type.is_implicit()?
|
||||
if not name.startswith('q_'):
|
||||
# implicit types won't be directly allocated/freed
|
||||
self._gen_type_cleanup(name)
|
||||
|
||||
def visit_alternate_type(self, name, info, variants):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, None,
|
||||
def visit_alternate_type(self, name, info, ifcond, variants):
|
||||
with ifcontext(ifcond, self._genh):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, ifcond, None,
|
||||
[variants.tag_member], variants))
|
||||
self._gen_type_cleanup(name)
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._gen_type_cleanup(name)
|
||||
|
||||
|
||||
def gen_types(schema, output_dir, prefix, opt_builtins):
|
||||
|
||||
@@ -310,30 +310,35 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
|
||||
''',
|
||||
types=types))
|
||||
|
||||
def visit_enum_type(self, name, info, values, prefix):
|
||||
self._genh.add(gen_visit_decl(name, scalar=True))
|
||||
self._genc.add(gen_visit_enum(name))
|
||||
def visit_enum_type(self, name, info, ifcond, values, prefix):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_decl(name, scalar=True))
|
||||
self._genc.add(gen_visit_enum(name))
|
||||
|
||||
def visit_array_type(self, name, info, element_type):
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_list(name, element_type))
|
||||
def visit_array_type(self, name, info, ifcond, element_type):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_list(name, element_type))
|
||||
|
||||
def visit_object_type(self, name, info, base, members, variants):
|
||||
def visit_object_type(self, name, info, ifcond, base, members, variants):
|
||||
# Nothing to do for the special empty builtin
|
||||
if name == 'q_empty':
|
||||
return
|
||||
self._genh.add(gen_visit_members_decl(name))
|
||||
self._genc.add(gen_visit_object_members(name, base, members, variants))
|
||||
# TODO Worth changing the visitor signature, so we could
|
||||
# directly use rather than repeat type.is_implicit()?
|
||||
if not name.startswith('q_'):
|
||||
# only explicit types need an allocating visit
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_object(name, base, members, variants))
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_members_decl(name))
|
||||
self._genc.add(gen_visit_object_members(name, base,
|
||||
members, variants))
|
||||
# TODO Worth changing the visitor signature, so we could
|
||||
# directly use rather than repeat type.is_implicit()?
|
||||
if not name.startswith('q_'):
|
||||
# only explicit types need an allocating visit
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_object(name, base, members, variants))
|
||||
|
||||
def visit_alternate_type(self, name, info, variants):
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_alternate(name, variants))
|
||||
def visit_alternate_type(self, name, info, ifcond, variants):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_alternate(name, variants))
|
||||
|
||||
|
||||
def gen_visit(schema, output_dir, prefix, opt_builtins):
|
||||
|
||||
@@ -442,6 +442,10 @@ qapi-schema += args-unknown.json
|
||||
qapi-schema += bad-base.json
|
||||
qapi-schema += bad-data.json
|
||||
qapi-schema += bad-ident.json
|
||||
qapi-schema += bad-if.json
|
||||
qapi-schema += bad-if-empty.json
|
||||
qapi-schema += bad-if-empty-list.json
|
||||
qapi-schema += bad-if-list.json
|
||||
qapi-schema += bad-type-bool.json
|
||||
qapi-schema += bad-type-dict.json
|
||||
qapi-schema += bad-type-int.json
|
||||
|
||||
1
tests/qapi-schema/bad-if-empty-list.err
Normal file
1
tests/qapi-schema/bad-if-empty-list.err
Normal file
@@ -0,0 +1 @@
|
||||
tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
|
||||
1
tests/qapi-schema/bad-if-empty-list.exit
Normal file
1
tests/qapi-schema/bad-if-empty-list.exit
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
3
tests/qapi-schema/bad-if-empty-list.json
Normal file
3
tests/qapi-schema/bad-if-empty-list.json
Normal file
@@ -0,0 +1,3 @@
|
||||
# check empty 'if' list
|
||||
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
|
||||
'if': [] }
|
||||
0
tests/qapi-schema/bad-if-empty-list.out
Normal file
0
tests/qapi-schema/bad-if-empty-list.out
Normal file
1
tests/qapi-schema/bad-if-empty.err
Normal file
1
tests/qapi-schema/bad-if-empty.err
Normal file
@@ -0,0 +1 @@
|
||||
tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user