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
2017-04-17 22:10:49 +03:00
# include "sane_ctype.h"
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 ;
2017-02-08 23:01:46 +03:00
__fallthrough ;
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 */
2016-10-19 20:50:01 +03:00
static bool __match_glob ( const char * str , const char * pat , bool ignore_space ,
bool case_ins )
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 + + ;
2016-10-19 20:50:01 +03:00
if ( case_ins ) {
if ( tolower ( * str ) ! = tolower ( * pat ) )
return false ;
} else if ( * str ! = * pat )
2010-01-06 01:47:24 +03:00
return false ;
2016-10-19 20:50:01 +03:00
str + + ;
pat + + ;
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 )
2016-10-19 20:50:01 +03:00
if ( __match_glob ( str + + , pat , ignore_space , case_ins ) )
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 )
{
2016-10-19 20:50:01 +03:00
return __match_glob ( str , pat , false , false ) ;
}
bool strglobmatch_nocase ( const char * str , const char * pat )
{
return __match_glob ( str , pat , false , true ) ;
2010-02-25 16:36:12 +03:00
}
/**
* 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 )
{
2016-10-19 20:50:01 +03:00
return __match_glob ( str , pat , true , false ) ;
2010-02-25 16:36:12 +03:00
}
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 )
{
2017-04-07 18:19:38 +03:00
while ( isspace ( * s ) )
2013-01-22 13:09:41 +04:00
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
perf tools: Asprintf like functions to format integer filter expression
char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints);
char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints);
Example of output formatted with those functions:
# ./tp_filter 6 12 2015
asprintf_expr_in_ints: id == 6 || id == 12 || id == 2015
asprintf_expr_not_in_ints: id != 6 && id != 12 && id != 2015
#
It'll be used with, for instance, perf_evsel__set_filter_in_ints(), that
will be used in turn to ask the kernel to filter out all raw_syscalls:*
except for the ones specified by the user via:
$ perf trace -e some,list,of,syscalls
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-jt07vfp6bd8y50c05j1t7hrn@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-07-02 23:48:23 +03:00
char * asprintf_expr_inout_ints ( const char * var , bool in , size_t nints , int * ints )
{
/*
* FIXME : replace this with an expression using log10 ( ) when we
* find a suitable implementation , maybe the one in the dvb drivers . . .
*
* " %s == %d || " = log10 ( MAXINT ) * 2 + 8 chars for the operators
*/
size_t size = nints * 28 + 1 ; /* \0 */
size_t i , printed = 0 ;
char * expr = malloc ( size ) ;
if ( expr ) {
const char * or_and = " || " , * eq_neq = " == " ;
char * e = expr ;
if ( ! in ) {
or_and = " && " ;
eq_neq = " != " ;
}
for ( i = 0 ; i < nints ; + + i ) {
if ( printed = = size )
goto out_err_overflow ;
if ( i > 0 )
printed + = snprintf ( e + printed , size - printed , " %s " , or_and ) ;
printed + = scnprintf ( e + printed , size - printed ,
" %s %s %d " , var , eq_neq , ints [ i ] ) ;
}
}
return expr ;
out_err_overflow :
free ( expr ) ;
return NULL ;
}