Branch data Line data Source code
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 : : #include <stdbool.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_os_shim.h>
12 : :
13 : : #include "rte_kvargs.h"
14 : :
15 : : /*
16 : : * Receive a string with a list of arguments following the pattern
17 : : * key=value,key=value,... and insert them into the list.
18 : : * Params string will be copied to be modified.
19 : : * list "[]" and list element splitter ",", "-" is treated as value.
20 : : * Supported examples:
21 : : * k1=v1,k2=v2
22 : : * k1
23 : : * k1=x[0-1]y[1,3-5,9]z
24 : : */
25 : : static int
26 : 111 : rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
27 : : {
28 : : char *str, *start;
29 : : bool in_list = false, end_key = false, end_value = false;
30 : : bool save = false, end_pair = false;
31 : :
32 : : /* Copy the const char *params to a modifiable string
33 : : * to pass to rte_strsplit
34 : : */
35 : 111 : kvlist->str = strdup(params);
36 [ + - ]: 111 : if (kvlist->str == NULL)
37 : : return -1;
38 : :
39 : : /* browse each key/value pair and add it in kvlist */
40 : : str = kvlist->str;
41 : : start = str; /* start of current key or value */
42 : : while (1) {
43 [ + + + + : 1679 : switch (*str) {
+ + ]
44 : 102 : case '=': /* End of key. */
45 : : end_key = true;
46 : : save = true;
47 : 102 : break;
48 : 53 : case ',':
49 : : /* End of value, skip comma in middle of range */
50 [ + + ]: 53 : if (!in_list) {
51 [ + + ]: 51 : if (end_key)
52 : : end_value = true;
53 : : else
54 : : end_key = true;
55 : : save = true;
56 : : end_pair = true;
57 : : }
58 : : break;
59 : 3 : case '[': /* Start of list. */
60 : : in_list = true;
61 : 3 : break;
62 : 1 : case ']': /* End of list. */
63 : : if (in_list)
64 : : in_list = false;
65 : : break;
66 : 111 : case '\0': /* End of string */
67 [ + + ]: 111 : if (end_key)
68 : : end_value = true;
69 : : else
70 : : end_key = true;
71 : : save = true;
72 : : end_pair = true;
73 : : break;
74 : : default:
75 : : break;
76 : : }
77 : :
78 [ + + ]: 1679 : if (!save) {
79 : : /* Continue if not end of key or value. */
80 : 1415 : str++;
81 : 1415 : continue;
82 : : }
83 : :
84 [ + - ]: 264 : if (kvlist->count >= RTE_KVARGS_MAX)
85 : : return -1;
86 : :
87 [ + + ]: 264 : if (end_value)
88 : : /* Value parsed */
89 : 102 : kvlist->pairs[kvlist->count].value = start;
90 [ + - ]: 162 : else if (end_key)
91 : : /* Key parsed. */
92 : 162 : kvlist->pairs[kvlist->count].key = start;
93 : :
94 [ + + ]: 264 : if (end_pair) {
95 [ + + ]: 162 : if (end_value || str != start)
96 : : /* Ignore empty pair. */
97 : 141 : kvlist->count++;
98 : : end_key = false;
99 : : end_value = false;
100 : : end_pair = false;
101 : : }
102 : :
103 [ + + ]: 264 : if (*str == '\0') /* End of string. */
104 : : break;
105 : 153 : *str = '\0';
106 : 153 : str++;
107 : : start = str;
108 : : save = false;
109 : : }
110 : :
111 : : return 0;
112 : : }
113 : :
114 : : /*
115 : : * Determine whether a key is valid or not by looking
116 : : * into a list of valid keys.
117 : : */
118 : : static int
119 : : is_valid_key(const char * const valid[], const char *key_match)
120 : : {
121 : : const char * const *valid_ptr;
122 : :
123 [ + + ]: 47 : for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) {
124 [ + + ]: 45 : if (strcmp(key_match, *valid_ptr) == 0)
125 : : return 1;
126 : : }
127 : : return 0;
128 : : }
129 : :
130 : : /*
131 : : * Determine whether all keys are valid or not by looking
132 : : * into a list of valid keys.
133 : : */
134 : : static int
135 : 32 : check_for_valid_keys(struct rte_kvargs *kvlist,
136 : : const char * const valid[])
137 : : {
138 : : unsigned i, ret;
139 : : struct rte_kvargs_pair *pair;
140 : :
141 [ + + ]: 56 : for (i = 0; i < kvlist->count; i++) {
142 : : pair = &kvlist->pairs[i];
143 : 26 : ret = is_valid_key(valid, pair->key);
144 [ + + ]: 26 : if (!ret)
145 : : return -1;
146 : : }
147 : : return 0;
148 : : }
149 : :
150 : : /*
151 : : * Return the number of times a given arg_name exists in the key/value list.
152 : : * E.g. given a list = { rx = 0, rx = 1, tx = 2 } the number of args for
153 : : * arg "rx" will be 2.
154 : : */
155 : : RTE_EXPORT_SYMBOL(rte_kvargs_count)
156 : : unsigned
157 : 31 : rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match)
158 : : {
159 : : const struct rte_kvargs_pair *pair;
160 : : unsigned i, ret;
161 : :
162 : : ret = 0;
163 [ + + ]: 86 : for (i = 0; i < kvlist->count; i++) {
164 : : pair = &kvlist->pairs[i];
165 [ + + + + ]: 55 : if (key_match == NULL || strcmp(pair->key, key_match) == 0)
166 : 40 : ret++;
167 : : }
168 : :
169 : 31 : return ret;
170 : : }
171 : :
172 : : static int
173 : 46 : kvargs_process_common(const struct rte_kvargs *kvlist, const char *key_match,
174 : : arg_handler_t handler, void *opaque_arg, bool support_only_key)
175 : : {
176 : : const struct rte_kvargs_pair *pair;
177 : : unsigned i;
178 : :
179 [ + - ]: 46 : if (kvlist == NULL)
180 : : return -1;
181 : :
182 [ + + ]: 78 : for (i = 0; i < kvlist->count; i++) {
183 : : pair = &kvlist->pairs[i];
184 [ + - + + ]: 35 : if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
185 [ + + + + ]: 23 : if (!support_only_key && pair->value == NULL)
186 : : return -1;
187 [ + + ]: 22 : if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
188 : : return -1;
189 : : }
190 : : }
191 : :
192 : : return 0;
193 : : }
194 : :
195 : : /*
196 : : * For each matching key in key=value, call the given handler function.
197 : : */
198 : : RTE_EXPORT_SYMBOL(rte_kvargs_process)
199 : : int
200 : 42 : rte_kvargs_process(const struct rte_kvargs *kvlist, const char *key_match, arg_handler_t handler,
201 : : void *opaque_arg)
202 : : {
203 : 42 : return kvargs_process_common(kvlist, key_match, handler, opaque_arg, false);
204 : : }
205 : :
206 : : /*
207 : : * For each matching key in key=value or only-key, call the given handler function.
208 : : */
209 : : RTE_EXPORT_SYMBOL(rte_kvargs_process_opt)
210 : : int
211 : 4 : rte_kvargs_process_opt(const struct rte_kvargs *kvlist, const char *key_match,
212 : : arg_handler_t handler, void *opaque_arg)
213 : : {
214 : 4 : return kvargs_process_common(kvlist, key_match, handler, opaque_arg, true);
215 : : }
216 : :
217 : : /* free the rte_kvargs structure */
218 : : RTE_EXPORT_SYMBOL(rte_kvargs_free)
219 : : void
220 : 381 : rte_kvargs_free(struct rte_kvargs *kvlist)
221 : : {
222 [ + + ]: 381 : if (!kvlist)
223 : : return;
224 : :
225 : 111 : free(kvlist->str);
226 : 111 : free(kvlist);
227 : : }
228 : :
229 : : /* Lookup a value in an rte_kvargs list by its key and value. */
230 : : RTE_EXPORT_SYMBOL(rte_kvargs_get_with_value)
231 : : const char *
232 : 14 : rte_kvargs_get_with_value(const struct rte_kvargs *kvlist, const char *key,
233 : : const char *value)
234 : : {
235 : : unsigned int i;
236 : :
237 [ + - ]: 14 : if (kvlist == NULL)
238 : : return NULL;
239 [ + + ]: 20 : for (i = 0; i < kvlist->count; ++i) {
240 [ + - + + ]: 15 : if (key != NULL && strcmp(kvlist->pairs[i].key, key) != 0)
241 : 6 : continue;
242 [ - + - - ]: 9 : if (value != NULL && strcmp(kvlist->pairs[i].value, value) != 0)
243 : 0 : continue;
244 : 9 : return kvlist->pairs[i].value;
245 : : }
246 : : return NULL;
247 : : }
248 : :
249 : : /* Lookup a value in an rte_kvargs list by its key. */
250 : : RTE_EXPORT_SYMBOL(rte_kvargs_get)
251 : : const char *
252 : 14 : rte_kvargs_get(const struct rte_kvargs *kvlist, const char *key)
253 : : {
254 [ + - ]: 14 : if (kvlist == NULL || key == NULL)
255 : : return NULL;
256 : 14 : return rte_kvargs_get_with_value(kvlist, key, NULL);
257 : : }
258 : :
259 : : /*
260 : : * Parse the arguments "key=value,key=value,..." string and return
261 : : * an allocated structure that contains a key/value list. Also
262 : : * check if only valid keys were used.
263 : : */
264 : : RTE_EXPORT_SYMBOL(rte_kvargs_parse)
265 : : struct rte_kvargs *
266 : 111 : rte_kvargs_parse(const char *args, const char * const valid_keys[])
267 : : {
268 : : struct rte_kvargs *kvlist;
269 : :
270 : 111 : kvlist = malloc(sizeof(*kvlist));
271 [ + - ]: 111 : if (kvlist == NULL)
272 : : return NULL;
273 : : memset(kvlist, 0, sizeof(*kvlist));
274 : :
275 [ - + ]: 111 : if (rte_kvargs_tokenize(kvlist, args) < 0) {
276 : 0 : rte_kvargs_free(kvlist);
277 : 0 : return NULL;
278 : : }
279 : :
280 [ + + + + ]: 111 : if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) {
281 : 2 : rte_kvargs_free(kvlist);
282 : 2 : return NULL;
283 : : }
284 : :
285 : : return kvlist;
286 : : }
287 : :
288 : : RTE_EXPORT_SYMBOL(rte_kvargs_parse_delim)
289 : : struct rte_kvargs *
290 : 0 : rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
291 : : const char *valid_ends)
292 : : {
293 : : struct rte_kvargs *kvlist = NULL;
294 : : char *copy;
295 : : size_t len;
296 : :
297 [ # # ]: 0 : if (valid_ends == NULL)
298 : 0 : return rte_kvargs_parse(args, valid_keys);
299 : :
300 : 0 : copy = strdup(args);
301 [ # # ]: 0 : if (copy == NULL)
302 : : return NULL;
303 : :
304 : 0 : len = strcspn(copy, valid_ends);
305 : 0 : copy[len] = '\0';
306 : :
307 : 0 : kvlist = rte_kvargs_parse(copy, valid_keys);
308 : :
309 : 0 : free(copy);
310 : 0 : return kvlist;
311 : : }
|