diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.objs | 5 | ||||
-rw-r--r-- | hw/qdev-properties.c | 186 | ||||
-rw-r--r-- | include/qemu/object.h | 24 | ||||
-rw-r--r-- | qapi/qapi-visit-core.c | 51 | ||||
-rw-r--r-- | qapi/qapi-visit-impl.h | 23 | ||||
-rw-r--r-- | qapi/qmp-input-visitor.c | 39 | ||||
-rw-r--r-- | qapi/qmp-output-visitor.c | 22 | ||||
-rw-r--r-- | qapi/string-input-visitor.c | 138 | ||||
-rw-r--r-- | qapi/string-input-visitor.h | 25 | ||||
-rw-r--r-- | qapi/string-output-visitor.c | 89 | ||||
-rw-r--r-- | qapi/string-output-visitor.h | 26 | ||||
-rw-r--r-- | qom/object.c | 25 | ||||
-rw-r--r-- | test-string-input-visitor.c | 195 | ||||
-rw-r--r-- | test-string-output-visitor.c | 188 | ||||
-rw-r--r-- | tests/Makefile | 12 |
16 files changed, 842 insertions, 208 deletions
diff --git a/.gitignore b/.gitignore index f5aab2cb07..c72955aad1 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,8 @@ QMP/qmp-commands.txt test-coroutine test-qmp-input-visitor test-qmp-output-visitor +test-string-input-visitor +test-string-output-visitor fsdev/virtfs-proxy-helper.1 fsdev/virtfs-proxy-helper.pod .gdbinit diff --git a/Makefile.objs b/Makefile.objs index 391e524525..2a4dbd1ea2 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -412,8 +412,9 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o ###################################################################### # qapi -qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o -qapi-nested-y += qmp-registry.o qmp-dispatch.o +qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o +qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +qapi-nested-y += string-input-visitor.o string-output-visitor.o qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y)) common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y) diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 7b74dd5beb..0423af1c31 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -27,16 +27,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) } /* Bit */ -static int parse_bit(DeviceState *dev, Property *prop, const char *str) -{ - if (!strcasecmp(str, "on")) - bit_prop_set(dev, prop, true); - else if (!strcasecmp(str, "off")) - bit_prop_set(dev, prop, false); - else - return -EINVAL; - return 0; -} static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) { @@ -79,7 +69,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_bit = { .name = "boolean", .legacy_name = "on/off", - .parse = parse_bit, .print = print_bit, .get = get_bit, .set = set_bit, @@ -87,26 +76,6 @@ PropertyInfo qdev_prop_bit = { /* --- 8bit integer --- */ -static int parse_uint8(DeviceState *dev, Property *prop, const char *str) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu8, *ptr); -} - static void get_int8(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -149,8 +118,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .parse = parse_uint8, - .print = print_uint8, .get = get_int8, .set = set_int8, .min = 0, @@ -164,6 +131,10 @@ static int parse_hex8(DeviceState *dev, Property *prop, const char *str) uint8_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -191,26 +162,6 @@ PropertyInfo qdev_prop_hex8 = { /* --- 16bit integer --- */ -static int parse_uint16(DeviceState *dev, Property *prop, const char *str) -{ - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu16, *ptr); -} - static void get_int16(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -253,8 +204,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .parse = parse_uint16, - .print = print_uint16, .get = get_int16, .set = set_int16, .min = 0, @@ -263,26 +212,6 @@ PropertyInfo qdev_prop_uint16 = { /* --- 32bit integer --- */ -static int parse_uint32(DeviceState *dev, Property *prop, const char *str) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu32, *ptr); -} - static void get_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -325,37 +254,14 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint32 = { .name = "uint32", - .parse = parse_uint32, - .print = print_uint32, .get = get_int32, .set = set_int32, .min = 0, .max = 0xFFFFFFFFULL, }; -static int parse_int32(DeviceState *dev, Property *prop, const char *str) -{ - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - *ptr = strtol(str, &end, 10); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRId32, *ptr); -} - PropertyInfo qdev_prop_int32 = { .name = "int32", - .parse = parse_int32, - .print = print_int32, .get = get_int32, .set = set_int32, .min = -0x80000000LL, @@ -369,6 +275,10 @@ static int parse_hex32(DeviceState *dev, Property *prop, const char *str) uint32_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -396,26 +306,6 @@ PropertyInfo qdev_prop_hex32 = { /* --- 64bit integer --- */ -static int parse_uint64(DeviceState *dev, Property *prop, const char *str) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoull(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu64, *ptr); -} - static void get_int64(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -443,8 +333,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .parse = parse_uint64, - .print = print_uint64, .get = get_int64, .set = set_int64, }; @@ -456,6 +344,10 @@ static int parse_hex64(DeviceState *dev, Property *prop, const char *str) uint64_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoull(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -737,19 +629,6 @@ PropertyInfo qdev_prop_netdev = { /* --- vlan --- */ -static int parse_vlan(DeviceState *dev, Property *prop, const char *str) -{ - VLANState **ptr = qdev_get_prop_ptr(dev, prop); - int id; - - if (sscanf(str, "%d", &id) != 1) - return -EINVAL; - *ptr = qemu_find_vlan(id, 1); - if (*ptr == NULL) - return -ENOENT; - return 0; -} - static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) { VLANState **ptr = qdev_get_prop_ptr(dev, prop); @@ -808,7 +687,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_vlan = { .name = "vlan", - .parse = parse_vlan, .print = print_vlan, .get = get_vlan, .set = set_vlan, @@ -943,25 +821,40 @@ PropertyInfo qdev_prop_losttickpolicy = { /* * bus-local address, i.e. "$slot" or "$slot.$fn" */ -static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; + Error *local_err = NULL; + char *str = (char *)""; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + return set_int32(obj, v, opaque, name, errp); + } if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { fn = 0; if (sscanf(str, "%x%n", &slot, &n) != 1) { - return -EINVAL; + goto invalid; } } - if (str[n] != '\0') - return -EINVAL; - if (fn > 7) - return -EINVAL; - if (slot > 31) - return -EINVAL; + if (str[n] != '\0' || fn > 7 || slot > 31) { + goto invalid; + } *ptr = slot << 3 | fn; - return 0; + return; + +invalid: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -978,10 +871,9 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t PropertyInfo qdev_prop_pci_devfn = { .name = "int32", .legacy_name = "pci-devfn", - .parse = parse_pci_devfn, .print = print_pci_devfn, .get = get_int32, - .set = set_int32, + .set = set_pci_devfn, /* FIXME: this should be -1...255, but the address is stored * into an uint32_t rather than int32_t. */ @@ -1054,9 +946,9 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) legacy_name = g_strdup_printf("legacy-%s", name); if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - object_property_set_str(OBJECT(dev), value, legacy_name, &err); + object_property_parse(OBJECT(dev), value, legacy_name, &err); } else { - object_property_set_str(OBJECT(dev), value, name, &err); + object_property_parse(OBJECT(dev), value, name, &err); } g_free(legacy_name); diff --git a/include/qemu/object.h b/include/qemu/object.h index 5179c0cf5a..ff6be14dfc 100644 --- a/include/qemu/object.h +++ b/include/qemu/object.h @@ -730,6 +730,30 @@ void object_property_set(Object *obj, struct Visitor *v, const char *name, struct Error **errp); /** + * object_property_parse: + * @obj: the object + * @string: the string that will be used to parse the property value. + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Parses a string and writes the result into a property of an object. + */ +void object_property_parse(Object *obj, const char *string, + const char *name, struct Error **errp); + +/** + * object_property_print: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns a string representation of the value of the property. The + * caller shall free the string. + */ +char *object_property_print(Object *obj, const char *name, + struct Error **errp); + +/** * object_property_get_type: * @obj: the object * @name: the name of the property diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index ddef3eda12..a4e088c9fc 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -12,6 +12,7 @@ */ #include "qapi/qapi-visit-core.h" +#include "qapi/qapi-visit-impl.h" void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp) @@ -116,3 +117,53 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp) v->type_number(v, obj, name, errp); } } + +void output_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, + Error **errp) +{ + int i = 0; + int value = *obj; + char *enum_str; + + assert(strings); + while (strings[i++] != NULL); + if (value < 0 || value >= i - 1) { + error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); + return; + } + + enum_str = (char *)strings[value]; + visit_type_str(v, &enum_str, name, errp); +} + +void input_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, + Error **errp) +{ + int64_t value = 0; + char *enum_str; + + assert(strings); + + visit_type_str(v, &enum_str, name, errp); + if (error_is_set(errp)) { + return; + } + + while (strings[value] != NULL) { + if (strcmp(strings[value], enum_str) == 0) { + break; + } + value++; + } + + if (strings[value] == NULL) { + error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); + g_free(enum_str); + return; + } + + g_free(enum_str); + *obj = value; +} diff --git a/qapi/qapi-visit-impl.h b/qapi/qapi-visit-impl.h new file mode 100644 index 0000000000..0f3a1898fe --- /dev/null +++ b/qapi/qapi-visit-impl.h @@ -0,0 +1,23 @@ +/* + * Core Definitions for QAPI Visitor implementations + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Author: Paolo Bonizni <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +#ifndef QAPI_VISITOR_IMPL_H +#define QAPI_VISITOR_IMPL_H + +#include "qapi/qapi-types-core.h" +#include "qapi/qapi-visit-core.h" + +void input_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, Error **errp); +void output_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, Error **errp); + +#endif diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index c78022bb87..e6b6152e08 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -12,6 +12,7 @@ */ #include "qmp-input-visitor.h" +#include "qapi/qapi-visit-impl.h" #include "qemu-queue.h" #include "qemu-common.h" #include "qemu-objects.h" @@ -217,37 +218,6 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name, *obj = qfloat_get_double(qobject_to_qfloat(qobj)); } -static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[], - const char *kind, const char *name, - Error **errp) -{ - int64_t value = 0; - char *enum_str; - - assert(strings); - - qmp_input_type_str(v, &enum_str, name, errp); - if (error_is_set(errp)) { - return; - } - - while (strings[value] != NULL) { - if (strcmp(strings[value], enum_str) == 0) { - break; - } - value++; - } - - if (strings[value] == NULL) { - error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); - g_free(enum_str); - return; - } - - g_free(enum_str); - *obj = value; -} - static void qmp_input_start_optional(Visitor *v, bool *present, const char *name, Error **errp) { @@ -262,10 +232,6 @@ static void qmp_input_start_optional(Visitor *v, bool *present, *present = true; } -static void qmp_input_end_optional(Visitor *v, Error **errp) -{ -} - Visitor *qmp_input_get_visitor(QmpInputVisitor *v) { return &v->visitor; @@ -288,13 +254,12 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.start_list = qmp_input_start_list; v->visitor.next_list = qmp_input_next_list; v->visitor.end_list = qmp_input_end_list; - v->visitor.type_enum = qmp_input_type_enum; + v->visitor.type_enum = input_type_enum; v->visitor.type_int = qmp_input_type_int; v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; v->visitor.start_optional = qmp_input_start_optional; - v->visitor.end_optional = qmp_input_end_optional; v->obj = obj; qobject_incref(v->obj); diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index f76d0159cd..e0697b0d0f 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -12,6 +12,7 @@ */ #include "qmp-output-visitor.h" +#include "qapi/qapi-visit-impl.h" #include "qemu-queue.h" #include "qemu-common.h" #include "qemu-objects.h" @@ -180,25 +181,6 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name, qmp_output_add(qov, name, qfloat_from_double(*obj)); } -static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[], - const char *kind, const char *name, - Error **errp) -{ - int i = 0; - int value = *obj; - char *enum_str; - - assert(strings); - while (strings[i++] != NULL); - if (value < 0 || value >= i - 1) { - error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); - return; - } - - enum_str = (char *)strings[value]; - qmp_output_type_str(v, &enum_str, name, errp); -} - QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) { QObject *obj = qmp_output_first(qov); @@ -239,7 +221,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void) v->visitor.start_list = qmp_output_start_list; v->visitor.next_list = qmp_output_next_list; v->visitor.end_list = qmp_output_end_list; - v->visitor.type_enum = qmp_output_type_enum; + v->visitor.type_enum = output_type_enum; v->visitor.type_int = qmp_output_type_int; v->visitor.type_bool = qmp_output_type_bool; v->visitor.type_str = qmp_output_type_str; diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c new file mode 100644 index 0000000000..497eb9a60a --- /dev/null +++ b/qapi/string-input-visitor.c @@ -0,0 +1,138 @@ +/* + * String parsing visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "string-input-visitor.h" +#include "qapi/qapi-visit-impl.h" +#include "qerror.h" + +struct StringInputVisitor +{ + Visitor visitor; + const char *string; +}; + +static void parse_type_int(Visitor *v, int64_t *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + char *endp = (char *) siv->string; + long long val; + + errno = 0; + if (siv->string) { + val = strtoll(siv->string, &endp, 0); + } + if (!siv->string || errno || endp == siv->string || *endp) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "integer"); + return; + } + + *obj = val; +} + +static void parse_type_bool(Visitor *v, bool *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + if (siv->string) { + if (!strcasecmp(siv->string, "on") || + !strcasecmp(siv->string, "yes") || + !strcasecmp(siv->string, "true")) { + *obj = true; + return; + } + if (!strcasecmp(siv->string, "off") || + !strcasecmp(siv->string, "no") || + !strcasecmp(siv->string, "false")) { + *obj = false; + return; + } + } + + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "boolean"); +} + +static void parse_type_str(Visitor *v, char **obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + if (siv->string) { + *obj = g_strdup(siv->string); + } else { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "string"); + } +} + +static void parse_type_number(Visitor *v, double *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + char *endp = (char *) siv->string; + double val; + + errno = 0; + if (siv->string) { + val = strtod(siv->string, &endp); + } + if (!siv->string || errno || endp == siv->string || *endp) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "number"); + return; + } + + *obj = val; +} + +static void parse_start_optional(Visitor *v, bool *present, + const char *name, Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + if (!siv->string) { + *present = false; + return; + } + + *present = true; +} + +Visitor *string_input_get_visitor(StringInputVisitor *v) +{ + return &v->visitor; +} + +void string_input_visitor_cleanup(StringInputVisitor *v) +{ + g_free(v); +} + +StringInputVisitor *string_input_visitor_new(const char *str) +{ + StringInputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type_enum = input_type_enum; + v->visitor.type_int = parse_type_int; + v->visitor.type_bool = parse_type_bool; + v->visitor.type_str = parse_type_str; + v->visitor.type_number = parse_type_number; + v->visitor.start_optional = parse_start_optional; + + v->string = str; + return v; +} diff --git a/qapi/string-input-visitor.h b/qapi/string-input-visitor.h new file mode 100644 index 0000000000..d269d42cef --- /dev/null +++ b/qapi/string-input-visitor.h @@ -0,0 +1,25 @@ +/* + * String parsing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef STRING_INPUT_VISITOR_H +#define STRING_INPUT_VISITOR_H + +#include "qapi-visit-core.h" + +typedef struct StringInputVisitor StringInputVisitor; + +StringInputVisitor *string_input_visitor_new(const char *str); +void string_input_visitor_cleanup(StringInputVisitor *v); + +Visitor *string_input_get_visitor(StringInputVisitor *v); + +#endif diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c new file mode 100644 index 0000000000..92b0305212 --- /dev/null +++ b/qapi/string-output-visitor.c @@ -0,0 +1,89 @@ +/* + * String printing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "string-output-visitor.h" +#include "qapi/qapi-visit-impl.h" +#include "qerror.h" + +struct StringOutputVisitor +{ + Visitor visitor; + char *string; +}; + +static void string_output_set(StringOutputVisitor *sov, char *string) +{ + g_free(sov->string); + sov->string = string; +} + +static void print_type_int(Visitor *v, int64_t *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup_printf("%lld", (long long) *obj)); +} + +static void print_type_bool(Visitor *v, bool *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup(*obj ? "true" : "false")); +} + +static void print_type_str(Visitor *v, char **obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup(*obj ? *obj : "")); +} + +static void print_type_number(Visitor *v, double *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup_printf("%g", *obj)); +} + +char *string_output_get_string(StringOutputVisitor *sov) +{ + char *string = sov->string; + sov->string = NULL; + return string; +} + +Visitor *string_output_get_visitor(StringOutputVisitor *sov) +{ + return &sov->visitor; +} + +void string_output_visitor_cleanup(StringOutputVisitor *sov) +{ + g_free(sov->string); + g_free(sov); +} + +StringOutputVisitor *string_output_visitor_new(void) +{ + StringOutputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type_enum = output_type_enum; + v->visitor.type_int = print_type_int; + v->visitor.type_bool = print_type_bool; + v->visitor.type_str = print_type_str; + v->visitor.type_number = print_type_number; + + return v; +} diff --git a/qapi/string-output-visitor.h b/qapi/string-output-visitor.h new file mode 100644 index 0000000000..8868454110 --- /dev/null +++ b/qapi/string-output-visitor.h @@ -0,0 +1,26 @@ +/* + * String printing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef STRING_OUTPUT_VISITOR_H +#define STRING_OUTPUT_VISITOR_H + +#include "qapi-visit-core.h" + +typedef struct StringOutputVisitor StringOutputVisitor; + +StringOutputVisitor *string_output_visitor_new(void); +void string_output_visitor_cleanup(StringOutputVisitor *v); + +char *string_output_get_string(StringOutputVisitor *v); +Visitor *string_output_get_visitor(StringOutputVisitor *v); + +#endif diff --git a/qom/object.c b/qom/object.c index 0cbd9bb004..941c291bf9 100644 --- a/qom/object.c +++ b/qom/object.c @@ -13,6 +13,8 @@ #include "qemu/object.h" #include "qemu-common.h" #include "qapi/qapi-visit-core.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" /* TODO: replace QObject with a simpler visitor to avoid a dependency * of the QOM core on QObject? */ @@ -782,6 +784,29 @@ int64_t object_property_get_int(Object *obj, const char *name, return retval; } +void object_property_parse(Object *obj, const char *string, + const char *name, Error **errp) +{ + StringInputVisitor *mi; + mi = string_input_visitor_new(string); + object_property_set(obj, string_input_get_visitor(mi), name, errp); + + string_input_visitor_cleanup(mi); +} + +char *object_property_print(Object *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *mo; + char *string; + + mo = string_output_visitor_new(); + object_property_get(obj, string_output_get_visitor(mo), name, NULL); + string = string_output_get_string(mo); + string_output_visitor_cleanup(mo); + return string; +} + const char *object_property_get_type(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = object_property_find(obj, name); diff --git a/test-string-input-visitor.c b/test-string-input-visitor.c new file mode 100644 index 0000000000..5370e32041 --- /dev/null +++ b/test-string-input-visitor.c @@ -0,0 +1,195 @@ +/* + * String Input Visitor unit-tests. + * + * Copyright (C) 2012 Red Hat Inc. + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-input-visitor) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <stdarg.h> + +#include "qapi/string-input-visitor.h" +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" + +typedef struct TestInputVisitorData { + StringInputVisitor *siv; +} TestInputVisitorData; + +static void visitor_input_teardown(TestInputVisitorData *data, + const void *unused) +{ + if (data->siv) { + string_input_visitor_cleanup(data->siv); + data->siv = NULL; + } +} + +/* This is provided instead of a test setup function so that the JSON + string used by the tests are kept in the test functions (and not + int main()) */ +static +Visitor *visitor_input_test_init(TestInputVisitorData *data, + const char *string) +{ + Visitor *v; + + data->siv = string_input_visitor_new(string); + g_assert(data->siv != NULL); + + v = string_input_get_visitor(data->siv); + g_assert(v != NULL); + + return v; +} + +static void test_visitor_in_int(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0, value = -42; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, "-42"); + + visit_type_int(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, value); +} + +static void test_visitor_in_bool(TestInputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + bool res = false; + Visitor *v; + + v = visitor_input_test_init(data, "true"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "yes"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "on"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "false"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "no"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "off"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); +} + +static void test_visitor_in_number(TestInputVisitorData *data, + const void *unused) +{ + double res = 0, value = 3.14; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, "3.14"); + + visit_type_number(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpfloat(res, ==, value); +} + +static void test_visitor_in_string(TestInputVisitorData *data, + const void *unused) +{ + char *res = NULL, *value = (char *) "Q E M U"; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, value); + + visit_type_str(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpstr(res, ==, value); + + g_free(res); +} + +static void test_visitor_in_enum(TestInputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + Visitor *v; + EnumOne i; + + for (i = 0; EnumOne_lookup[i]; i++) { + EnumOne res = -1; + + v = visitor_input_test_init(data, EnumOne_lookup[i]); + + visit_type_EnumOne(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(i, ==, res); + + visitor_input_teardown(data, NULL); + } + + data->siv = NULL; +} + +static void input_visitor_test_add(const char *testpath, + TestInputVisitorData *data, + void (*test_func)(TestInputVisitorData *data, const void *user_data)) +{ + g_test_add(testpath, TestInputVisitorData, data, NULL, test_func, + visitor_input_teardown); +} + +int main(int argc, char **argv) +{ + TestInputVisitorData in_visitor_data; + + g_test_init(&argc, &argv, NULL); + + input_visitor_test_add("/string-visitor/input/int", + &in_visitor_data, test_visitor_in_int); + input_visitor_test_add("/string-visitor/input/bool", + &in_visitor_data, test_visitor_in_bool); + input_visitor_test_add("/string-visitor/input/number", + &in_visitor_data, test_visitor_in_number); + input_visitor_test_add("/string-visitor/input/string", + &in_visitor_data, test_visitor_in_string); + input_visitor_test_add("/string-visitor/input/enum", + &in_visitor_data, test_visitor_in_enum); + + g_test_run(); + + return 0; +} diff --git a/test-string-output-visitor.c b/test-string-output-visitor.c new file mode 100644 index 0000000000..22909b84ef --- /dev/null +++ b/test-string-output-visitor.c @@ -0,0 +1,188 @@ +/* + * String Output Visitor unit-tests. + * + * Copyright (C) 2012 Red Hat Inc. + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-visitor) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> + +#include "qapi/string-output-visitor.h" +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" + +typedef struct TestOutputVisitorData { + StringOutputVisitor *sov; + Visitor *ov; +} TestOutputVisitorData; + +static void visitor_output_setup(TestOutputVisitorData *data, + const void *unused) +{ + data->sov = string_output_visitor_new(); + g_assert(data->sov != NULL); + + data->ov = string_output_get_visitor(data->sov); + g_assert(data->ov != NULL); +} + +static void visitor_output_teardown(TestOutputVisitorData *data, + const void *unused) +{ + string_output_visitor_cleanup(data->sov); + data->sov = NULL; + data->ov = NULL; +} + +static void test_visitor_out_int(TestOutputVisitorData *data, + const void *unused) +{ + int64_t value = -42; + Error *errp = NULL; + char *str; + + visit_type_int(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "-42"); + g_free(str); +} + +static void test_visitor_out_bool(TestOutputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + bool value = true; + char *str; + + visit_type_bool(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "true"); + g_free(str); +} + +static void test_visitor_out_number(TestOutputVisitorData *data, + const void *unused) +{ + double value = 3.14; + Error *errp = NULL; + char *str; + + visit_type_number(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "3.14"); + g_free(str); +} + +static void test_visitor_out_string(TestOutputVisitorData *data, + const void *unused) +{ + char *string = (char *) "Q E M U"; + Error *errp = NULL; + char *str; + + visit_type_str(data->ov, &string, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, string); + g_free(str); +} + +static void test_visitor_out_no_string(TestOutputVisitorData *data, + const void *unused) +{ + char *string = NULL; + Error *errp = NULL; + char *str; + + /* A null string should return "" */ + visit_type_str(data->ov, &string, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, ""); + g_free(str); +} + +static void test_visitor_out_enum(TestOutputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + char *str; + EnumOne i; + + for (i = 0; i < ENUM_ONE_MAX; i++) { + visit_type_EnumOne(data->ov, &i, "unused", &errp); + g_assert(!error_is_set(&errp)); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, EnumOne_lookup[i]); + g_free(str); + } +} + +static void test_visitor_out_enum_errors(TestOutputVisitorData *data, + const void *unused) +{ + EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; + Error *errp; + + for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { + errp = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); + g_assert(error_is_set(&errp) == true); + error_free(errp); + } +} + +static void output_visitor_test_add(const char *testpath, + TestOutputVisitorData *data, + void (*test_func)(TestOutputVisitorData *data, const void *user_data)) +{ + g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, + test_func, visitor_output_teardown); +} + +int main(int argc, char **argv) +{ + TestOutputVisitorData out_visitor_data; + + g_test_init(&argc, &argv, NULL); + + output_visitor_test_add("/string-visitor/output/int", + &out_visitor_data, test_visitor_out_int); + output_visitor_test_add("/string-visitor/output/bool", + &out_visitor_data, test_visitor_out_bool); + output_visitor_test_add("/string-visitor/output/number", + &out_visitor_data, test_visitor_out_number); + output_visitor_test_add("/string-visitor/output/string", + &out_visitor_data, test_visitor_out_string); + output_visitor_test_add("/string-visitor/output/no-string", + &out_visitor_data, test_visitor_out_no_string); + output_visitor_test_add("/string-visitor/output/enum", + &out_visitor_data, test_visitor_out_enum); + output_visitor_test_add("/string-visitor/output/enum-errors", + &out_visitor_data, test_visitor_out_enum_errors); + + g_test_run(); + + return 0; +} diff --git a/tests/Makefile b/tests/Makefile index 55e8eb0ad5..74b29dc076 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor -CHECKS += test-coroutine +CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS) @@ -12,7 +12,9 @@ check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y) check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y) test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y) -test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) +test-qmp-input-visitor.o test-qmp-output-visitor.o \ +test-string-input-visitor.o test-string-output-visitor.o \ + test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) $(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py @@ -25,6 +27,12 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") +test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) +test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o + +test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) +test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o + test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o |