xref: /dpdk/lib/kvargs/rte_kvargs.c (revision de89988365a7ca4087dd451c675320c993910332)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2013 Intel Corporation.
399a2dd95SBruce Richardson  * Copyright(c) 2014 6WIND S.A.
499a2dd95SBruce Richardson  */
599a2dd95SBruce Richardson 
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson #include <stdlib.h>
899a2dd95SBruce Richardson #include <stdbool.h>
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #include <rte_os_shim.h>
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson #include "rte_kvargs.h"
1399a2dd95SBruce Richardson 
1499a2dd95SBruce Richardson /*
1599a2dd95SBruce Richardson  * Receive a string with a list of arguments following the pattern
1699a2dd95SBruce Richardson  * key=value,key=value,... and insert them into the list.
1799a2dd95SBruce Richardson  * Params string will be copied to be modified.
1899a2dd95SBruce Richardson  * list "[]" and list element splitter ",", "-" is treated as value.
1999a2dd95SBruce Richardson  * Supported examples:
2099a2dd95SBruce Richardson  *   k1=v1,k2=v2
2199a2dd95SBruce Richardson  *   k1
2299a2dd95SBruce Richardson  *   k1=x[0-1]y[1,3-5,9]z
2399a2dd95SBruce Richardson  */
2499a2dd95SBruce Richardson static int
2599a2dd95SBruce Richardson rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
2699a2dd95SBruce Richardson {
2799a2dd95SBruce Richardson 	char *str, *start;
2899a2dd95SBruce Richardson 	bool in_list = false, end_key = false, end_value = false;
2999a2dd95SBruce Richardson 	bool save = false, end_pair = false;
3099a2dd95SBruce Richardson 
3199a2dd95SBruce Richardson 	/* Copy the const char *params to a modifiable string
3299a2dd95SBruce Richardson 	 * to pass to rte_strsplit
3399a2dd95SBruce Richardson 	 */
3499a2dd95SBruce Richardson 	kvlist->str = strdup(params);
3599a2dd95SBruce Richardson 	if (kvlist->str == NULL)
3699a2dd95SBruce Richardson 		return -1;
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson 	/* browse each key/value pair and add it in kvlist */
3999a2dd95SBruce Richardson 	str = kvlist->str;
4099a2dd95SBruce Richardson 	start = str; /* start of current key or value */
4199a2dd95SBruce Richardson 	while (1) {
4299a2dd95SBruce Richardson 		switch (*str) {
4399a2dd95SBruce Richardson 		case '=': /* End of key. */
4499a2dd95SBruce Richardson 			end_key = true;
4599a2dd95SBruce Richardson 			save = true;
4699a2dd95SBruce Richardson 			break;
4799a2dd95SBruce Richardson 		case ',':
4899a2dd95SBruce Richardson 			/* End of value, skip comma in middle of range */
4999a2dd95SBruce Richardson 			if (!in_list) {
5099a2dd95SBruce Richardson 				if (end_key)
5199a2dd95SBruce Richardson 					end_value = true;
5299a2dd95SBruce Richardson 				else
5399a2dd95SBruce Richardson 					end_key = true;
5499a2dd95SBruce Richardson 				save = true;
5599a2dd95SBruce Richardson 				end_pair = true;
5699a2dd95SBruce Richardson 			}
5799a2dd95SBruce Richardson 			break;
5899a2dd95SBruce Richardson 		case '[': /* Start of list. */
5999a2dd95SBruce Richardson 			in_list = true;
6099a2dd95SBruce Richardson 			break;
6199a2dd95SBruce Richardson 		case ']': /* End of list.  */
6299a2dd95SBruce Richardson 			if (in_list)
6399a2dd95SBruce Richardson 				in_list = false;
6499a2dd95SBruce Richardson 			break;
6599a2dd95SBruce Richardson 		case '\0': /* End of string */
6699a2dd95SBruce Richardson 			if (end_key)
6799a2dd95SBruce Richardson 				end_value = true;
6899a2dd95SBruce Richardson 			else
6999a2dd95SBruce Richardson 				end_key = true;
7099a2dd95SBruce Richardson 			save = true;
7199a2dd95SBruce Richardson 			end_pair = true;
7299a2dd95SBruce Richardson 			break;
7399a2dd95SBruce Richardson 		default:
7499a2dd95SBruce Richardson 			break;
7599a2dd95SBruce Richardson 		}
7699a2dd95SBruce Richardson 
7799a2dd95SBruce Richardson 		if (!save) {
7899a2dd95SBruce Richardson 			/* Continue if not end of key or value. */
7999a2dd95SBruce Richardson 			str++;
8099a2dd95SBruce Richardson 			continue;
8199a2dd95SBruce Richardson 		}
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 		if (kvlist->count >= RTE_KVARGS_MAX)
8499a2dd95SBruce Richardson 			return -1;
8599a2dd95SBruce Richardson 
8699a2dd95SBruce Richardson 		if (end_value)
8799a2dd95SBruce Richardson 			/* Value parsed */
8899a2dd95SBruce Richardson 			kvlist->pairs[kvlist->count].value = start;
8999a2dd95SBruce Richardson 		else if (end_key)
9099a2dd95SBruce Richardson 			/* Key parsed. */
9199a2dd95SBruce Richardson 			kvlist->pairs[kvlist->count].key = start;
9299a2dd95SBruce Richardson 
9399a2dd95SBruce Richardson 		if (end_pair) {
9499a2dd95SBruce Richardson 			if (end_value || str != start)
9599a2dd95SBruce Richardson 				/* Ignore empty pair. */
9699a2dd95SBruce Richardson 				kvlist->count++;
9799a2dd95SBruce Richardson 			end_key = false;
9899a2dd95SBruce Richardson 			end_value = false;
9999a2dd95SBruce Richardson 			end_pair = false;
10099a2dd95SBruce Richardson 		}
10199a2dd95SBruce Richardson 
10299a2dd95SBruce Richardson 		if (*str == '\0') /* End of string. */
10399a2dd95SBruce Richardson 			break;
10499a2dd95SBruce Richardson 		*str = '\0';
10599a2dd95SBruce Richardson 		str++;
10699a2dd95SBruce Richardson 		start = str;
10799a2dd95SBruce Richardson 		save = false;
10899a2dd95SBruce Richardson 	}
10999a2dd95SBruce Richardson 
11099a2dd95SBruce Richardson 	return 0;
11199a2dd95SBruce Richardson }
11299a2dd95SBruce Richardson 
11399a2dd95SBruce Richardson /*
11499a2dd95SBruce Richardson  * Determine whether a key is valid or not by looking
11599a2dd95SBruce Richardson  * into a list of valid keys.
11699a2dd95SBruce Richardson  */
11799a2dd95SBruce Richardson static int
11899a2dd95SBruce Richardson is_valid_key(const char * const valid[], const char *key_match)
11999a2dd95SBruce Richardson {
12099a2dd95SBruce Richardson 	const char * const *valid_ptr;
12199a2dd95SBruce Richardson 
12299a2dd95SBruce Richardson 	for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) {
12399a2dd95SBruce Richardson 		if (strcmp(key_match, *valid_ptr) == 0)
12499a2dd95SBruce Richardson 			return 1;
12599a2dd95SBruce Richardson 	}
12699a2dd95SBruce Richardson 	return 0;
12799a2dd95SBruce Richardson }
12899a2dd95SBruce Richardson 
12999a2dd95SBruce Richardson /*
13099a2dd95SBruce Richardson  * Determine whether all keys are valid or not by looking
13199a2dd95SBruce Richardson  * into a list of valid keys.
13299a2dd95SBruce Richardson  */
13399a2dd95SBruce Richardson static int
13499a2dd95SBruce Richardson check_for_valid_keys(struct rte_kvargs *kvlist,
13599a2dd95SBruce Richardson 		const char * const valid[])
13699a2dd95SBruce Richardson {
13799a2dd95SBruce Richardson 	unsigned i, ret;
13899a2dd95SBruce Richardson 	struct rte_kvargs_pair *pair;
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson 	for (i = 0; i < kvlist->count; i++) {
14199a2dd95SBruce Richardson 		pair = &kvlist->pairs[i];
14299a2dd95SBruce Richardson 		ret = is_valid_key(valid, pair->key);
14399a2dd95SBruce Richardson 		if (!ret)
14499a2dd95SBruce Richardson 			return -1;
14599a2dd95SBruce Richardson 	}
14699a2dd95SBruce Richardson 	return 0;
14799a2dd95SBruce Richardson }
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson /*
15099a2dd95SBruce Richardson  * Return the number of times a given arg_name exists in the key/value list.
15199a2dd95SBruce Richardson  * E.g. given a list = { rx = 0, rx = 1, tx = 2 } the number of args for
15299a2dd95SBruce Richardson  * arg "rx" will be 2.
15399a2dd95SBruce Richardson  */
15499a2dd95SBruce Richardson unsigned
15599a2dd95SBruce Richardson rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match)
15699a2dd95SBruce Richardson {
15799a2dd95SBruce Richardson 	const struct rte_kvargs_pair *pair;
15899a2dd95SBruce Richardson 	unsigned i, ret;
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 	ret = 0;
16199a2dd95SBruce Richardson 	for (i = 0; i < kvlist->count; i++) {
16299a2dd95SBruce Richardson 		pair = &kvlist->pairs[i];
16399a2dd95SBruce Richardson 		if (key_match == NULL || strcmp(pair->key, key_match) == 0)
16499a2dd95SBruce Richardson 			ret++;
16599a2dd95SBruce Richardson 	}
16699a2dd95SBruce Richardson 
16799a2dd95SBruce Richardson 	return ret;
16899a2dd95SBruce Richardson }
16999a2dd95SBruce Richardson 
170*de899883SChengwen Feng static int
171*de899883SChengwen Feng kvargs_process_common(const struct rte_kvargs *kvlist, const char *key_match,
172*de899883SChengwen Feng 		      arg_handler_t handler, void *opaque_arg, bool support_only_key)
17399a2dd95SBruce Richardson {
17499a2dd95SBruce Richardson 	const struct rte_kvargs_pair *pair;
17599a2dd95SBruce Richardson 	unsigned i;
17699a2dd95SBruce Richardson 
17799a2dd95SBruce Richardson 	if (kvlist == NULL)
178*de899883SChengwen Feng 		return -1;
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	for (i = 0; i < kvlist->count; i++) {
18199a2dd95SBruce Richardson 		pair = &kvlist->pairs[i];
18299a2dd95SBruce Richardson 		if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
183*de899883SChengwen Feng 			if (!support_only_key && pair->value == NULL)
184*de899883SChengwen Feng 				return -1;
18599a2dd95SBruce Richardson 			if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
18699a2dd95SBruce Richardson 				return -1;
18799a2dd95SBruce Richardson 		}
18899a2dd95SBruce Richardson 	}
189*de899883SChengwen Feng 
19099a2dd95SBruce Richardson 	return 0;
19199a2dd95SBruce Richardson }
19299a2dd95SBruce Richardson 
193*de899883SChengwen Feng /*
194*de899883SChengwen Feng  * For each matching key in key=value, call the given handler function.
195*de899883SChengwen Feng  */
196*de899883SChengwen Feng int
197*de899883SChengwen Feng rte_kvargs_process(const struct rte_kvargs *kvlist, const char *key_match, arg_handler_t handler,
198*de899883SChengwen Feng 		   void *opaque_arg)
199*de899883SChengwen Feng {
200*de899883SChengwen Feng 	return kvargs_process_common(kvlist, key_match, handler, opaque_arg, false);
201*de899883SChengwen Feng }
202*de899883SChengwen Feng 
203*de899883SChengwen Feng /*
204*de899883SChengwen Feng  * For each matching key in key=value or only-key, call the given handler function.
205*de899883SChengwen Feng  */
206*de899883SChengwen Feng int
207*de899883SChengwen Feng rte_kvargs_process_opt(const struct rte_kvargs *kvlist, const char *key_match,
208*de899883SChengwen Feng 		       arg_handler_t handler, void *opaque_arg)
209*de899883SChengwen Feng {
210*de899883SChengwen Feng 	return kvargs_process_common(kvlist, key_match, handler, opaque_arg, true);
211*de899883SChengwen Feng }
212*de899883SChengwen Feng 
21399a2dd95SBruce Richardson /* free the rte_kvargs structure */
21499a2dd95SBruce Richardson void
21599a2dd95SBruce Richardson rte_kvargs_free(struct rte_kvargs *kvlist)
21699a2dd95SBruce Richardson {
21799a2dd95SBruce Richardson 	if (!kvlist)
21899a2dd95SBruce Richardson 		return;
21999a2dd95SBruce Richardson 
22099a2dd95SBruce Richardson 	free(kvlist->str);
22199a2dd95SBruce Richardson 	free(kvlist);
22299a2dd95SBruce Richardson }
22399a2dd95SBruce Richardson 
2246aebb942SOlivier Matz /* Lookup a value in an rte_kvargs list by its key and value. */
2256aebb942SOlivier Matz const char *
2266aebb942SOlivier Matz rte_kvargs_get_with_value(const struct rte_kvargs *kvlist, const char *key,
2276aebb942SOlivier Matz 			  const char *value)
2286aebb942SOlivier Matz {
2296aebb942SOlivier Matz 	unsigned int i;
2306aebb942SOlivier Matz 
2316aebb942SOlivier Matz 	if (kvlist == NULL)
2326aebb942SOlivier Matz 		return NULL;
2336aebb942SOlivier Matz 	for (i = 0; i < kvlist->count; ++i) {
2346aebb942SOlivier Matz 		if (key != NULL && strcmp(kvlist->pairs[i].key, key) != 0)
2356aebb942SOlivier Matz 			continue;
2366aebb942SOlivier Matz 		if (value != NULL && strcmp(kvlist->pairs[i].value, value) != 0)
2376aebb942SOlivier Matz 			continue;
2386aebb942SOlivier Matz 		return kvlist->pairs[i].value;
2396aebb942SOlivier Matz 	}
2406aebb942SOlivier Matz 	return NULL;
2416aebb942SOlivier Matz }
2426aebb942SOlivier Matz 
24399a2dd95SBruce Richardson /* Lookup a value in an rte_kvargs list by its key. */
24499a2dd95SBruce Richardson const char *
24599a2dd95SBruce Richardson rte_kvargs_get(const struct rte_kvargs *kvlist, const char *key)
24699a2dd95SBruce Richardson {
24799a2dd95SBruce Richardson 	if (kvlist == NULL || key == NULL)
24899a2dd95SBruce Richardson 		return NULL;
2496aebb942SOlivier Matz 	return rte_kvargs_get_with_value(kvlist, key, NULL);
25099a2dd95SBruce Richardson }
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson /*
25399a2dd95SBruce Richardson  * Parse the arguments "key=value,key=value,..." string and return
25499a2dd95SBruce Richardson  * an allocated structure that contains a key/value list. Also
25599a2dd95SBruce Richardson  * check if only valid keys were used.
25699a2dd95SBruce Richardson  */
25799a2dd95SBruce Richardson struct rte_kvargs *
25899a2dd95SBruce Richardson rte_kvargs_parse(const char *args, const char * const valid_keys[])
25999a2dd95SBruce Richardson {
26099a2dd95SBruce Richardson 	struct rte_kvargs *kvlist;
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson 	kvlist = malloc(sizeof(*kvlist));
26399a2dd95SBruce Richardson 	if (kvlist == NULL)
26499a2dd95SBruce Richardson 		return NULL;
26599a2dd95SBruce Richardson 	memset(kvlist, 0, sizeof(*kvlist));
26699a2dd95SBruce Richardson 
26799a2dd95SBruce Richardson 	if (rte_kvargs_tokenize(kvlist, args) < 0) {
26899a2dd95SBruce Richardson 		rte_kvargs_free(kvlist);
26999a2dd95SBruce Richardson 		return NULL;
27099a2dd95SBruce Richardson 	}
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) {
27399a2dd95SBruce Richardson 		rte_kvargs_free(kvlist);
27499a2dd95SBruce Richardson 		return NULL;
27599a2dd95SBruce Richardson 	}
27699a2dd95SBruce Richardson 
27799a2dd95SBruce Richardson 	return kvlist;
27899a2dd95SBruce Richardson }
27999a2dd95SBruce Richardson 
28099a2dd95SBruce Richardson struct rte_kvargs *
28199a2dd95SBruce Richardson rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
28299a2dd95SBruce Richardson 		       const char *valid_ends)
28399a2dd95SBruce Richardson {
28499a2dd95SBruce Richardson 	struct rte_kvargs *kvlist = NULL;
28599a2dd95SBruce Richardson 	char *copy;
28699a2dd95SBruce Richardson 	size_t len;
28799a2dd95SBruce Richardson 
28899a2dd95SBruce Richardson 	if (valid_ends == NULL)
28999a2dd95SBruce Richardson 		return rte_kvargs_parse(args, valid_keys);
29099a2dd95SBruce Richardson 
29199a2dd95SBruce Richardson 	copy = strdup(args);
29299a2dd95SBruce Richardson 	if (copy == NULL)
29399a2dd95SBruce Richardson 		return NULL;
29499a2dd95SBruce Richardson 
29599a2dd95SBruce Richardson 	len = strcspn(copy, valid_ends);
29699a2dd95SBruce Richardson 	copy[len] = '\0';
29799a2dd95SBruce Richardson 
29899a2dd95SBruce Richardson 	kvlist = rte_kvargs_parse(copy, valid_keys);
29999a2dd95SBruce Richardson 
30099a2dd95SBruce Richardson 	free(copy);
30199a2dd95SBruce Richardson 	return kvlist;
30299a2dd95SBruce Richardson }
303