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> 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 0889fa3..8adcc2b 100644 --- a/qmp-gen.py +++ b/qmp-gen.py @@ -281,6 +281,154 @@ void qmp_free_%s(%s *obj) return qemu_mallocz(512); }''' % (name, c_var_name, name) +def print_metatype_def(typeinfo, name, lhs, indent=0): + if indent == 0: + sep = '->' + else: + sep = '.' + new_lhs = 'qmp__member%d' % (indent / 4) + + if type(typeinfo) == str: + inprint(' %s = %s(%s);' % (lhs, qmp_type_to_qobj_ctor(typeinfo), name), indent) + elif is_dict(typeinfo): + inprint(' {', indent) + inprint(' QDict *qmp__dict = qdict_new();', indent) + inprint(' QObject *%s;' % new_lhs, indent) + print + for key in typeinfo: + member = key + if key.startswith('*'): + member = key[1:] + inprint(' if (%s%shas_%s) {' % (name, sep, c_var(member)), indent) + print_metatype_def(typeinfo[key], '%s%s%s' % (name, sep, c_var(member)), new_lhs, indent + 8) + inprint(' qdict_put_obj(qmp__dict, "%s", %s);' % (member, new_lhs), indent) + inprint(' }', indent) + else: + print_metatype_def(typeinfo[key], '%s%s%s' % (name, sep, c_var(member)), new_lhs, indent + 4) + inprint(' qdict_put_obj(qmp__dict, "%s", %s);' % (member, new_lhs), indent) + print + inprint(' %s = QOBJECT(qmp__dict);' % lhs, indent) + inprint(' }', indent) + elif type(typeinfo) == list: + inprint(' {', indent) + inprint(' QList *qmp__list = qlist_new();', indent) + inprint(' %s %s_i;' % (qmp_type_to_c(typeinfo[0], True), new_lhs), indent) + print + inprint(' for (%s_i = %s; %s_i != NULL; %s_i = %s_i->next) {' % (new_lhs, name, new_lhs, new_lhs, new_lhs), indent) + inprint(' QObject *qmp__member = %s(%s_i);' % (qmp_type_to_qobj_ctor(typeinfo[0]), new_lhs), indent) + inprint(' qlist_append_obj(qmp__list, qmp__member);', indent) + inprint(' }', indent) + inprint(' %s = QOBJECT(qmp__list);' % lhs, indent) + inprint(' }', indent) + +def qobj_to_c(typename): + return 'qmp_unmarshal_type_%s' % typename + +def print_metatype_undef(typeinfo, name, lhs, indent=0): + if indent == 0: + sep = '->' + else: + sep = '.' + + indent += 4 + + if type(typeinfo) == str: + inprint('%s = %s(%s, &qmp__err);' % (lhs, qobj_to_c(typeinfo), name), indent) + inprint('if (qmp__err) {', indent) + inprint(' goto qmp__err_out;', indent) + inprint('}', indent) + elif is_dict(typeinfo): + objname = 'qmp__object%d' % ((indent - 4) / 4) + inprint('{', indent) + inprint(' QDict *qmp__dict = qobject_to_qdict(%s);' % c_var(name), indent) + inprint(' QObject *%s;' % objname, indent) + for key in typeinfo: + member = key + optional = False + if key.startswith('*'): + member = key[1:] + optional = True + if optional: + inprint('if (qdict_haskey(qmp__dict, "%s")) {' % (member), indent + 4) + inprint(' %s = qdict_get(qmp__dict, "%s");' % (objname, member), indent + 4) + inprint(' %s%shas_%s = true;' % (lhs, sep, c_var(member)), indent + 4) + print_metatype_undef(typeinfo[key], objname, '%s%s%s' % (lhs, sep, c_var(member)), indent + 4) + inprint('} else {', indent + 4) + inprint(' %s%shas_%s = false;' % (lhs, sep, c_var(member)), indent + 4) + inprint('}', indent + 4) + else: + inprint('%s = qdict_get(qmp__dict, "%s");' % (objname, key), indent + 4) + print_metatype_undef(typeinfo[key], objname, '%s%s%s' % (lhs, sep, c_var(member)), indent) + inprint('}', indent) + elif type(typeinfo) == list: + objname = 'qmp__object%d' % ((indent - 4) / 4) + inprint('{', indent) + inprint(' QList *qmp__list = qobject_to_qlist(%s);' % c_var(name), indent) + inprint(' QListEntry *%s;' % objname, indent) + inprint(' QLIST_FOREACH_ENTRY(qmp__list, %s) {' % objname, indent) + inprint(' %s qmp__node = %s(%s->value, &qmp__err);' % (qmp_type_to_c(typeinfo[0], True), qmp_type_from_qobj(typeinfo[0]), objname), indent) + inprint(' if (qmp__err) {', indent) + inprint(' goto qmp__err_out;', indent) + inprint(' }', indent) + inprint(' qmp__node->next = %s;' % lhs, indent) + inprint(' %s = qmp__node;' % lhs, indent) + inprint(' }', indent) + inprint('}', indent) + +def print_type_marshal_definition(name, typeinfo): + c_var_name = de_camel_case(name) + if qmp_type_is_event(name): + return + + print ''' +QObject *qmp_marshal_type_%s(%s src) +{''' % (name, qmp_type_to_c(name)) + print ' QObject *qmp__retval;' + print_metatype_def(typeinfo, 'src', 'qmp__retval') + print ''' return qmp__retval; +} + +%s qmp_unmarshal_type_%s(QObject *src, Error **errp) +{''' % (qmp_type_to_c(name), name) + print ' Error *qmp__err = NULL;' + print ' %s qmp__retval = qmp_alloc_%s();' % (qmp_type_to_c(name), c_var_name) + print_metatype_undef(typeinfo, 'src', 'qmp__retval') + print ''' return qmp__retval; +qmp__err_out: + error_propagate(errp, qmp__err); + %s(qmp__retval); + return NULL; +}''' % (qmp_free_func(name)) + +def print_type_marshal_declaration(name, typeinfo): + if qmp_type_is_event(name): + return + + if is_dict(typeinfo): + print + print 'QObject *qmp_marshal_type_%s(%s src);' % (name, qmp_type_to_c(name)) + print '%s qmp_unmarshal_type_%s(QObject *src, Error **errp);' % (qmp_type_to_c(name), name) + +def print_enum_marshal_declaration(name, entries): + print + print 'QObject *qmp_marshal_type_%s(%s value);' % (name, name) + print '%s qmp_unmarshal_type_%s(QObject *obj, Error **errp);' % (name, name) + +def print_enum_marshal_definition(name, entries): + print ''' +QObject *qmp_marshal_type_%s(%s value) +{ + return QOBJECT(qint_from_int(value)); +} +''' % (name, name) + + print ''' +%s qmp_unmarshal_type_%s(QObject *obj, Error **errp) +{ + return (%s)qint_get_int(qobject_to_qint(obj)); +} +''' % (name, name, name) + def tokenize(data): while len(data): if data[0] in ['{', '}', ':', ',', '[', ']']: @@ -336,6 +484,10 @@ if len(sys.argv) == 2: kind = 'types-body' elif sys.argv[1] == '--types-header': kind = 'types-header' + elif sys.argv[1] == '--marshal-body': + kind = 'marshal-body' + elif sys.argv[1] == '--marshal-header': + kind = 'marshal-header' if kind == 'types-header': print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */ @@ -351,6 +503,20 @@ elif kind == 'types-body': #include "qmp-types.h" #include "qemu-common.h" ''' +elif kind == 'marshal-header': + print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */ +#ifndef QMP_MARSHAL_TYPES_H +#define QMP_MARSHAL_TYPES_H + +#include "qmp-marshal-types-core.h" + +''' +elif kind == 'marshal-body': + print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */ + +#include "qmp-marshal-types.h" +#include "qerror.h" +''' exprs = [] expr = '' @@ -382,12 +548,20 @@ for s in exprs: print_type_definition(key, s[key]) elif kind == 'types-header': print_type_declaration(key, s[key]) + elif kind == 'marshal-body': + print_type_marshal_definition(key, s[key]) + elif kind == 'marshal-header': + print_type_marshal_declaration(key, s[key]) else: enum_types.append(key) if kind == 'types-header': print_enum_declaration(key, s[key]) elif kind == 'types-body': print_enum_definition(key, s[key]) + elif kind == 'marshal-header': + print_enum_marshal_declaration(key, s[key]) + elif kind == 'marshal-body': + print_enum_marshal_definition(key, s[key]) if kind.endswith('header'): print '#endif' 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