2009-11-15 14:36:53 +03:00
# include "util.h"
2012-09-10 20:50:17 +04:00
# include "linux/string.h"
2009-06-02 05:31:03 +04:00
2009-11-15 14:36:53 +03:00
# define K 1024LL
/*
* perf_atoll ( )
* Parse ( \ d + ) ( b | B | kb | KB | mb | MB | gb | GB | tb | TB ) ( e . g . " 256MB " )
* and return its numeric value
*/
s64 perf_atoll ( const char * str )
{
2014-08-29 20:37:29 +04:00
s64 length ;
char * p ;
char c ;
2009-11-15 14:36:53 +03:00
if ( ! isdigit ( str [ 0 ] ) )
goto out_err ;
2014-08-29 20:37:29 +04:00
length = strtoll ( str , & p , 10 ) ;
switch ( c = * p + + ) {
case ' b ' : case ' B ' :
if ( * p )
2009-11-15 14:36:53 +03:00
goto out_err ;
2014-08-29 20:37:29 +04:00
case ' \0 ' :
return length ;
default :
goto out_err ;
/* two-letter suffices */
case ' k ' : case ' K ' :
length < < = 10 ;
2009-11-15 14:36:53 +03:00
break ;
2014-08-29 20:37:29 +04:00
case ' m ' : case ' M ' :
length < < = 20 ;
2009-11-15 14:36:53 +03:00
break ;
2014-08-29 20:37:29 +04:00
case ' g ' : case ' G ' :
length < < = 30 ;
2009-11-15 14:36:53 +03:00
break ;
2014-08-29 20:37:29 +04:00
case ' t ' : case ' T ' :
length < < = 40 ;
2009-11-15 14:36:53 +03:00
break ;
}
2014-08-29 20:37:29 +04:00
/* we want the cases to match */
if ( islower ( c ) ) {
if ( strcmp ( p , " b " ) ! = 0 )
goto out_err ;
} else {
if ( strcmp ( p , " B " ) ! = 0 )
goto out_err ;
}
return length ;
2009-11-15 14:36:53 +03:00
out_err :
2014-08-29 20:37:29 +04:00
return - 1 ;
2009-11-15 14:36:53 +03:00
}
2009-12-01 03:20:05 +03:00
/*
* Helper function for splitting a string into an argv - like array .
2011-03-31 05:57:33 +04:00
* originally copied from lib / argv_split . c
2009-12-01 03:20:05 +03:00
*/
static const char * skip_sep ( const char * cp )
{
while ( * cp & & isspace ( * cp ) )
cp + + ;
return cp ;
}
static const char * skip_arg ( const char * cp )
{
while ( * cp & & ! isspace ( * cp ) )
cp + + ;
return cp ;
}
static int count_argc ( const char * str )
{
int count = 0 ;
while ( * str ) {
str = skip_sep ( str ) ;
if ( * str ) {
count + + ;
str = skip_arg ( str ) ;
}
}
return count ;
}
/**
* argv_free - free an argv
* @ argv - the argument vector to be freed
*
* Frees an argv and the strings it points to .
*/
void argv_free ( char * * argv )
{
char * * p ;
for ( p = argv ; * p ; p + + )
2013-12-27 23:55:14 +04:00
zfree ( p ) ;
2009-12-01 03:20:05 +03:00
free ( argv ) ;
}
/**
* argv_split - split a string at whitespace , returning an argv
* @ str : the string to be split
* @ argcp : returned argument count
*
* Returns an array of pointers to strings which are split out from
* @ str . This is performed by strictly splitting on white - space ; no
* quote processing is performed . Multiple whitespace characters are
* considered to be a single argument separator . The returned array
* is always NULL - terminated . Returns NULL on memory allocation
* failure .
*/
char * * argv_split ( const char * str , int * argcp )
{
int argc = count_argc ( str ) ;
char * * argv = zalloc ( sizeof ( * argv ) * ( argc + 1 ) ) ;
char * * argvp ;
if ( argv = = NULL )
goto out ;
if ( argcp )
* argcp = argc ;
argvp = argv ;
while ( * str ) {
str = skip_sep ( str ) ;
if ( * str ) {
const char * p = str ;
char * t ;
str = skip_arg ( str ) ;
t = strndup ( p , str - p ) ;
if ( t = = NULL )
goto fail ;
* argvp + + = t ;
}
}
* argvp = NULL ;
out :
return argv ;
fail :
argv_free ( argv ) ;
return NULL ;
}
2009-12-15 18:32:10 +03:00
2010-01-06 01:47:24 +03:00
/* Character class matching */
static bool __match_charclass ( const char * pat , char c , const char * * npat )
{
bool complement = false , ret = true ;
if ( * pat = = ' ! ' ) {
complement = true ;
pat + + ;
}
if ( * pat + + = = c ) /* First character is special */
goto end ;
while ( * pat & & * pat ! = ' ] ' ) { /* Matching */
if ( * pat = = ' - ' & & * ( pat + 1 ) ! = ' ] ' ) { /* Range */
if ( * ( pat - 1 ) < = c & & c < = * ( pat + 1 ) )
goto end ;
if ( * ( pat - 1 ) > * ( pat + 1 ) )
goto error ;
pat + = 2 ;
} else if ( * pat + + = = c )
goto end ;
}
if ( ! * pat )
goto error ;
ret = false ;
end :
while ( * pat & & * pat ! = ' ] ' ) /* Searching closing */
pat + + ;
if ( ! * pat )
goto error ;
* npat = pat + 1 ;
return complement ? ! ret : ret ;
error :
return false ;
}
2010-02-25 16:36:12 +03:00
/* Glob/lazy pattern matching */
static bool __match_glob ( const char * str , const char * pat , bool ignore_space )
2009-12-15 18:32:10 +03:00
{
while ( * str & & * pat & & * pat ! = ' * ' ) {
2010-02-25 16:36:12 +03:00
if ( ignore_space ) {
/* Ignore spaces for lazy matching */
if ( isspace ( * str ) ) {
str + + ;
continue ;
}
if ( isspace ( * pat ) ) {
pat + + ;
continue ;
}
}
2010-01-06 01:47:24 +03:00
if ( * pat = = ' ? ' ) { /* Matches any single character */
2009-12-15 18:32:10 +03:00
str + + ;
pat + + ;
2010-01-06 01:47:24 +03:00
continue ;
} else if ( * pat = = ' [ ' ) /* Character classes/Ranges */
if ( __match_charclass ( pat + 1 , * str , & pat ) ) {
str + + ;
continue ;
} else
2009-12-15 18:32:10 +03:00
return false ;
2010-01-06 01:47:24 +03:00
else if ( * pat = = ' \\ ' ) /* Escaped char match as normal char */
pat + + ;
if ( * str + + ! = * pat + + )
return false ;
2009-12-15 18:32:10 +03:00
}
/* Check wild card */
if ( * pat = = ' * ' ) {
while ( * pat = = ' * ' )
pat + + ;
if ( ! * pat ) /* Tail wild card matches all */
return true ;
while ( * str )
2010-12-17 16:12:00 +03:00
if ( __match_glob ( str + + , pat , ignore_space ) )
2009-12-15 18:32:10 +03:00
return true ;
}
return ! * str & & ! * pat ;
}
2010-02-25 16:36:12 +03:00
/**
* strglobmatch - glob expression pattern matching
* @ str : the target string to match
* @ pat : the pattern string to match
*
* This returns true if the @ str matches @ pat . @ pat can includes wildcards
* ( ' * ' , ' ? ' ) and character classes ( [ CHARS ] , complementation and ranges are
* also supported ) . Also , this supports escape character ( ' \ ' ) to use special
* characters as normal character .
*
* Note : if @ pat syntax is broken , this always returns false .
*/
bool strglobmatch ( const char * str , const char * pat )
{
return __match_glob ( str , pat , false ) ;
}
/**
* strlazymatch - matching pattern strings lazily with glob pattern
* @ str : the target string to match
* @ pat : the pattern string to match
*
* This is similar to strglobmatch , except this ignores spaces in
* the target string .
*/
bool strlazymatch ( const char * str , const char * pat )
{
return __match_glob ( str , pat , true ) ;
}
2011-06-27 11:27:15 +04:00
/**
* strtailcmp - Compare the tail of two strings
* @ s1 : 1 st string to be compared
* @ s2 : 2 nd string to be compared
*
* Return 0 if whole of either string is same as another ' s tail part .
*/
int strtailcmp ( const char * s1 , const char * s2 )
{
int i1 = strlen ( s1 ) ;
int i2 = strlen ( s2 ) ;
while ( - - i1 > = 0 & & - - i2 > = 0 ) {
if ( s1 [ i1 ] ! = s2 [ i2 ] )
return s1 [ i1 ] - s2 [ i2 ] ;
}
return 0 ;
}
2012-10-28 01:18:31 +04:00
/**
* strxfrchar - Locate and replace character in @ s
* @ s : The string to be searched / changed .
* @ from : Source character to be replaced .
* @ to : Destination character .
*
* Return pointer to the changed string .
*/
char * strxfrchar ( char * s , char from , char to )
{
char * p = s ;
while ( ( p = strchr ( p , from ) ) ! = NULL )
* p + + = to ;
return s ;
}
2013-01-22 13:09:41 +04:00
/**
* ltrim - Removes leading whitespace from @ s .
* @ s : The string to be stripped .
*
* Return pointer to the first non - whitespace character in @ s .
*/
char * ltrim ( char * s )
{
int len = strlen ( s ) ;
while ( len & & isspace ( * s ) ) {
len - - ;
s + + ;
}
return s ;
}
2012-06-08 01:23:31 +04:00
/**
* rtrim - Removes trailing whitespace from @ s .
* @ s : The string to be stripped .
*
* Note that the first trailing whitespace is replaced with a % NUL - terminator
* in the given string @ s . Returns @ s .
*/
char * rtrim ( char * s )
{
size_t size = strlen ( s ) ;
char * end ;
if ( ! size )
return s ;
end = s + size - 1 ;
while ( end > = s & & isspace ( * end ) )
end - - ;
* ( end + 1 ) = ' \0 ' ;
return s ;
}
2012-09-10 20:50:17 +04:00
/**
* memdup - duplicate region of memory
* @ src : memory region to duplicate
* @ len : memory region length
*/
void * memdup ( const void * src , size_t len )
{
void * p ;
p = malloc ( len ) ;
if ( p )
memcpy ( p , src , len ) ;
return p ;
}