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 : 100 : 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 : 100 : kvlist->str = strdup(params);
35 [ + - ]: 100 : 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 [ + + + + : 1447 : switch (*str) {
+ + ]
43 : 87 : case '=': /* End of key. */
44 : : end_key = true;
45 : : save = true;
46 : 87 : break;
47 : 38 : case ',':
48 : : /* End of value, skip comma in middle of range */
49 [ + + ]: 38 : if (!in_list) {
50 [ + + ]: 36 : 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 : 100 : case '\0': /* End of string */
66 [ + + ]: 100 : 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 [ + + ]: 1447 : if (!save) {
78 : : /* Continue if not end of key or value. */
79 : 1224 : str++;
80 : 1224 : continue;
81 : : }
82 : :
83 [ + - ]: 223 : if (kvlist->count >= RTE_KVARGS_MAX)
84 : : return -1;
85 : :
86 [ + + ]: 223 : if (end_value)
87 : : /* Value parsed */
88 : 87 : kvlist->pairs[kvlist->count].value = start;
89 [ + - ]: 136 : else if (end_key)
90 : : /* Key parsed. */
91 : 136 : kvlist->pairs[kvlist->count].key = start;
92 : :
93 [ + + ]: 223 : if (end_pair) {
94 [ + + ]: 136 : if (end_value || str != start)
95 : : /* Ignore empty pair. */
96 : 120 : kvlist->count++;
97 : : end_key = false;
98 : : end_value = false;
99 : : end_pair = false;
100 : : }
101 : :
102 [ + + ]: 223 : if (*str == '\0') /* End of string. */
103 : : break;
104 : 123 : *str = '\0';
105 : 123 : 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 [ + + ]: 40 : for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) {
123 [ + + ]: 38 : 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 : 28 : 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 [ + + ]: 48 : for (i = 0; i < kvlist->count; i++) {
141 : : pair = &kvlist->pairs[i];
142 : 22 : ret = is_valid_key(valid, pair->key);
143 [ + + ]: 22 : 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 : 20 : 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 [ + + ]: 51 : for (i = 0; i < kvlist->count; i++) {
162 : : pair = &kvlist->pairs[i];
163 [ + + + + ]: 31 : if (key_match == NULL || strcmp(pair->key, key_match) == 0)
164 : 22 : ret++;
165 : : }
166 : :
167 : 20 : return ret;
168 : : }
169 : :
170 : : /*
171 : : * For each matching key, call the given handler function.
172 : : */
173 : : int
174 : 32 : rte_kvargs_process(const struct rte_kvargs *kvlist,
175 : : const char *key_match,
176 : : arg_handler_t handler,
177 : : void *opaque_arg)
178 : : {
179 : : const struct rte_kvargs_pair *pair;
180 : : unsigned i;
181 : :
182 [ + - ]: 32 : if (kvlist == NULL)
183 : : return 0;
184 : :
185 [ + + ]: 52 : for (i = 0; i < kvlist->count; i++) {
186 : : pair = &kvlist->pairs[i];
187 [ + - + + ]: 21 : if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
188 [ + + ]: 16 : if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
189 : : return -1;
190 : : }
191 : : }
192 : : return 0;
193 : : }
194 : :
195 : : /* free the rte_kvargs structure */
196 : : void
197 : 348 : rte_kvargs_free(struct rte_kvargs *kvlist)
198 : : {
199 [ + + ]: 348 : if (!kvlist)
200 : : return;
201 : :
202 : 100 : free(kvlist->str);
203 : 100 : free(kvlist);
204 : : }
205 : :
206 : : /* Lookup a value in an rte_kvargs list by its key and value. */
207 : : const char *
208 : 14 : rte_kvargs_get_with_value(const struct rte_kvargs *kvlist, const char *key,
209 : : const char *value)
210 : : {
211 : : unsigned int i;
212 : :
213 [ + - ]: 14 : if (kvlist == NULL)
214 : : return NULL;
215 [ + + ]: 20 : for (i = 0; i < kvlist->count; ++i) {
216 [ + - + + ]: 15 : if (key != NULL && strcmp(kvlist->pairs[i].key, key) != 0)
217 : 6 : continue;
218 [ - + - - ]: 9 : if (value != NULL && strcmp(kvlist->pairs[i].value, value) != 0)
219 : 0 : continue;
220 : 9 : return kvlist->pairs[i].value;
221 : : }
222 : : return NULL;
223 : : }
224 : :
225 : : /* Lookup a value in an rte_kvargs list by its key. */
226 : : const char *
227 : 14 : rte_kvargs_get(const struct rte_kvargs *kvlist, const char *key)
228 : : {
229 [ + - ]: 14 : if (kvlist == NULL || key == NULL)
230 : : return NULL;
231 : 14 : return rte_kvargs_get_with_value(kvlist, key, NULL);
232 : : }
233 : :
234 : : /*
235 : : * Parse the arguments "key=value,key=value,..." string and return
236 : : * an allocated structure that contains a key/value list. Also
237 : : * check if only valid keys were used.
238 : : */
239 : : struct rte_kvargs *
240 : 100 : rte_kvargs_parse(const char *args, const char * const valid_keys[])
241 : : {
242 : : struct rte_kvargs *kvlist;
243 : :
244 : 100 : kvlist = malloc(sizeof(*kvlist));
245 [ + - ]: 100 : if (kvlist == NULL)
246 : : return NULL;
247 : : memset(kvlist, 0, sizeof(*kvlist));
248 : :
249 [ - + ]: 100 : if (rte_kvargs_tokenize(kvlist, args) < 0) {
250 : 0 : rte_kvargs_free(kvlist);
251 : 0 : return NULL;
252 : : }
253 : :
254 [ + + + + ]: 100 : if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) {
255 : 2 : rte_kvargs_free(kvlist);
256 : 2 : return NULL;
257 : : }
258 : :
259 : : return kvlist;
260 : : }
261 : :
262 : : struct rte_kvargs *
263 : 0 : rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
264 : : const char *valid_ends)
265 : : {
266 : : struct rte_kvargs *kvlist = NULL;
267 : : char *copy;
268 : : size_t len;
269 : :
270 [ # # ]: 0 : if (valid_ends == NULL)
271 : 0 : return rte_kvargs_parse(args, valid_keys);
272 : :
273 : 0 : copy = strdup(args);
274 [ # # ]: 0 : if (copy == NULL)
275 : : return NULL;
276 : :
277 : 0 : len = strcspn(copy, valid_ends);
278 : 0 : copy[len] = '\0';
279 : :
280 : 0 : kvlist = rte_kvargs_parse(copy, valid_keys);
281 : :
282 : 0 : free(copy);
283 : 0 : return kvlist;
284 : : }
|