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