doc: add Meson coding style to contributors guide
[dpdk.git] / lib / librte_kvargs / rte_kvargs.c
index 747f149..38e9d5c 100644 (file)
@@ -5,7 +5,9 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
+#include <rte_os_shim.h>
 #include <rte_string_fns.h>
 
 #include "rte_kvargs.h"
 /*
  * 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,20 +38,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;
 
-               kvlist->count++;
-               str = NULL;
+               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;
@@ -120,6 +180,9 @@ rte_kvargs_process(const struct rte_kvargs *kvlist,
        const struct rte_kvargs_pair *pair;
        unsigned i;
 
+       if (kvlist == NULL)
+               return 0;
+
        for (i = 0; i < kvlist->count; i++) {
                pair = &kvlist->pairs[i];
                if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
@@ -141,6 +204,21 @@ rte_kvargs_free(struct rte_kvargs *kvlist)
        free(kvlist);
 }
 
+/* Lookup a value in an rte_kvargs list by its key. */
+const char *
+rte_kvargs_get(const struct rte_kvargs *kvlist, const char *key)
+{
+       unsigned int i;
+
+       if (kvlist == NULL || key == NULL)
+               return NULL;
+       for (i = 0; i < kvlist->count; ++i) {
+               if (strcmp(kvlist->pairs[i].key, key) == 0)
+                       return kvlist->pairs[i].value;
+       }
+       return NULL;
+}
+
 /*
  * Parse the arguments "key=value,key=value,..." string and return
  * an allocated structure that contains a key/value list. Also
@@ -168,3 +246,36 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
        return kvlist;
 }
+
+struct rte_kvargs *
+rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
+                      const char *valid_ends)
+{
+       struct rte_kvargs *kvlist = NULL;
+       char *copy;
+       size_t len;
+
+       if (valid_ends == NULL)
+               return rte_kvargs_parse(args, valid_keys);
+
+       copy = strdup(args);
+       if (copy == NULL)
+               return NULL;
+
+       len = strcspn(copy, valid_ends);
+       copy[len] = '\0';
+
+       kvlist = rte_kvargs_parse(copy, valid_keys);
+
+       free(copy);
+       return kvlist;
+}
+
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+                 const char *value, void *opaque)
+{
+       const char *str = opaque;
+
+       return -abs(strcmp(str, value));
+}