From patchwork Wed Feb 19 07:54: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: 321767 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C35E72C0309 for ; Wed, 19 Feb 2014 18:58:32 +1100 (EST) Received: from localhost ([::1]:56985 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WG234-000267-J6 for incoming@patchwork.ozlabs.org; Wed, 19 Feb 2014 02:58:30 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49537) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WG20u-0007Rm-2L for qemu-devel@nongnu.org; Wed, 19 Feb 2014 02:56:20 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WG20p-0003Wd-9m for qemu-devel@nongnu.org; Wed, 19 Feb 2014 02:56:15 -0500 Received: from [222.73.24.84] (port=23891 helo=song.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WG20o-0003T0-Cp for qemu-devel@nongnu.org; Wed, 19 Feb 2014 02:56:11 -0500 X-IronPort-AV: E=Sophos;i="4.97,504,1389715200"; d="scan'208";a="9558776" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 19 Feb 2014 15:52:06 +0800 Received: from fnstmail02.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id s1J7tplY012638; Wed, 19 Feb 2014 15:55:55 +0800 Received: from G08FNSTD100614.fnst.cn.fujitsu.com ([10.167.226.102]) by fnstmail02.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.3) with ESMTP id 2014021915534257-35706 ; Wed, 19 Feb 2014 15:53:42 +0800 From: Hu Tao To: qemu-devel@nongnu.org Date: Wed, 19 Feb 2014 15:54:02 +0800 Message-Id: <2b9b6745ac6f7a5b697f479d684b226505952701.1392794450.git.hutao@cn.fujitsu.com> X-Mailer: git-send-email 1.8.5.2.229.g4448466 In-Reply-To: References: X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2014/02/19 15:53:42, Serialize by Router on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2014/02/19 15:53:46, Serialize complete at 2014/02/19 15:53:46 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 222.73.24.84 Cc: pbonzini@redhat.com, lersek@redhat.com, Wanlong Gao , imammedo@redhat.com Subject: [Qemu-devel] [PATCH v18 11/14] 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 Cc: Laszlo Ersek Signed-off-by: Hu Tao --- qapi/string-input-visitor.c | 160 ++++++++++++++++++++++++++++++++++++-- tests/test-string-input-visitor.c | 22 ++++++ 2 files changed, 176 insertions(+), 6 deletions(-) diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index a152f5d..4540ca3 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -15,30 +15,175 @@ #include "qapi/visitor-impl.h" #include "qapi/qmp/qerror.h" +enum ListMode { + LM_NONE, /* not traversing a list of repeated options */ + LM_STARTED, /* start_list() succeeded */ + + LM_IN_PROGRESS, /* next_list() has been called. + * + * Generating the next list link will consume the most + * recently parsed QemuOpt instance of the repeated + * option. + * + * Parsing a value into the list link will examine the + * next QemuOpt instance of the repeated option, and + * possibly enter LM_SIGNED_INTERVAL or + * LM_UNSIGNED_INTERVAL. + */ + + LM_SIGNED_INTERVAL, /* next_list() has been called. + * + * Generating the next list link will consume the most + * recently stored element from the signed interval, + * parsed from the most recent QemuOpt instance of the + * repeated option. This may consume QemuOpt itself + * and return to LM_IN_PROGRESS. + * + * Parsing a value into the list link will store the + * next element of the signed interval. + */ + + LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */ + + LM_END +}; + +typedef enum ListMode ListMode; + struct StringInputVisitor { Visitor visitor; + + ListMode list_mode; + + /* When parsing a list of repeating options as integers, values of the form + * "a-b", representing a closed interval, are allowed. Elements in the + * range are generated individually. + */ + union { + int64_t s; + uint64_t u; + } range_next, range_limit; + const char *string; }; +static void +start_list(Visitor *v, const char *name, Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + /* we can't traverse a list in a list */ + assert(siv->list_mode == LM_NONE); + siv->list_mode = LM_STARTED; +} + +static GenericList * +next_list(Visitor *v, GenericList **list, Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + GenericList **link; + + switch (siv->list_mode) { + case LM_STARTED: + siv->list_mode = LM_IN_PROGRESS; + link = list; + break; + + case LM_SIGNED_INTERVAL: + case LM_UNSIGNED_INTERVAL: + link = &(*list)->next; + + if (siv->list_mode == LM_SIGNED_INTERVAL) { + if (siv->range_next.s < siv->range_limit.s) { + ++siv->range_next.s; + break; + } + } else if (siv->range_next.u < siv->range_limit.u) { + ++siv->range_next.u; + break; + } + siv->list_mode = LM_END; + /* range has been completed, fall through */ + + case LM_END: + return NULL; + + case LM_IN_PROGRESS: + link = &(*list)->next; + break; + + default: + abort(); + } + + *link = g_malloc0(sizeof **link); + return *link; +} + +static void +end_list(Visitor *v, Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + assert(siv->list_mode == LM_STARTED || + siv->list_mode == LM_END || + siv->list_mode == LM_IN_PROGRESS || + siv->list_mode == LM_SIGNED_INTERVAL || + siv->list_mode == LM_UNSIGNED_INTERVAL); + siv->list_mode = LM_NONE; +} + 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; + char *str = (char *) siv->string; long long val; + char *endptr; - errno = 0; - if (siv->string) { - val = strtoll(siv->string, &endp, 0); + if (siv->list_mode == LM_SIGNED_INTERVAL) { + *obj = siv->range_next.s; + return; } - 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; + errno = 0; + val = strtoll(siv->string, &endptr, 0); + + if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) { + if (*endptr == '\0') { + *obj = val; + siv->list_mode = LM_END; + return; + } + if (*endptr == '-' && siv->list_mode == LM_IN_PROGRESS) { + long long val2; + + str = endptr + 1; + val2 = strtoll(str, &endptr, 0); + if (errno == 0 && endptr > str && *endptr == '\0' && + INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 && + (val > INT64_MAX - 65536 || + val2 < val + 65536)) { + siv->range_next.s = val; + siv->range_limit.s = val2; + siv->list_mode = LM_SIGNED_INTERVAL; + + /* as if entering on the top */ + *obj = siv->range_next.s; + return; + } + } + } + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, + (siv->list_mode == LM_NONE) ? "an int64 value" : + "an int64 value or range"); } static void parse_type_bool(Visitor *v, bool *obj, const char *name, @@ -149,6 +294,9 @@ StringInputVisitor *string_input_visitor_new(const char *str) v->visitor.type_str = parse_type_str; v->visitor.type_number = parse_type_number; v->visitor.type_size = parse_type_size; + 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; diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index 5989f81..3b47ddf 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -64,6 +64,26 @@ 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}; + int16List *res = NULL; + Error *errp = NULL; + Visitor *v; + int i = 0; + + v = visitor_input_test_init(data, "-2-4"); + + visit_type_int16List(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + while (res && i < sizeof(value) / sizeof(value[0])) { + printf("%d\n", res->value); + g_assert_cmpint(res->value, ==, value[i++]); + res = res->next; + } +} + static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { @@ -228,6 +248,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",