kvargs: support multiple lists
This patch updates kvargs parser to support value of multiple lists or ranges: k1=v[1,2]v[3-5] Signed-off-by: Xueming Li <xuemingl@nvidia.com> Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com> Acked-by: Thomas Monjalon <thomas@monjalon.net>
This commit is contained in:
parent
fa4f3fecb9
commit
9be46b4308
@ -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 };
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rte_string_fns.h>
|
||||
|
||||
@ -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) {
|
||||
|
||||
i = kvlist->count;
|
||||
if (i >= RTE_KVARGS_MAX)
|
||||
return -1;
|
||||
|
||||
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)
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
kvlist->count++;
|
||||
str = NULL;
|
||||
if (!save) {
|
||||
/* Continue if not end of key or value. */
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kvlist->count >= RTE_KVARGS_MAX)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (*str == '\0') /* End of string. */
|
||||
break;
|
||||
*str = '\0';
|
||||
str++;
|
||||
start = str;
|
||||
save = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user