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 /* 171 * For each matching key, call the given handler function. 172 */ 173 int 174 rte_kvargs_process(const struct rte_kvargs *kvlist, 175 const char *key_match, 176 arg_handler_t handler, 177 void *opaque_arg) 178 { 179 const struct rte_kvargs_pair *pair; 180 unsigned i; 181 182 if (kvlist == NULL) 183 return 0; 184 185 for (i = 0; i < kvlist->count; i++) { 186 pair = &kvlist->pairs[i]; 187 if (key_match == NULL || strcmp(pair->key, key_match) == 0) { 188 if ((*handler)(pair->key, pair->value, opaque_arg) < 0) 189 return -1; 190 } 191 } 192 return 0; 193 } 194 195 /* free the rte_kvargs structure */ 196 void 197 rte_kvargs_free(struct rte_kvargs *kvlist) 198 { 199 if (!kvlist) 200 return; 201 202 free(kvlist->str); 203 free(kvlist); 204 } 205 206 /* Lookup a value in an rte_kvargs list by its key and value. */ 207 const char * 208 rte_kvargs_get_with_value(const struct rte_kvargs *kvlist, const char *key, 209 const char *value) 210 { 211 unsigned int i; 212 213 if (kvlist == NULL) 214 return NULL; 215 for (i = 0; i < kvlist->count; ++i) { 216 if (key != NULL && strcmp(kvlist->pairs[i].key, key) != 0) 217 continue; 218 if (value != NULL && strcmp(kvlist->pairs[i].value, value) != 0) 219 continue; 220 return kvlist->pairs[i].value; 221 } 222 return NULL; 223 } 224 225 /* Lookup a value in an rte_kvargs list by its key. */ 226 const char * 227 rte_kvargs_get(const struct rte_kvargs *kvlist, const char *key) 228 { 229 if (kvlist == NULL || key == NULL) 230 return NULL; 231 return rte_kvargs_get_with_value(kvlist, key, NULL); 232 } 233 234 /* 235 * Parse the arguments "key=value,key=value,..." string and return 236 * an allocated structure that contains a key/value list. Also 237 * check if only valid keys were used. 238 */ 239 struct rte_kvargs * 240 rte_kvargs_parse(const char *args, const char * const valid_keys[]) 241 { 242 struct rte_kvargs *kvlist; 243 244 kvlist = malloc(sizeof(*kvlist)); 245 if (kvlist == NULL) 246 return NULL; 247 memset(kvlist, 0, sizeof(*kvlist)); 248 249 if (rte_kvargs_tokenize(kvlist, args) < 0) { 250 rte_kvargs_free(kvlist); 251 return NULL; 252 } 253 254 if (valid_keys != NULL && check_for_valid_keys(kvlist, valid_keys) < 0) { 255 rte_kvargs_free(kvlist); 256 return NULL; 257 } 258 259 return kvlist; 260 } 261 262 struct rte_kvargs * 263 rte_kvargs_parse_delim(const char *args, const char * const valid_keys[], 264 const char *valid_ends) 265 { 266 struct rte_kvargs *kvlist = NULL; 267 char *copy; 268 size_t len; 269 270 if (valid_ends == NULL) 271 return rte_kvargs_parse(args, valid_keys); 272 273 copy = strdup(args); 274 if (copy == NULL) 275 return NULL; 276 277 len = strcspn(copy, valid_ends); 278 copy[len] = '\0'; 279 280 kvlist = rte_kvargs_parse(copy, valid_keys); 281 282 free(copy); 283 return kvlist; 284 } 285