From patchwork Wed Mar 26 10:37:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hu Tao X-Patchwork-Id: 333866 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 71F6514008D for ; Wed, 26 Mar 2014 23:54:12 +1100 (EST) Received: from localhost ([::1]:47810 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSnLO-0005OQ-IU for incoming@patchwork.ozlabs.org; Wed, 26 Mar 2014 08:54:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38138) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSlje-0002dX-6J for qemu-devel@nongnu.org; Wed, 26 Mar 2014 07:11:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WSljZ-0003FF-He for qemu-devel@nongnu.org; Wed, 26 Mar 2014 07:11:06 -0400 Received: from [59.151.112.132] (port=53275 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSljY-0003CR-BF for qemu-devel@nongnu.org; Wed, 26 Mar 2014 07:11:01 -0400 X-IronPort-AV: E=Sophos;i="4.97,734,1389715200"; d="scan'208";a="28487342" Received: from unknown (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 26 Mar 2014 18:34:35 +0800 Received: from G08CNEXCHPEKD01.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id s2QAapw4003096; Wed, 26 Mar 2014 18:36:56 +0800 Received: from G08CNEXMBPEKD03.g08.fujitsu.local ([10.167.33.86]) by G08CNEXCHPEKD01.g08.fujitsu.local ([10.167.33.80]) with mapi id 14.03.0146.002; Wed, 26 Mar 2014 18:37:07 +0800 From: "hutao@cn.fujitsu.com" To: "qemu-devel@nongnu.org" Thread-Topic: [PATCH v3 30/34] qapi: make string input visitor parse int list Thread-Index: AQHPSN9VdPiDg+vW002+H4oG86++Cw== Date: Wed, 26 Mar 2014 10:37:02 +0000 Message-ID: References: In-Reply-To: Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.167.226.102] MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 59.151.112.132 Cc: "ehabkost@redhat.com" , "imammedo@redhat.com" , "mtosatti@redhat.com" , Paolo Bonzini , "a.motakis@virtualopensystems.com" , "gaowanlong@cn.fujitsu.com" Subject: [Qemu-devel] [PATCH v3 30/34] qapi: make string input visitor parse int list X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Hu Tao --- qapi/string-input-visitor.c | 158 ++++++++++++++++++++++++++++++++++++-- tests/test-string-input-visitor.c | 34 ++++++++ 2 files changed, 184 insertions(+), 8 deletions(-) diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 793548a..ab9301e 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -15,31 +15,159 @@ #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; + char *endptr; + + if (!siv->ranges) { + 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') { + range_list_add(siv->ranges, start, 1); + 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') { + range_list_add(siv->ranges, start, end - start + 1); + str = NULL; + } else if (*endptr == ',') { + str = endptr + 1; + range_list_add(siv->ranges, start, end - start + 1); + } else { + /* error */ + return; + } + } else { + return; + } + } else if (*endptr == ',') { + str = endptr + 1; + range_list_add(siv->ranges, start, 1); + } else { + return; + } + } else { + return; + } + } while (str); + } +} + +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 +268,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 +293,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 d406263..c7c67f7 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) { @@ -193,6 +222,7 @@ 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_bool(v, &bres, NULL, NULL); @@ -200,11 +230,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 +260,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",