From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B505FA0561; Thu, 4 Mar 2021 15:32:09 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2147822A318; Thu, 4 Mar 2021 15:31:24 +0100 (CET) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by mails.dpdk.org (Postfix) with ESMTP id 4416D22A2F7 for ; Thu, 4 Mar 2021 15:31:21 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from xuemingl@nvidia.com) with SMTP; 4 Mar 2021 16:31:18 +0200 Received: from nvidia.com (pegasus05.mtr.labs.mlnx [10.210.16.100]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 124EUkoX027668; Thu, 4 Mar 2021 16:31:18 +0200 From: Xueming Li To: Andrew Rybchenko Cc: dev@dpdk.org, Viacheslav Ovsiienko , xuemingl@nvidia.com, Asaf Penso , Olivier Matz Date: Thu, 4 Mar 2021 14:30:25 +0000 Message-Id: <1614868228-13685-10-git-send-email-xuemingl@nvidia.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1614868228-13685-1-git-send-email-xuemingl@nvidia.com> References: <1614868228-13685-1-git-send-email-xuemingl@nvidia.com> In-Reply-To: <1608303356-13089-2-git-send-email-xuemingl@nvidia.com> References: <1608303356-13089-2-git-send-email-xuemingl@nvidia.com> Subject: [dpdk-dev] [PATCH v8 9/9] kvargs: update parser to support lists X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch updates kvargs parser to support lists on top of range, allow multiple lists or range: k1=a[1,2]b[3-5] Signed-off-by: Xueming Li Acked-by: Viacheslav Ovsiienko Acked-by: Thomas Monjalon --- app/test/test_kvargs.c | 46 +++++++++++++-- lib/librte_kvargs/rte_kvargs.c | 101 +++++++++++++++++++++++---------- 2 files changed, 112 insertions(+), 35 deletions(-) diff --git a/app/test/test_kvargs.c b/app/test/test_kvargs.c index 2a2dae43a0..a91ea8dc47 100644 --- a/app/test/test_kvargs.c +++ b/app/test/test_kvargs.c @@ -35,6 +35,25 @@ static int check_handler(const char *key, const char *value, return 0; } +/* test parsing. */ +static int test_kvargs_parsing(const char *args, unsigned int n) +{ + struct rte_kvargs *kvlist; + + kvlist = rte_kvargs_parse(args, NULL); + if (kvlist == NULL) { + printf("rte_kvargs_parse() error: %s\n", args); + return -1; + } + if (kvlist->count != n) { + printf("invalid count value %d: %s\n", kvlist->count, args); + rte_kvargs_free(kvlist); + return -1; + } + rte_kvargs_free(kvlist); + return 0; +} + /* test a valid case */ static int test_valid_kvargs(void) { @@ -42,6 +61,19 @@ static int test_valid_kvargs(void) const char *args; const char *valid_keys_list[] = { "foo", "check", NULL }; const char **valid_keys; + static const struct { + unsigned int expected; + const char *input; + } valid_inputs[] = { + { 2, "foo=1,foo=" }, + { 2, "foo=1,foo=" }, + { 2, "foo=1,foo" }, + { 2, "foo=1,=2" }, + { 1, "foo=[1,2" }, + { 1, ",=" }, + { 1, "foo=[" }, + }; + unsigned int i; /* empty args is valid */ args = ""; @@ -191,6 +223,14 @@ static int test_valid_kvargs(void) } rte_kvargs_free(kvlist); + valid_keys = NULL; + + for (i = 0; i < RTE_DIM(valid_inputs); ++i) { + args = valid_inputs[i].input; + if (test_kvargs_parsing(args, valid_inputs[i].expected)) + goto fail; + } + return 0; fail: @@ -212,12 +252,6 @@ static int test_invalid_kvargs(void) /* list of argument that should fail */ const char *args_list[] = { "wrong-key=x", /* key not in valid_keys_list */ - "foo=1,foo=", /* empty value */ - "foo=1,foo", /* no value */ - "foo=1,=2", /* no key */ - "foo=[1,2", /* no closing bracket in value */ - ",=", /* also test with a smiley */ - "foo=[", /* no value in list and no closing bracket */ NULL }; const char **args; const char *valid_keys_list[] = { "foo", "check", NULL }; diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c index 285081c86c..ffae8914cf 100644 --- a/lib/librte_kvargs/rte_kvargs.c +++ b/lib/librte_kvargs/rte_kvargs.c @@ -5,6 +5,7 @@ #include #include +#include #include @@ -13,15 +14,19 @@ /* * Receive a string with a list of arguments following the pattern * key=value,key=value,... and insert them into the list. - * strtok() is used so the params string will be copied to be modified. + * Params string will be copied to be modified. + * list "[]" and list element splitter ",", "-" is treated as value. + * Supported examples: + * k1=v1,k2=v2 + * k1 + * k1=x[0-1]y[1,3-5,9]z */ static int rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params) { - unsigned i; - char *str; - char *ctx1 = NULL; - char *ctx2 = NULL; + char *str, *start; + bool in_list = false, end_key = false, end_value = false; + bool save = false, end_pair = false; /* Copy the const char *params to a modifiable string * to pass to rte_strsplit @@ -32,36 +37,74 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params) /* browse each key/value pair and add it in kvlist */ str = kvlist->str; - while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) { + start = str; /* start of current key or value */ + while (1) { + switch (*str) { + case '=': /* End of key. */ + end_key = true; + save = true; + break; + case ',': + /* End of value, skip comma in middle of range */ + if (!in_list) { + if (end_key) + end_value = true; + else + end_key = true; + save = true; + end_pair = true; + } + break; + case '[': /* Start of list. */ + in_list = true; + break; + case ']': /* End of list. */ + if (in_list) + in_list = false; + break; + case '\0': /* End of string */ + if (end_key) + end_value = true; + else + end_key = true; + save = true; + end_pair = true; + break; + default: + break; + } - i = kvlist->count; - if (i >= RTE_KVARGS_MAX) - return -1; + if (!save) { + /* Continue if not end of key or value. */ + str++; + continue; + } - kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2); - kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2); - if (kvlist->pairs[i].key == NULL || - kvlist->pairs[i].value == NULL) + if (kvlist->count >= RTE_KVARGS_MAX) return -1; - /* Detect list [a,b] to skip comma delimiter in list. */ - str = kvlist->pairs[i].value; - if (str[0] == '[') { - /* Find the end of the list. */ - while (str[strlen(str) - 1] != ']') { - /* Restore the comma erased by strtok_r(). */ - if (ctx1 == NULL || ctx1[0] == '\0') - return -1; /* no closing bracket */ - str[strlen(str)] = ','; - /* Parse until next comma. */ - str = strtok_r(NULL, RTE_KVARGS_PAIRS_DELIM, &ctx1); - if (str == NULL) - return -1; /* no closing bracket */ - } + if (end_value) + /* Value parsed */ + kvlist->pairs[kvlist->count].value = start; + else if (end_key) + /* Key parsed. */ + kvlist->pairs[kvlist->count].key = start; + + if (end_pair) { + if (end_value || str != start) + /* Ignore empty pair. */ + kvlist->count++; + end_key = false; + end_value = false; + end_pair = false; } - kvlist->count++; - str = NULL; + if (*str == '\0') /* End of string. */ + break; + *str = '\0'; + str++; + start = str; + save = false; } return 0; -- 2.25.1