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