[RFC,5/7] kvargs: update parser for new representor syntax
Checks
Commit Message
This patch updates kvargs parser to allow comma in list value:
k1=a[1,2]b[3-5]
Signed-off-by: Xueming Li <xuemingl@nvidia.com>
---
lib/librte_kvargs/rte_kvargs.c | 82 +++++++++++++++++++++++-----------
1 file changed, 56 insertions(+), 26 deletions(-)
Comments
On 12/18/20 5:55 PM, Xueming Li wrote:
> This patch updates kvargs parser to allow comma in list value:
> k1=a[1,2]b[3-5]
>
> Signed-off-by: Xueming Li <xuemingl@nvidia.com>
> ---
> lib/librte_kvargs/rte_kvargs.c | 82 +++++++++++++++++++++++-----------
> 1 file changed, 56 insertions(+), 26 deletions(-)
>
> diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
> index 285081c86c..6193109a17 100644
> --- a/lib/librte_kvargs/rte_kvargs.c
> +++ b/lib/librte_kvargs/rte_kvargs.c
> @@ -13,15 +13,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
> + * v1
> + * 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;
> + int in_list = 0, end_k = 0, end_v = 0;
>
> /* Copy the const char *params to a modifiable string
> * to pass to rte_strsplit
> @@ -32,36 +36,62 @@ 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_k = 1;
> + break;
> + case ',':
> + /* End of value, skip comma in middle of range */
> + if (!in_list)
> + end_v = 1;
> + break;
> + case '[': /* Start of list. */
> + in_list++;
> + break;
> + case ']': /* End of list. */
> + if (in_list)
> + in_list--;
> + break;
> + case 0: /* End of string */
> + end_v = 1;
> + break;
> + default:
> + break;
> + }
> +
> + if (!end_k && !end_v) {
DPDK coding style requires to compare integers vs 0 explicitly.
Otherwise you can define it as bool and use as bool this way.
> + /* Continue if not end of key or value. */
> + str++;
> + continue;
> + }
>
> 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 */
> + if (start == str) /* Empty key or value. */
> + start = NULL;
> +
> + if (end_k) {
same
> + /* Key parsed. */
> + kvlist->pairs[i].key = start;
> + end_k = 0;
> + } else if (end_v) {
same
> + /* Allow single key or single value. */
> + if (kvlist->pairs[i].key || start) {
> + kvlist->pairs[i].value = start;
> + kvlist->count++;
> }
> + end_v = 0;
> }
>
> - kvlist->count++;
> - str = NULL;
> + if (!*str) /* End of string. */
Compare with '\0'.
> + break;
> + *str = 0;
> + str++;
> + start = str;
> }
>
> return 0;
@@ -13,15 +13,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
+ * v1
+ * 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;
+ int in_list = 0, end_k = 0, end_v = 0;
/* Copy the const char *params to a modifiable string
* to pass to rte_strsplit
@@ -32,36 +36,62 @@ 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_k = 1;
+ break;
+ case ',':
+ /* End of value, skip comma in middle of range */
+ if (!in_list)
+ end_v = 1;
+ break;
+ case '[': /* Start of list. */
+ in_list++;
+ break;
+ case ']': /* End of list. */
+ if (in_list)
+ in_list--;
+ break;
+ case 0: /* End of string */
+ end_v = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (!end_k && !end_v) {
+ /* Continue if not end of key or value. */
+ str++;
+ continue;
+ }
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 */
+ if (start == str) /* Empty key or value. */
+ start = NULL;
+
+ if (end_k) {
+ /* Key parsed. */
+ kvlist->pairs[i].key = start;
+ end_k = 0;
+ } else if (end_v) {
+ /* Allow single key or single value. */
+ if (kvlist->pairs[i].key || start) {
+ kvlist->pairs[i].value = start;
+ kvlist->count++;
}
+ end_v = 0;
}
- kvlist->count++;
- str = NULL;
+ if (!*str) /* End of string. */
+ break;
+ *str = 0;
+ str++;
+ start = str;
}
return 0;