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