1 /* 2 * (C) Copyright 2012 3 * Joe Hershberger, National Instruments, joe.hershberger@ni.com 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <linux/linux_string.h> 12 #else 13 #include <common.h> 14 #include <slre.h> 15 #endif 16 17 #include <env_attr.h> 18 #include <errno.h> 19 #include <linux/string.h> 20 #include <malloc.h> 21 22 /* 23 * Iterate through the whole list calling the callback for each found element. 24 * "attr_list" takes the form: 25 * attributes = [^,:\s]* 26 * entry = name[:attributes] 27 * list = entry[,list] 28 */ 29 int env_attr_walk(const char *attr_list, 30 int (*callback)(const char *name, const char *attributes, void *priv), 31 void *priv) 32 { 33 const char *entry, *entry_end; 34 char *name, *attributes; 35 36 if (!attr_list) 37 /* list not found */ 38 return 1; 39 40 entry = attr_list; 41 do { 42 char *entry_cpy = NULL; 43 44 entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); 45 /* check if this is the last entry in the list */ 46 if (entry_end == NULL) { 47 int entry_len = strlen(entry); 48 49 if (entry_len) { 50 /* 51 * allocate memory to copy the entry into since 52 * we will need to inject '\0' chars and squash 53 * white-space before calling the callback 54 */ 55 entry_cpy = malloc(entry_len + 1); 56 if (entry_cpy) 57 /* copy the rest of the list */ 58 strcpy(entry_cpy, entry); 59 else 60 return -ENOMEM; 61 } 62 } else { 63 int entry_len = entry_end - entry; 64 65 if (entry_len) { 66 /* 67 * allocate memory to copy the entry into since 68 * we will need to inject '\0' chars and squash 69 * white-space before calling the callback 70 */ 71 entry_cpy = malloc(entry_len + 1); 72 if (entry_cpy) { 73 /* copy just this entry and null term */ 74 strncpy(entry_cpy, entry, entry_len); 75 entry_cpy[entry_len] = '\0'; 76 } else 77 return -ENOMEM; 78 } 79 } 80 81 /* check if there is anything to process (e.g. not ",,,") */ 82 if (entry_cpy != NULL) { 83 attributes = strchr(entry_cpy, ENV_ATTR_SEP); 84 /* check if there is a ':' */ 85 if (attributes != NULL) { 86 /* replace the ':' with '\0' to term name */ 87 *attributes++ = '\0'; 88 /* remove white-space from attributes */ 89 attributes = strim(attributes); 90 } 91 /* remove white-space from name */ 92 name = strim(entry_cpy); 93 94 /* only call the callback if there is a name */ 95 if (strlen(name) != 0) { 96 int retval = 0; 97 98 retval = callback(name, attributes, priv); 99 if (retval) { 100 free(entry_cpy); 101 return retval; 102 } 103 } 104 } 105 106 free(entry_cpy); 107 entry = entry_end + 1; 108 } while (entry_end != NULL); 109 110 return 0; 111 } 112 113 #if defined(CONFIG_REGEX) 114 struct regex_callback_priv { 115 const char *searched_for; 116 char *regex; 117 char *attributes; 118 }; 119 120 static int regex_callback(const char *name, const char *attributes, void *priv) 121 { 122 int retval = 0; 123 struct regex_callback_priv *cbp = (struct regex_callback_priv *)priv; 124 struct slre slre; 125 char regex[strlen(name) + 3]; 126 127 /* Require the whole string to be described by the regex */ 128 sprintf(regex, "^%s$", name); 129 if (slre_compile(&slre, regex)) { 130 struct cap caps[slre.num_caps + 2]; 131 132 if (slre_match(&slre, cbp->searched_for, 133 strlen(cbp->searched_for), caps)) { 134 free(cbp->regex); 135 if (!attributes) { 136 retval = -EINVAL; 137 goto done; 138 } 139 cbp->regex = malloc(strlen(regex) + 1); 140 if (cbp->regex) { 141 strcpy(cbp->regex, regex); 142 } else { 143 retval = -ENOMEM; 144 goto done; 145 } 146 147 free(cbp->attributes); 148 cbp->attributes = malloc(strlen(attributes) + 1); 149 if (cbp->attributes) { 150 strcpy(cbp->attributes, attributes); 151 } else { 152 retval = -ENOMEM; 153 free(cbp->regex); 154 cbp->regex = NULL; 155 goto done; 156 } 157 } 158 } else { 159 printf("Error compiling regex: %s\n", slre.err_str); 160 retval = -EINVAL; 161 } 162 done: 163 return retval; 164 } 165 166 /* 167 * Retrieve the attributes string associated with a single name in the list 168 * There is no protection on attributes being too small for the value 169 */ 170 int env_attr_lookup(const char *attr_list, const char *name, char *attributes) 171 { 172 if (!attributes) 173 /* bad parameter */ 174 return -EINVAL; 175 if (!attr_list) 176 /* list not found */ 177 return -EINVAL; 178 179 struct regex_callback_priv priv; 180 int retval; 181 182 priv.searched_for = name; 183 priv.regex = NULL; 184 priv.attributes = NULL; 185 retval = env_attr_walk(attr_list, regex_callback, &priv); 186 if (retval) 187 return retval; /* error */ 188 189 if (priv.regex) { 190 strcpy(attributes, priv.attributes); 191 free(priv.attributes); 192 free(priv.regex); 193 /* success */ 194 return 0; 195 } 196 return -ENOENT; /* not found in list */ 197 } 198 #else 199 200 /* 201 * Search for the last exactly matching name in an attribute list 202 */ 203 static int reverse_name_search(const char *searched, const char *search_for, 204 const char **result) 205 { 206 int result_size = 0; 207 const char *cur_searched = searched; 208 209 if (result) 210 *result = NULL; 211 212 if (*search_for == '\0') { 213 if (result) 214 *result = searched; 215 return strlen(searched); 216 } 217 218 for (;;) { 219 const char *match = strstr(cur_searched, search_for); 220 const char *prevch; 221 const char *nextch; 222 223 /* Stop looking if no new match is found */ 224 if (match == NULL) 225 break; 226 227 prevch = match - 1; 228 nextch = match + strlen(search_for); 229 230 /* Skip spaces */ 231 while (*prevch == ' ' && prevch >= searched) 232 prevch--; 233 while (*nextch == ' ') 234 nextch++; 235 236 /* Start looking past the current match so last is found */ 237 cur_searched = match + 1; 238 /* Check for an exact match */ 239 if (match != searched && 240 *prevch != ENV_ATTR_LIST_DELIM && 241 prevch != searched - 1) 242 continue; 243 if (*nextch != ENV_ATTR_SEP && 244 *nextch != ENV_ATTR_LIST_DELIM && 245 *nextch != '\0') 246 continue; 247 248 if (result) 249 *result = match; 250 result_size = strlen(search_for); 251 } 252 253 return result_size; 254 } 255 256 /* 257 * Retrieve the attributes string associated with a single name in the list 258 * There is no protection on attributes being too small for the value 259 */ 260 int env_attr_lookup(const char *attr_list, const char *name, char *attributes) 261 { 262 const char *entry = NULL; 263 int entry_len; 264 265 if (!attributes) 266 /* bad parameter */ 267 return -EINVAL; 268 if (!attr_list) 269 /* list not found */ 270 return -EINVAL; 271 272 entry_len = reverse_name_search(attr_list, name, &entry); 273 if (entry != NULL) { 274 int len; 275 276 /* skip the name */ 277 entry += entry_len; 278 /* skip spaces */ 279 while (*entry == ' ') 280 entry++; 281 if (*entry != ENV_ATTR_SEP) 282 len = 0; 283 else { 284 const char *delim; 285 static const char delims[] = { 286 ENV_ATTR_LIST_DELIM, ' ', '\0'}; 287 288 /* skip the attr sep */ 289 entry += 1; 290 /* skip spaces */ 291 while (*entry == ' ') 292 entry++; 293 294 delim = strpbrk(entry, delims); 295 if (delim == NULL) 296 len = strlen(entry); 297 else 298 len = delim - entry; 299 memcpy(attributes, entry, len); 300 } 301 attributes[len] = '\0'; 302 303 /* success */ 304 return 0; 305 } 306 307 /* not found in list */ 308 return -ENOENT; 309 } 310 #endif 311