This code will marshal a QMP type from native representation to a QObject and vice versa.
Marshaling from a native representation to a QObject can never generate an Error although the opposite direction may. Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> --- v1 -> v2 - update code generator to use multiline strings - support proxy commands - support async commands diff --git a/Makefile b/Makefile index 6b9fd69..8f3a4d3 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ GENERATED_HEADERS = config-host.h trace.h qemu-options.def ifeq ($(TRACE_BACKEND),dtrace) GENERATED_HEADERS += trace-dtrace.h endif -GENERATED_HEADERS += qmp-types.h +GENERATED_HEADERS += qmp-types.h qmp-marshal-types.h ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -153,7 +153,14 @@ qmp-types.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py qmp-types.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --types-header < $< > $@, " GEN $@") +qmp-marshal-types.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py + $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --marshal-body < $< > $@, " GEN $@") + +qmp-marshal-types.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py + $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --marshal-header < $< > $@, " GEN $@") + qmp-types.o: qmp-types.c qmp-types.h +qmp-marshal-types.o: qmp-marshal-types.c qmp-marshal-types.h qmp-types.h version.o: $(SRC_PATH)/version.rc config-host.mak $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") diff --git a/Makefile.objs b/Makefile.objs index 710d99f..f51eab3 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -102,6 +102,7 @@ common-obj-y += qdev.o qdev-properties.o common-obj-y += block-migration.o common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o +common-obj-y += qmp-marshal-types.o qmp-marshal-types-core.o common-obj-$(CONFIG_BRLAPI) += baum.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o diff --git a/qmp-gen.py b/qmp-gen.py index cded2f6..02084d9 100644 --- a/qmp-gen.py +++ b/qmp-gen.py @@ -360,6 +360,205 @@ const char *qmp_type_%(dcc_name)s_to_str(%(name)s value, Error **errp) name=name) return ret +def gen_type_marshal_declaration(name, typeinfo): + if is_dict(typeinfo): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(type)s src); +%(type)s qmp_unmarshal_type_%(name)s(QObject *src, Error **errp); +''', + name=name, type=qmp_type_to_c(name)) + + return '' + +def gen_metatype_def(typeinfo, name, lhs, sep='->', level=0): + new_lhs = 'qmp__member%d' % level + + ret = '' + + if type(typeinfo) == str: + ret += cgen(' %(lhs)s = %(marshal)s(%(name)s);', + lhs=lhs, name=name, + marshal=qmp_type_to_qobj(typeinfo)) + elif is_dict(typeinfo): + ret += mcgen(''' + { + QDict *qmp__dict = qdict_new(); + QObject *%(new_lhs)s; +''', + new_lhs=new_lhs) + for argname, argtype, optional in parse_args(typeinfo): + ret += cgen('') + if optional: + ret += mcgen(''' + if (%(name)s%(sep)shas_%(c_name)s) { +''', + name=name, sep=sep, + c_name=c_var(argname)) + push_indent() + push_indent() + ret += gen_metatype_def(argtype, '%s%s%s' % (name, sep, c_var(argname)), new_lhs, '.', level + 1) + pop_indent() + ret += mcgen(''' + qdict_put_obj(qmp__dict, "%(name)s", %(new_lhs)s); +''', + name=argname, new_lhs=new_lhs) + if optional: + pop_indent() + ret += mcgen(''' + } +''') + ret += mcgen(''' + %(lhs)s = QOBJECT(qmp__dict); + } +''', + lhs=lhs) + elif type(typeinfo) == list: + ret += mcgen(''' + { + QList *qmp__list = qlist_new(); + %(type)s %(new_lhs)s_i; + + for (%(new_lhs)s_i = %(name)s; %(new_lhs)s_i != NULL; %(new_lhs)s_i = %(new_lhs)s_i->next) { + QObject *qmp__member = %(marshal)s(%(new_lhs)s_i); + qlist_append_obj(qmp__list, qmp__member); + } + %(lhs)s = QOBJECT(qmp__list); + } +''', + type=qmp_type_to_c(typeinfo[0], True), + new_lhs=new_lhs, name=name, lhs=lhs, + marshal=qmp_type_to_qobj(typeinfo[0])) + + return ret + +def gen_metatype_undef(typeinfo, name, lhs, sep='->', level=0): + ret = '' + if type(typeinfo) == str: + ret += mcgen(''' + %(lhs)s = %(unmarshal)s(%(c_name)s, &qmp__err); + if (qmp__err) { + goto qmp__err_out; + } +''', + lhs=lhs, c_name=c_var(name), + unmarshal=qmp_type_from_qobj(typeinfo)) + elif is_dict(typeinfo): + objname = 'qmp__object%d' % level + ret += mcgen(''' + { + QDict *qmp__dict = qobject_to_qdict(%(c_name)s); + QObject *%(objname)s; + +''', + c_name=c_var(name), objname=objname) + for argname, argtype, optional in parse_args(typeinfo): + if optional: + ret += mcgen(''' + if (qdict_haskey(qmp__dict, "%(name)s")) { +''', + name=argname) + push_indent() + ret += mcgen(''' + %(objname)s = qdict_get(qmp__dict, "%(name)s"); +''', + name=argname, objname=objname) + push_indent() + ret += gen_metatype_undef(argtype, objname, '%s%s%s' % (lhs, sep, c_var(argname)), '.', level + 1) + pop_indent() + if optional: + pop_indent() + ret += mcgen(''' + %(lhs)s%(sep)shas_%(c_name)s = true; + } else { + %(lhs)s%(sep)shas_%(c_name)s = false; + } +''', + lhs=lhs, sep=sep, c_name=c_var(argname)) + + ret += mcgen(''' + } +''') + + elif type(typeinfo) == list: + objname = 'qmp__object%d' % level + ret += mcgen(''' + { + QList *qmp__list = qobject_to_qlist(%(c_name)s); + QListEntry *%(objname)s; + QLIST_FOREACH_ENTRY(qmp__list, %(objname)s) { + %(type)s qmp__node = %(unmarshal)s(%(objname)s->value, &qmp__err); + if (qmp__err) { + goto qmp__err_out; + } + qmp__node->next = %(lhs)s; + %(lhs)s = qmp__node; + } + } +''', + c_name=c_var(name), objname=objname, lhs=lhs, + type=qmp_type_to_c(typeinfo[0], True), + unmarshal=qmp_type_from_qobj(typeinfo[0])) + + return ret + +def gen_type_marshal_definition(name, typeinfo): + ret = mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(type)s src) +{ + QObject *qmp__retval; + +%(marshal)s + + return qmp__retval; +} + +%(type)s qmp_unmarshal_type_%(name)s(QObject *src, Error **errp) +{ + Error *qmp__err = NULL; + %(type)s qmp__retval = qmp_alloc_%(dcc_name)s(); + +%(unmarshal)s + + return qmp__retval; + +qmp__err_out: + error_propagate(errp, qmp__err); + %(free)s(qmp__retval); + return NULL; +} +''', + name=name, type=qmp_type_to_c(name), + marshal=gen_metatype_def(typeinfo, 'src', 'qmp__retval'), + dcc_name=de_camel_case(name), free=qmp_free_func(name), + unmarshal=gen_metatype_undef(typeinfo, 'src', 'qmp__retval')) + + return ret + +def gen_enum_marshal_declaration(name, entries): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(name)s value); +%(name)s qmp_unmarshal_type_%(name)s(QObject *obj, Error **errp); +''', + name=name) + +def gen_enum_marshal_definition(name, entries): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(name)s value) +{ + return QOBJECT(qint_from_int(value)); +} + +%(name)s qmp_unmarshal_type_%(name)s(QObject *obj, Error **errp) +{ + return (%(name)s)qint_get_int(qobject_to_qint(obj)); +} +''', + name=name) + def tokenize(data): while len(data): if data[0] in ['{', '}', ':', ',', '[', ']']: @@ -436,6 +635,18 @@ def generate(kind): #include "qmp-types.h" #include "qmp-marshal-types.h" ''') + elif kind == 'marshal-header': + ret += mcgen(''' +#ifndef QMP_MARSHAL_TYPES_H +#define QMP_MARSHAL_TYPES_H + +#include "qmp-marshal-types-core.h" +''') + elif kind == 'marshal-body': + ret += mcgen(''' +#include "qmp-marshal-types.h" +#include "qerror.h" +''') exprs = [] expr = '' @@ -466,6 +677,10 @@ def generate(kind): ret += gen_type_definition(name, data) elif kind == 'types-header': ret += gen_type_declaration(name, data) + elif kind == 'marshal-body': + ret += gen_type_marshal_definition(name, data) + elif kind == 'marshal-header': + ret += gen_type_marshal_declaration(name, data) elif s.has_key('enum'): name = s['enum'] data = s['data'] @@ -475,6 +690,10 @@ def generate(kind): ret += gen_enum_declaration(name, data) elif kind == 'types-body': ret += gen_enum_definition(name, data) + elif kind == 'marshal-header': + ret += gen_enum_marshal_declaration(name, data) + elif kind == 'marshal-body': + ret += gen_enum_marshal_definition(name, data) elif s.has_key('event'): name = s['event'] data = {} diff --git a/qmp-marshal-types-core.c b/qmp-marshal-types-core.c new file mode 100644 index 0000000..6a55733 --- /dev/null +++ b/qmp-marshal-types-core.c @@ -0,0 +1,71 @@ +/* + * QAPI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori <aligu...@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. See + * the COPYING.LIB file in the top-level directory. + */ +#include "qmp-marshal-types-core.h" +#include "qerror.h" + +QObject *qmp_marshal_type_int(int64_t value) +{ + return QOBJECT(qint_from_int(value)); +} + +QObject *qmp_marshal_type_str(const char *value) +{ + return QOBJECT(qstring_from_str(value)); +} + +QObject *qmp_marshal_type_bool(bool value) +{ + return QOBJECT(qbool_from_int(value)); +} + +QObject *qmp_marshal_type_number(double value) +{ + return QOBJECT(qfloat_from_double(value)); +} + +int64_t qmp_unmarshal_type_int(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QINT) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "<unknown>", "int"); + return 0; + } + return qint_get_int(qobject_to_qint(value)); +} + +char *qmp_unmarshal_type_str(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QSTRING) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "<unknown>", "string"); + return 0; + } + return qemu_strdup(qstring_get_str(qobject_to_qstring(value))); +} + +bool qmp_unmarshal_type_bool(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QBOOL) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "<unknown>", "bool"); + return 0; + } + return qbool_get_int(qobject_to_qbool(value)); +} + +double qmp_unmarshal_type_number(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QFLOAT) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "<unknown>", "float"); + return 0; + } + return qfloat_get_double(qobject_to_qfloat(value)); +} + + diff --git a/qmp-marshal-types-core.h b/qmp-marshal-types-core.h new file mode 100644 index 0000000..38fe696 --- /dev/null +++ b/qmp-marshal-types-core.h @@ -0,0 +1,31 @@ +/* + * QAPI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori <aligu...@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. See + * the COPYING.LIB file in the top-level directory. + */ +#ifndef QMP_MARSHAL_TYPES_CORE_H +#define QMP_MARSHAL_TYPES_CORE_H + +#include "qemu-common.h" +#include "qemu-objects.h" +#include "qerror.h" +#include "error.h" +#include "qmp-types.h" + +QObject *qmp_marshal_type_int(int64_t value); +QObject *qmp_marshal_type_str(const char *value); +QObject *qmp_marshal_type_bool(bool value); +QObject *qmp_marshal_type_number(double value); + +int64_t qmp_unmarshal_type_int(QObject *value, Error **errp); +char *qmp_unmarshal_type_str(QObject *value, Error **errp); +bool qmp_unmarshal_type_bool(QObject *value, Error **errp); +double qmp_unmarshal_type_number(QObject *value, Error **errp); + +#endif -- 1.7.0.4