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