|  | /* | 
|  | * (C) Copyright 2012 | 
|  | * Joe Hershberger, National Instruments, joe.hershberger@ni.com | 
|  | * | 
|  | * SPDX-License-Identifier:	GPL-2.0+ | 
|  | */ | 
|  |  | 
|  | #ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ | 
|  | #include <stdint.h> | 
|  | #include <stdio.h> | 
|  | #include <linux/linux_string.h> | 
|  | #else | 
|  | #include <common.h> | 
|  | #endif | 
|  |  | 
|  | #include <env_attr.h> | 
|  | #include <errno.h> | 
|  | #include <linux/string.h> | 
|  | #include <malloc.h> | 
|  |  | 
|  | /* | 
|  | * Iterate through the whole list calling the callback for each found element. | 
|  | * "attr_list" takes the form: | 
|  | *	attributes = [^,:\s]* | 
|  | *	entry = name[:attributes] | 
|  | *	list = entry[,list] | 
|  | */ | 
|  | int env_attr_walk(const char *attr_list, | 
|  | int (*callback)(const char *name, const char *attributes)) | 
|  | { | 
|  | const char *entry, *entry_end; | 
|  | char *name, *attributes; | 
|  |  | 
|  | if (!attr_list) | 
|  | /* list not found */ | 
|  | return 1; | 
|  |  | 
|  | entry = attr_list; | 
|  | do { | 
|  | char *entry_cpy = NULL; | 
|  |  | 
|  | entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); | 
|  | /* check if this is the last entry in the list */ | 
|  | if (entry_end == NULL) { | 
|  | int entry_len = strlen(entry); | 
|  |  | 
|  | if (entry_len) { | 
|  | /* | 
|  | * allocate memory to copy the entry into since | 
|  | * we will need to inject '\0' chars and squash | 
|  | * white-space before calling the callback | 
|  | */ | 
|  | entry_cpy = malloc(entry_len + 1); | 
|  | if (entry_cpy) | 
|  | /* copy the rest of the list */ | 
|  | strcpy(entry_cpy, entry); | 
|  | else | 
|  | return -ENOMEM; | 
|  | } | 
|  | } else { | 
|  | int entry_len = entry_end - entry; | 
|  |  | 
|  | if (entry_len) { | 
|  | /* | 
|  | * allocate memory to copy the entry into since | 
|  | * we will need to inject '\0' chars and squash | 
|  | * white-space before calling the callback | 
|  | */ | 
|  | entry_cpy = malloc(entry_len + 1); | 
|  | if (entry_cpy) { | 
|  | /* copy just this entry and null term */ | 
|  | strncpy(entry_cpy, entry, entry_len); | 
|  | entry_cpy[entry_len] = '\0'; | 
|  | } else | 
|  | return -ENOMEM; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* check if there is anything to process (e.g. not ",,,") */ | 
|  | if (entry_cpy != NULL) { | 
|  | attributes = strchr(entry_cpy, ENV_ATTR_SEP); | 
|  | /* check if there is a ':' */ | 
|  | if (attributes != NULL) { | 
|  | /* replace the ':' with '\0' to term name */ | 
|  | *attributes++ = '\0'; | 
|  | /* remove white-space from attributes */ | 
|  | attributes = strim(attributes); | 
|  | } | 
|  | /* remove white-space from name */ | 
|  | name = strim(entry_cpy); | 
|  |  | 
|  | /* only call the callback if there is a name */ | 
|  | if (strlen(name) != 0) { | 
|  | int retval = 0; | 
|  |  | 
|  | retval = callback(name, attributes); | 
|  | if (retval) { | 
|  | free(entry_cpy); | 
|  | return retval; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | free(entry_cpy); | 
|  | entry = entry_end + 1; | 
|  | } while (entry_end != NULL); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Search for the last matching string in another string with the option to | 
|  | * start looking at a certain point (i.e. ignore anything beyond that point). | 
|  | */ | 
|  | static char *reverse_strstr(const char *searched, const char *search_for, | 
|  | const char *searched_start) | 
|  | { | 
|  | char *result = NULL; | 
|  |  | 
|  | if (*search_for == '\0') | 
|  | return (char *)searched; | 
|  |  | 
|  | for (;;) { | 
|  | char *match = strstr(searched, search_for); | 
|  |  | 
|  | /* | 
|  | * Stop looking if no new match is found or looking past the | 
|  | * searched_start pointer | 
|  | */ | 
|  | if (match == NULL || (searched_start != NULL && | 
|  | match + strlen(search_for) > searched_start)) | 
|  | break; | 
|  |  | 
|  | result = match; | 
|  | searched = match + 1; | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Retrieve the attributes string associated with a single name in the list | 
|  | * There is no protection on attributes being too small for the value | 
|  | */ | 
|  | int env_attr_lookup(const char *attr_list, const char *name, char *attributes) | 
|  | { | 
|  | const char *entry = NULL; | 
|  |  | 
|  | if (!attributes) | 
|  | /* bad parameter */ | 
|  | return -1; | 
|  | if (!attr_list) | 
|  | /* list not found */ | 
|  | return 1; | 
|  |  | 
|  | entry = reverse_strstr(attr_list, name, NULL); | 
|  | while (entry != NULL) { | 
|  | const char *prevch = entry - 1; | 
|  | const char *nextch = entry + strlen(name); | 
|  |  | 
|  | /* Skip spaces */ | 
|  | while (*prevch == ' ') | 
|  | prevch--; | 
|  | while (*nextch == ' ') | 
|  | nextch++; | 
|  |  | 
|  | /* check for an exact match */ | 
|  | if ((entry == attr_list || | 
|  | *prevch == ENV_ATTR_LIST_DELIM) && | 
|  | (*nextch == ENV_ATTR_SEP || | 
|  | *nextch == ENV_ATTR_LIST_DELIM || | 
|  | *nextch == '\0')) | 
|  | break; | 
|  |  | 
|  | entry = reverse_strstr(attr_list, name, entry); | 
|  | } | 
|  | if (entry != NULL) { | 
|  | int len; | 
|  |  | 
|  | /* skip the name */ | 
|  | entry += strlen(name); | 
|  | /* skip spaces */ | 
|  | while (*entry == ' ') | 
|  | entry++; | 
|  | if (*entry != ENV_ATTR_SEP) | 
|  | len = 0; | 
|  | else { | 
|  | const char *delim; | 
|  | static const char delims[] = { | 
|  | ENV_ATTR_LIST_DELIM, ' ', '\0'}; | 
|  |  | 
|  | /* skip the attr sep */ | 
|  | entry += 1; | 
|  | /* skip spaces */ | 
|  | while (*entry == ' ') | 
|  | entry++; | 
|  |  | 
|  | delim = strpbrk(entry, delims); | 
|  | if (delim == NULL) | 
|  | len = strlen(entry); | 
|  | else | 
|  | len = delim - entry; | 
|  | memcpy(attributes, entry, len); | 
|  | } | 
|  | attributes[len] = '\0'; | 
|  |  | 
|  | /* success */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* not found in list */ | 
|  | return 2; | 
|  | } |