New upstream version 18.11-rc1
[deb_dpdk.git] / lib / librte_kvargs / rte_kvargs.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2013 Intel Corporation.
3  * Copyright(c) 2014 6WIND S.A.
4  */
5
6 #include <string.h>
7 #include <stdlib.h>
8
9 #include <rte_string_fns.h>
10
11 #include "rte_kvargs.h"
12
13 /*
14  * Receive a string with a list of arguments following the pattern
15  * key=value,key=value,... and insert them into the list.
16  * strtok() is used so the params string will be copied to be modified.
17  */
18 static int
19 rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
20 {
21         unsigned i;
22         char *str;
23         char *ctx1 = NULL;
24         char *ctx2 = NULL;
25
26         /* Copy the const char *params to a modifiable string
27          * to pass to rte_strsplit
28          */
29         kvlist->str = strdup(params);
30         if (kvlist->str == NULL)
31                 return -1;
32
33         /* browse each key/value pair and add it in kvlist */
34         str = kvlist->str;
35         while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) {
36
37                 i = kvlist->count;
38                 if (i >= RTE_KVARGS_MAX)
39                         return -1;
40
41                 kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2);
42                 kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2);
43                 if (kvlist->pairs[i].key == NULL ||
44                     kvlist->pairs[i].value == NULL)
45                         return -1;
46
47                 /* Detect list [a,b] to skip comma delimiter in list. */
48                 str = kvlist->pairs[i].value;
49                 if (str[0] == '[') {
50                         /* Find the end of the list. */
51                         while (str[strlen(str) - 1] != ']') {
52                                 /* Restore the comma erased by strtok_r(). */
53                                 str[strlen(str)] = ',';
54                                 /* Parse until next comma. */
55                                 str = strtok_r(NULL, RTE_KVARGS_PAIRS_DELIM, &ctx1);
56                                 if (str == NULL)
57                                         return -1; /* no closing bracket */
58                         }
59                 }
60
61                 kvlist->count++;
62                 str = NULL;
63         }
64
65         return 0;
66 }
67
68 /*
69  * Determine whether a key is valid or not by looking
70  * into a list of valid keys.
71  */
72 static int
73 is_valid_key(const char * const valid[], const char *key_match)
74 {
75         const char * const *valid_ptr;
76
77         for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) {
78                 if (strcmp(key_match, *valid_ptr) == 0)
79                         return 1;
80         }
81         return 0;
82 }
83
84 /*
85  * Determine whether all keys are valid or not by looking
86  * into a list of valid keys.
87  */
88 static int
89 check_for_valid_keys(struct rte_kvargs *kvlist,
90                 const char * const valid[])
91 {
92         unsigned i, ret;
93         struct rte_kvargs_pair *pair;
94
95         for (i = 0; i < kvlist->count; i++) {
96                 pair = &kvlist->pairs[i];
97                 ret = is_valid_key(valid, pair->key);
98                 if (!ret)
99                         return -1;
100         }
101         return 0;
102 }
103
104 /*
105  * Return the number of times a given arg_name exists in the key/value list.
106  * E.g. given a list = { rx = 0, rx = 1, tx = 2 } the number of args for
107  * arg "rx" will be 2.
108  */
109 unsigned
110 rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match)
111 {
112         const struct rte_kvargs_pair *pair;
113         unsigned i, ret;
114
115         ret = 0;
116         for (i = 0; i < kvlist->count; i++) {
117                 pair = &kvlist->pairs[i];
118                 if (key_match == NULL || strcmp(pair->key, key_match) == 0)
119                         ret++;
120         }
121
122         return ret;
123 }
124
125 /*
126  * For each matching key, call the given handler function.
127  */
128 int
129 rte_kvargs_process(const struct rte_kvargs *kvlist,
130                 const char *key_match,
131                 arg_handler_t handler,
132                 void *opaque_arg)
133 {
134         const struct rte_kvargs_pair *pair;
135         unsigned i;
136
137         if (kvlist == NULL)
138                 return 0;
139
140         for (i = 0; i < kvlist->count; i++) {
141                 pair = &kvlist->pairs[i];
142                 if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
143                         if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
144                                 return -1;
145                 }
146         }
147         return 0;
148 }
149
150 /* free the rte_kvargs structure */
151 void
152 rte_kvargs_free(struct rte_kvargs *kvlist)
153 {
154         if (!kvlist)
155                 return;
156
157         free(kvlist->str);
158         free(kvlist);
159 }
160
161 /*
162  * Parse the arguments "key=value,key=value,..." string and return
163  * an allocated structure that contains a key/value list. Also
164  * check if only valid keys were used.
165  */
166 struct rte_kvargs *
167 rte_kvargs_parse(const char *args, const char * const valid_keys[])
168 {
169         struct rte_kvargs *kvlist;
170
171         kvlist = malloc(sizeof(*kvlist));
172         if (kvlist == NULL)
173                 return NULL;
174         memset(kvlist, 0, sizeof(*kvlist));
175
176         if (rte_kvargs_tokenize(kvlist, args) < 0) {
177                 rte_kvargs_free(kvlist);
178                 return NULL;
179         }
180
181         if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) {
182                 rte_kvargs_free(kvlist);
183                 return NULL;
184         }
185
186         return kvlist;
187 }
188
189 __rte_experimental
190 struct rte_kvargs *
191 rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
192                        const char *valid_ends)
193 {
194         struct rte_kvargs *kvlist = NULL;
195         char *copy;
196         size_t len;
197
198         if (valid_ends == NULL)
199                 return rte_kvargs_parse(args, valid_keys);
200
201         copy = strdup(args);
202         if (copy == NULL)
203                 return NULL;
204
205         len = strcspn(copy, valid_ends);
206         copy[len] = '\0';
207
208         kvlist = rte_kvargs_parse(copy, valid_keys);
209
210         free(copy);
211         return kvlist;
212 }
213
214 __rte_experimental
215 int
216 rte_kvargs_strcmp(const char *key __rte_unused,
217                   const char *value, void *opaque)
218 {
219         const char *str = opaque;
220
221         return -abs(strcmp(str, value));
222 }