/*
* ( 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 ;
}