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
all_names[name] = meta
+def check_if(expr, info):
+
+ def check_if_str(ifcond, info):
+ if not isinstance(ifcond, str):
+ raise QAPISemError(
+ info, "'if' condition must be a string or a list of strings")
+ if ifcond == '':
+ raise QAPISemError(info, "'if' condition '' makes no sense")
+
+ ifcond = expr.get('if')
+ if ifcond is None:
+ return
+ if isinstance(ifcond, list):
+ if ifcond == []:
+ raise QAPISemError(info, "'if' condition [] is useless")
+ for elt in ifcond:
+ check_if_str(elt, info)
+ else:
+ check_if_str(ifcond, info)
+
+
def check_type(info, source, value, allow_array=False,
allow_dict=False, allow_optional=False,
allow_metas=[]):
raise QAPISemError(info,
"'%s' of %s '%s' should only use true value"
% (key, meta, name))
+ if key == 'if':
+ check_if(expr, info)
for key in required:
if key not in expr:
raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
if 'enum' in expr:
meta = 'enum'
- check_keys(expr_elem, 'enum', ['data'], ['prefix'])
+ check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
check_keys(expr_elem, 'union', ['data'],
- ['base', 'discriminator'])
+ ['base', 'discriminator', 'if'])
union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
- check_keys(expr_elem, 'alternate', ['data'])
+ check_keys(expr_elem, 'alternate', ['data'], ['if'])
elif 'struct' in expr:
meta = 'struct'
- check_keys(expr_elem, 'struct', ['data'], ['base'])
+ check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
- 'boxed', 'allow-oob', 'allow-preconfig'])
+ 'boxed', 'allow-oob', 'allow-preconfig', 'if'])
elif 'event' in expr:
meta = 'event'
- check_keys(expr_elem, 'event', [], ['data', 'boxed'])
+ check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
else:
raise QAPISemError(expr_elem['info'],
"Expression is missing metatype")
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
--- /dev/null
+tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
--- /dev/null
+# check empty 'if' list
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': [] }
--- /dev/null
+tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
--- /dev/null
+# check empty 'if'
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': '' }
--- /dev/null
+tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
--- /dev/null
+# check invalid 'if' content
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': ['foo', ''] }
--- /dev/null
+tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
--- /dev/null
+# check invalid 'if' type
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
'data': { 'string0': 'str',
'dict1': 'UserDefTwoDict' } }
+{ 'struct': 'UserDefThree',
+ 'data': { 'string0': 'str' } }
+
# dummy struct to force generation of array types not otherwise mentioned
{ 'struct': 'ForceArrays',
'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'],
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
'returns': '__org.qemu_x-Union1' }
+
+# test 'if' condition handling
+
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': 'defined(TEST_IF_STRUCT)' }
+
+{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+ 'if': 'defined(TEST_IF_ENUM)' }
+
+{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+ 'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
+
+{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
+ 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
+
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+ 'returns': 'UserDefThree',
+ 'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
+
+{ 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' }
+
+{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+ 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
object UserDefTwo
member string0: str optional=False
member dict1: UserDefTwoDict optional=False
+object UserDefThree
+ member string0: str optional=False
object ForceArrays
member unused1: UserDefOneList optional=False
member unused2: UserDefTwoList optional=False
member d: __org.qemu_x-Alt optional=False
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
gen=True success_response=True boxed=False oob=False preconfig=False
+object TestIfStruct
+ member foo: int optional=False
+enum TestIfEnum ['foo', 'bar']
+object q_obj_TestStruct-wrapper
+ member data: TestStruct optional=False
+enum TestIfUnionKind ['foo']
+object TestIfUnion
+ member type: TestIfUnionKind optional=False
+ tag type
+ case foo: q_obj_TestStruct-wrapper
+alternate TestIfAlternate
+ tag type
+ case foo: int
+ case bar: TestStruct
+object q_obj_TestIfCmd-arg
+ member foo: TestIfStruct optional=False
+command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
+ gen=True success_response=True boxed=False oob=False preconfig=False
+command TestCmdReturnDefThree None -> UserDefThree
+ gen=True success_response=True boxed=False oob=False preconfig=False
+object q_obj_TestIfEvent-arg
+ member foo: TestIfStruct optional=False
+event TestIfEvent q_obj_TestIfEvent-arg
+ boxed=False
static QmpCommandList qmp_commands;
+/* #if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD) */
+UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
+{
+ return NULL;
+}
+/* #endif */
+
+UserDefThree *qmp_TestCmdReturnDefThree(Error **errp)
+{
+ return NULL;
+}
+
void qmp_user_def_cmd(Error **errp)
{
}