Merge remote-tracking branch 'bonzini/qdev-props-for-anthony' into staging

* bonzini/qdev-props-for-anthony:
  qdev: drop unnecessary parse/print methods
  qdev: use built-in QOM string parser
  qdev: accept hex properties only if prefixed by 0x
  qdev: accept both strings and integers for PCI addresses
  qom: add generic string parsing/printing
  qapi: add tests for string-based visitors
  qapi: add string-based visitors
  qapi: drop qmp_input_end_optional
  qapi: allow sharing enum implementation across visitors
This commit is contained in:
Anthony Liguori 2012-02-22 07:35:03 -06:00
commit 4732dcaf5a
16 changed files with 842 additions and 208 deletions

2
.gitignore vendored
View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -729,6 +729,30 @@ int64_t object_property_get_int(Object *obj, const char *name,
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

View file

@ -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;
}

23
qapi/qapi-visit-impl.h Normal file
View file

@ -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

View file

@ -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);

View file

@ -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;

138
qapi/string-input-visitor.c Normal file
View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);

195
test-string-input-visitor.c Normal file
View file

@ -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;
}

View file

@ -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;
}

View file

@ -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