mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 18:05:37 +00:00
qapi: make string input visitor parse int list
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Tested-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> MST: split up patch
This commit is contained in:
parent
cac124d17c
commit
659268ffbf
|
@ -15,31 +15,205 @@
|
|||
#include "qapi/visitor-impl.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/range.h"
|
||||
|
||||
|
||||
struct StringInputVisitor
|
||||
{
|
||||
Visitor visitor;
|
||||
|
||||
bool head;
|
||||
|
||||
GList *ranges;
|
||||
GList *cur_range;
|
||||
int64_t cur;
|
||||
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static void parse_str(StringInputVisitor *siv, Error **errp)
|
||||
{
|
||||
char *str = (char *) siv->string;
|
||||
long long start, end;
|
||||
Range *cur;
|
||||
char *endptr;
|
||||
|
||||
if (siv->ranges) {
|
||||
return;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
do {
|
||||
start = strtoll(str, &endptr, 0);
|
||||
if (errno == 0 && endptr > str && INT64_MIN <= start &&
|
||||
start <= INT64_MAX) {
|
||||
if (*endptr == '\0') {
|
||||
cur = g_malloc0(sizeof(*cur));
|
||||
cur->begin = start;
|
||||
cur->end = start + 1;
|
||||
siv->ranges = g_list_insert_sorted_merged(siv->ranges, cur,
|
||||
range_compare);
|
||||
cur = NULL;
|
||||
str = NULL;
|
||||
} else if (*endptr == '-') {
|
||||
str = endptr + 1;
|
||||
end = strtoll(str, &endptr, 0);
|
||||
if (errno == 0 && endptr > str &&
|
||||
INT64_MIN <= end && end <= INT64_MAX && start <= end &&
|
||||
(start > INT64_MAX - 65536 ||
|
||||
end < start + 65536)) {
|
||||
if (*endptr == '\0') {
|
||||
cur = g_malloc0(sizeof(*cur));
|
||||
cur->begin = start;
|
||||
cur->end = end + 1;
|
||||
siv->ranges =
|
||||
g_list_insert_sorted_merged(siv->ranges,
|
||||
cur,
|
||||
range_compare);
|
||||
cur = NULL;
|
||||
str = NULL;
|
||||
} else if (*endptr == ',') {
|
||||
str = endptr + 1;
|
||||
cur = g_malloc0(sizeof(*cur));
|
||||
cur->begin = start;
|
||||
cur->end = end + 1;
|
||||
siv->ranges =
|
||||
g_list_insert_sorted_merged(siv->ranges,
|
||||
cur,
|
||||
range_compare);
|
||||
cur = NULL;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
} else if (*endptr == ',') {
|
||||
str = endptr + 1;
|
||||
cur = g_malloc0(sizeof(*cur));
|
||||
cur->begin = start;
|
||||
cur->end = start + 1;
|
||||
siv->ranges = g_list_insert_sorted_merged(siv->ranges,
|
||||
cur,
|
||||
range_compare);
|
||||
cur = NULL;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
} while (str);
|
||||
|
||||
return;
|
||||
error:
|
||||
g_list_free_full(siv->ranges, g_free);
|
||||
assert(siv->ranges == NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
start_list(Visitor *v, const char *name, Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
|
||||
parse_str(siv, errp);
|
||||
|
||||
siv->cur_range = g_list_first(siv->ranges);
|
||||
if (siv->cur_range) {
|
||||
Range *r = siv->cur_range->data;
|
||||
if (r) {
|
||||
siv->cur = r->begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GenericList *
|
||||
next_list(Visitor *v, GenericList **list, Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
GenericList **link;
|
||||
Range *r;
|
||||
|
||||
if (!siv->ranges || !siv->cur_range) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = siv->cur_range->data;
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (siv->cur < r->begin || siv->cur >= r->end) {
|
||||
siv->cur_range = g_list_next(siv->cur_range);
|
||||
if (!siv->cur_range) {
|
||||
return NULL;
|
||||
}
|
||||
r = siv->cur_range->data;
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
siv->cur = r->begin;
|
||||
}
|
||||
|
||||
if (siv->head) {
|
||||
link = list;
|
||||
siv->head = false;
|
||||
} else {
|
||||
link = &(*list)->next;
|
||||
}
|
||||
|
||||
*link = g_malloc0(sizeof **link);
|
||||
return *link;
|
||||
}
|
||||
|
||||
static void
|
||||
end_list(Visitor *v, Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
siv->head = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!siv->string) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"integer");
|
||||
return;
|
||||
}
|
||||
|
||||
*obj = val;
|
||||
parse_str(siv, errp);
|
||||
|
||||
if (!siv->ranges) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!siv->cur_range) {
|
||||
Range *r;
|
||||
|
||||
siv->cur_range = g_list_first(siv->ranges);
|
||||
if (!siv->cur_range) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = siv->cur_range->data;
|
||||
if (!r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
siv->cur = r->begin;
|
||||
}
|
||||
|
||||
*obj = siv->cur;
|
||||
siv->cur++;
|
||||
return;
|
||||
|
||||
error:
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name,
|
||||
"an int64 value or range");
|
||||
}
|
||||
|
||||
static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
|
||||
|
@ -140,6 +314,7 @@ Visitor *string_input_get_visitor(StringInputVisitor *v)
|
|||
|
||||
void string_input_visitor_cleanup(StringInputVisitor *v)
|
||||
{
|
||||
g_list_free_full(v->ranges, g_free);
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
|
@ -155,8 +330,12 @@ StringInputVisitor *string_input_visitor_new(const char *str)
|
|||
v->visitor.type_bool = parse_type_bool;
|
||||
v->visitor.type_str = parse_type_str;
|
||||
v->visitor.type_number = parse_type_number;
|
||||
v->visitor.start_list = start_list;
|
||||
v->visitor.next_list = next_list;
|
||||
v->visitor.end_list = end_list;
|
||||
v->visitor.optional = parse_optional;
|
||||
|
||||
v->string = str;
|
||||
v->head = true;
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,35 @@ static void test_visitor_in_int(TestInputVisitorData *data,
|
|||
g_assert_cmpint(res, ==, value);
|
||||
}
|
||||
|
||||
static void test_visitor_in_intList(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
int64_t value[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20};
|
||||
int16List *res = NULL, *tmp;
|
||||
Error *errp = NULL;
|
||||
Visitor *v;
|
||||
int i = 0;
|
||||
|
||||
v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8");
|
||||
|
||||
visit_type_int16List(v, &res, NULL, &errp);
|
||||
g_assert(errp == NULL);
|
||||
tmp = res;
|
||||
while (i < sizeof(value) / sizeof(value[0])) {
|
||||
g_assert(tmp);
|
||||
g_assert_cmpint(tmp->value, ==, value[i++]);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
g_assert(!tmp);
|
||||
|
||||
tmp = res;
|
||||
while (tmp) {
|
||||
res = res->next;
|
||||
g_free(tmp);
|
||||
tmp = res;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_visitor_in_bool(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
|
@ -170,6 +199,7 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data,
|
|||
const void *unused)
|
||||
{
|
||||
int64_t ires;
|
||||
intList *ilres;
|
||||
bool bres;
|
||||
double nres;
|
||||
char *sres;
|
||||
|
@ -195,6 +225,10 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data,
|
|||
visit_type_int(v, &ires, NULL, NULL);
|
||||
visitor_input_teardown(data, NULL);
|
||||
|
||||
v = visitor_input_test_init(data, buf);
|
||||
visit_type_intList(v, &ilres, NULL, NULL);
|
||||
visitor_input_teardown(data, NULL);
|
||||
|
||||
v = visitor_input_test_init(data, buf);
|
||||
visit_type_bool(v, &bres, NULL, NULL);
|
||||
visitor_input_teardown(data, NULL);
|
||||
|
@ -231,6 +265,8 @@ int main(int argc, char **argv)
|
|||
|
||||
input_visitor_test_add("/string-visitor/input/int",
|
||||
&in_visitor_data, test_visitor_in_int);
|
||||
input_visitor_test_add("/string-visitor/input/intList",
|
||||
&in_visitor_data, test_visitor_in_intList);
|
||||
input_visitor_test_add("/string-visitor/input/bool",
|
||||
&in_visitor_data, test_visitor_in_bool);
|
||||
input_visitor_test_add("/string-visitor/input/number",
|
||||
|
|
Loading…
Reference in a new issue