On Wed, May 14, 2014 at 05:43:31PM +0800, Hu Tao wrote: > Signed-off-by: Hu Tao <hu...@cn.fujitsu.com>
Conflicts with commit e2cd0f4fb42b1fae65ad22e8efde9804446e6254 qapi: Replace start_optional()/end_optional() by optional() needs a rebase. > --- > qapi/string-input-visitor.c | 181 > ++++++++++++++++++++++++++++++++++++-- > tests/test-string-input-visitor.c | 39 ++++++++ > 2 files changed, 212 insertions(+), 8 deletions(-) > > diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c > index 793548a..0f6add7 100644 > --- a/qapi/string-input-visitor.c > +++ b/qapi/string-input-visitor.c > @@ -15,31 +15,182 @@ > #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; > + > + SignedRangeList *ranges; > + SignedRange *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; > + SignedRange *r, *next; > + char *endptr; > + > + if (siv->ranges) { > + return; > + } > + > + siv->ranges = g_malloc0(sizeof(*siv->ranges)); > + QTAILQ_INIT(siv->ranges); > + errno = 0; > + do { > + start = strtoll(str, &endptr, 0); > + if (errno == 0 && endptr > str && INT64_MIN <= start && > + start <= INT64_MAX) { > + if (*endptr == '\0') { > + if (!range_list_add(siv->ranges, start, 1)) { > + goto error; > + } > + 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') { > + if (!range_list_add(siv->ranges, start, > + end - start + 1)) { > + goto error; > + } > + str = NULL; > + } else if (*endptr == ',') { > + str = endptr + 1; > + if (!range_list_add(siv->ranges, start, > + end - start + 1)) { > + goto error; > + } > + } else { > + goto error; > + } > + } else { > + goto error; > + } > + } else if (*endptr == ',') { > + str = endptr + 1; > + if (!range_list_add(siv->ranges, start, 1)) { > + goto error; > + } > + } else { > + goto error; > + } > + } else { > + goto error; > + } > + } while (str); > + > + return; > +error: > + if (siv->ranges) { > + QTAILQ_FOREACH_SAFE(r, siv->ranges, entry, next) { > + QTAILQ_REMOVE(siv->ranges, r, entry); > + g_free(r); > + } > + g_free(siv->ranges); > + 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); > + > + if (siv->ranges) { > + siv->cur_range = QTAILQ_FIRST(siv->ranges); > + if (siv->cur_range) { > + siv->cur = siv->cur_range->start; > + } > + } > +} > + > +static GenericList * > +next_list(Visitor *v, GenericList **list, Error **errp) > +{ > + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); > + GenericList **link; > + > + if (!siv->ranges || !siv->cur_range) { > + return NULL; > + } > + > + if (siv->cur < siv->cur_range->start || > + siv->cur >= (siv->cur_range->start + siv->cur_range->length)) { > + siv->cur_range = QTAILQ_NEXT(siv->cur_range, entry); > + if (siv->cur_range) { > + siv->cur = siv->cur_range->start; > + } else { > + return NULL; > + } > + } > + > + 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) { > + siv->cur_range = QTAILQ_FIRST(siv->ranges); > + if (siv->cur_range) { > + siv->cur = siv->cur_range->start; > + } else { > + goto error; > + } > + } > + > + *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 +291,16 @@ Visitor *string_input_get_visitor(StringInputVisitor *v) > > void string_input_visitor_cleanup(StringInputVisitor *v) > { > + SignedRange *r, *next; > + > + if (v->ranges) { > + QTAILQ_FOREACH_SAFE(r, v->ranges, entry, next) { > + QTAILQ_REMOVE(v->ranges, r, entry); > + g_free(r); > + } > + g_free(v->ranges); > + } > + > g_free(v); > } > > @@ -155,8 +316,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.start_optional = parse_start_optional; > > v->string = str; > + v->head = true; > return v; > } > diff --git a/tests/test-string-input-visitor.c > b/tests/test-string-input-visitor.c > index 877e737..05b3dab 100644 > --- a/tests/test-string-input-visitor.c > +++ b/tests/test-string-input-visitor.c > @@ -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[] = {-2, -1, 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,-2-1,2-4,20,5-9,1-8"); > + > + visit_type_int16List(v, &res, NULL, &errp); > + g_assert(!error_is_set(&errp)); > + 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; > @@ -193,6 +223,11 @@ static void test_visitor_in_fuzz(TestInputVisitorData > *data, > > v = visitor_input_test_init(data, buf); > 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); > @@ -200,11 +235,13 @@ static void test_visitor_in_fuzz(TestInputVisitorData > *data, > > v = visitor_input_test_init(data, buf); > visit_type_number(v, &nres, NULL, NULL); > + visitor_input_teardown(data, NULL); > > v = visitor_input_test_init(data, buf); > sres = NULL; > visit_type_str(v, &sres, NULL, NULL); > g_free(sres); > + visitor_input_teardown(data, NULL); > > v = visitor_input_test_init(data, buf); > visit_type_EnumOne(v, &eres, NULL, NULL); > @@ -228,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", > -- > 1.8.5.2.229.g4448466 >