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 9 #include <rte_string_fns.h> 10 11 #include "rte_kvargs.h" 12 13 /* 14 * Receive a string with a list of arguments following the pattern 15 * key=value,key=value,... and insert them into the list. 16 * strtok() is used so the params string will be copied to be modified. 17 */ 18 static int 19 rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params) 20 { 21 unsigned i; 22 char *str; 23 char *ctx1 = NULL; 24 char *ctx2 = NULL; 25 26 /* Copy the const char *params to a modifiable string 27 * to pass to rte_strsplit 28 */ 29 kvlist->str = strdup(params); 30 if (kvlist->str == NULL) 31 return -1; 32 33 /* browse each key/value pair and add it in kvlist */ 34 str = kvlist->str; 35 while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) { 36 37 i = kvlist->count; 38 if (i >= RTE_KVARGS_MAX) 39 return -1; 40 41 kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2); 42 kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2); 43 if (kvlist->pairs[i].key == NULL || 44 kvlist->pairs[i].value == NULL) 45 return -1; 46 47 /* Detect list [a,b] to skip comma delimiter in list. */ 48 str = kvlist->pairs[i].value; 49 if (str[0] == '[') { 50 /* Find the end of the list. */ 51 while (str[strlen(str) - 1] != ']') { 52 /* Restore the comma erased by strtok_r(). */ 53 str[strlen(str)] = ','; 54 /* Parse until next comma. */ 55 str = strtok_r(NULL, RTE_KVARGS_PAIRS_DELIM, &ctx1); 56 if (str == NULL) 57 return -1; /* no closing bracket */ 58 } 59 } 60 61 kvlist->count++; 62 str = NULL; 63 } 64 65 return 0; 66 } 67 68 /* 69 * Determine whether a key is valid or not by looking 70 * into a list of valid keys. 71 */ 72 static int 73 is_valid_key(const char * const valid[], const char *key_match) 74 { 75 const char * const *valid_ptr; 76 77 for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) { 78 if (strcmp(key_match, *valid_ptr) == 0) 79 return 1; 80 } 81 return 0; 82 } 83 84 /* 85 * Determine whether all keys are valid or not by looking 86 * into a list of valid keys. 87 */ 88 static int 89 check_for_valid_keys(struct rte_kvargs *kvlist, 90 const char * const valid[]) 91 { 92 unsigned i, ret; 93 struct rte_kvargs_pair *pair; 94 95 for (i = 0; i < kvlist->count; i++) { 96 pair = &kvlist->pairs[i]; 97 ret = is_valid_key(valid, pair->key); 98 if (!ret) 99 return -1; 100 } 101 return 0; 102 } 103 104 /* 105 * Return the number of times a given arg_name exists in the key/value list. 106 * E.g. given a list = { rx = 0, rx = 1, tx = 2 } the number of args for 107 * arg "rx" will be 2. 108 */ 109 unsigned 110 rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match) 111 { 112 const struct rte_kvargs_pair *pair; 113 unsigned i, ret; 114 115 ret = 0; 116 for (i = 0; i < kvlist->count; i++) { 117 pair = &kvlist->pairs[i]; 118 if (key_match == NULL || strcmp(pair->key, key_match) == 0) 119 ret++; 120 } 121 122 return ret; 123 } 124 125 /* 126 * For each matching key, call the given handler function. 127 */ 128 int 129 rte_kvargs_process(const struct rte_kvargs *kvlist, 130 const char *key_match, 131 arg_handler_t handler, 132 void *opaque_arg) 133 { 134 const struct rte_kvargs_pair *pair; 135 unsigned i; 136 137 if (kvlist == NULL) 138 return 0; 139 140 for (i = 0; i < kvlist->count; i++) { 141 pair = &kvlist->pairs[i]; 142 if (key_match == NULL || strcmp(pair->key, key_match) == 0) { 143 if ((*handler)(pair->key, pair->value, opaque_arg) < 0) 144 return -1; 145 } 146 } 147 return 0; 148 } 149 150 /* free the rte_kvargs structure */ 151 void 152 rte_kvargs_free(struct rte_kvargs *kvlist) 153 { 154 if (!kvlist) 155 return; 156 157 free(kvlist->str); 158 free(kvlist); 159 } 160 161 /* 162 * Parse the arguments "key=value,key=value,..." string and return 163 * an allocated structure that contains a key/value list. Also 164 * check if only valid keys were used. 165 */ 166 struct rte_kvargs * 167 rte_kvargs_parse(const char *args, const char * const valid_keys[]) 168 { 169 struct rte_kvargs *kvlist; 170 171 kvlist = malloc(sizeof(*kvlist)); 172 if (kvlist == NULL) 173 return NULL; 174 memset(kvlist, 0, sizeof(*kvlist)); 175 176 if (rte_kvargs_tokenize(kvlist, args) < 0) { 177 rte_kvargs_free(kvlist); 178 return NULL; 179 } 180 181 if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) { 182 rte_kvargs_free(kvlist); 183 return NULL; 184 } 185 186 return kvlist; 187 } 188 189 __rte_experimental 190 struct rte_kvargs * 191 rte_kvargs_parse_delim(const char *args, const char * const valid_keys[], 192 const char *valid_ends) 193 { 194 struct rte_kvargs *kvlist = NULL; 195 char *copy; 196 size_t len; 197 198 if (valid_ends == NULL) 199 return rte_kvargs_parse(args, valid_keys); 200 201 copy = strdup(args); 202 if (copy == NULL) 203 return NULL; 204 205 len = strcspn(copy, valid_ends); 206 copy[len] = '\0'; 207 208 kvlist = rte_kvargs_parse(copy, valid_keys); 209 210 free(copy); 211 return kvlist; 212 } 213 214 __rte_experimental 215 int 216 rte_kvargs_strcmp(const char *key __rte_unused, 217 const char *value, void *opaque) 218 { 219 const char *str = opaque; 220 221 return -abs(strcmp(str, value)); 222 } 223