In command definition, 'defaults' is now parsed as a dict of default values. Only optional parameters will have effect in generated code.
'str' and 'int' are supported. In generated code, 'str' will be converted to g_strdup'ed string pointer, 'int' will be identically assigned. E.g. { 'command': 'block-commit', 'data': { 'device': 'str', '*base': 'str', 'top': 'str', '*speed': 'int' }, 'defaults': {'base': 'earthquake', 'speed': 100 } } will generate int qmp_marshal_input_block_commit(Monitor *mon, const QDict *qdict, QObject **ret) { ... bool has_base = true; char * base = g_strdup("earthquake"); ... bool has_speed = true; int64_t speed = 100; Updated docs/qapi-code-gen.txt and qapi-schema tests. Signed-off-by: Fam Zheng <f...@redhat.com> --- docs/qapi-code-gen.txt | 8 ++++++-- scripts/qapi-commands.py | 29 ++++++++++++++++++++++------- scripts/qapi.py | 8 ++++++++ tests/qapi-schema/qapi-schema-test.json | 3 +++ tests/qapi-schema/qapi-schema-test.out | 1 + tests/test-qmp-commands.c | 7 +++++++ 6 files changed, 47 insertions(+), 9 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index d78921f..b4cc6ed 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -172,12 +172,16 @@ This example allows using both of the following example objects: Commands are defined by using a list containing three members. The first member is the command name, the second member is a dictionary containing -arguments, and the third member is the return type. +arguments, the third member is optional to define default values for optional +arguments in 'data' dictionary, and the fourth member is the return type. + +Non-optional argument names are not allowed in the 'defaults' dictionary. An example command is: { 'command': 'my-command', - 'data': { 'arg1': 'str', '*arg2': 'str' }, + 'data': { 'arg1': 'str', '*arg2': 'str', '*arg3': 'int' }, + 'defaults': { 'arg2': 'default value for arg2', 'arg3': 12345 }, 'returns': 'str' } diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 9734ab0..aa4ce65 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -83,16 +83,28 @@ Visitor *v; return ret.rstrip() -def gen_visitor_input_vars_decl(args): +def gen_visitor_input_vars_decl(cmd_name, args, defaults): ret = "" push_indent() for argname, argtype, optional, structured in parse_args(args): if optional: ret += mcgen(''' -bool has_%(argname)s = false; +bool has_%(argname)s = %(has_val)s; ''', - argname=c_var(argname)) - if c_type(argtype).endswith("*"): + argname=c_var(argname), + has_val="true" if defaults.get(argname) else "false") + if defaults.get(argname): + if optional: + ret += mcgen(''' +%(argtype)s %(argname)s = %(argval)s; +''', + argname=c_var(argname), argtype=c_type(argtype), + argval=c_val(argtype, defaults[argname])) + else: + raise Exception('Error while generating "%s": ' + 'default value given to non-optional value: "%s"' + % (cmd_name, argname)) + elif c_type(argtype).endswith("*"): ret += mcgen(''' %(argtype)s %(argname)s = NULL; ''', @@ -194,7 +206,7 @@ def gen_marshal_input_decl(name, args, ret_type, middle_mode): -def gen_marshal_input(name, args, ret_type, middle_mode): +def gen_marshal_input(name, args, ret_type, middle_mode, defaults): hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode) ret = mcgen(''' @@ -229,7 +241,7 @@ def gen_marshal_input(name, args, ret_type, middle_mode): ''', visitor_input_containers_decl=gen_visitor_input_containers_decl(args), - visitor_input_vars_decl=gen_visitor_input_vars_decl(args), + visitor_input_vars_decl=gen_visitor_input_vars_decl(name, args, defaults), visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) else: ret += mcgen(''' @@ -434,9 +446,12 @@ if dispatch_type == "sync": for cmd in commands: arglist = [] + defaults = {} ret_type = None if cmd.has_key('data'): arglist = cmd['data'] + if cmd.has_key('defaults'): + defaults = cmd['defaults'] if cmd.has_key('returns'): ret_type = cmd['returns'] ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" @@ -448,7 +463,7 @@ if dispatch_type == "sync": if middle_mode: fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) - ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" + ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode, defaults) + "\n" fdef.write(ret) fdecl.write("\n#endif\n"); diff --git a/scripts/qapi.py b/scripts/qapi.py index 6022de5..e1ee232 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -432,6 +432,14 @@ def find_enum(name): def is_enum(name): return find_enum(name) != None +def c_val(t, val): + if t == 'str': + return 'g_strdup("%s")' % val + elif t == 'int': + return val + else: + assert False, "Unknown type: %s" % t + def c_type(name): if name == 'str': return 'char *' diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 818c06d..600439e 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -74,6 +74,9 @@ 'returns': 'UserDefTwo' } { 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } +{ 'command': 'user_def_cmd4', 'data': {'a': 'int', '*b': 'int', '*c': 'str' }, + 'defaults': { 'b': 100, 'c': 'A string' }, + 'returns': 'int' } # For testing integer range flattening in opts-visitor. The following schema # corresponds to the option format: diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 6cd03f3..fb26643 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -15,6 +15,7 @@ OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]), + OrderedDict([('command', 'user_def_cmd4'), ('data', OrderedDict([('a', 'int'), ('*b', 'int'), ('*c', 'str')])), ('defaults', OrderedDict([('b', 100), ('c', 'A string')])), ('returns', 'int')]), OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': 'UserDefUnionKind', 'enum_values': None}, diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 554e222..eb2a77a 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -48,6 +48,13 @@ int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp) return a + (has_b ? b : 0); } +int64_t qmp_user_def_cmd4(int64_t a, bool has_b, int64_t b, + bool has_c, const char *c, + Error **errp) +{ + return has_b && b == 100 && has_c && !strcmp(c, "A string"); +} + /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { -- 1.9.2