2007-07-18 05:37:02 +04:00
/*
* Helper function for splitting a string into an argv - like array .
*/
# include <linux/kernel.h>
# include <linux/ctype.h>
2009-12-15 05:01:06 +03:00
# include <linux/string.h>
2007-10-20 02:25:12 +04:00
# include <linux/slab.h>
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2007-07-18 05:37:02 +04:00
static int count_argc ( const char * str )
{
int count = 0 ;
2013-04-30 03:18:10 +04:00
bool was_space ;
2007-07-18 05:37:02 +04:00
2013-04-30 03:18:10 +04:00
for ( was_space = true ; * str ; str + + ) {
if ( isspace ( * str ) ) {
was_space = true ;
} else if ( was_space ) {
was_space = false ;
2007-07-18 05:37:02 +04:00
count + + ;
}
}
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 )
{
2013-04-30 03:18:10 +04:00
argv - - ;
kfree ( argv [ 0 ] ) ;
2007-07-18 05:37:02 +04:00
kfree ( argv ) ;
}
EXPORT_SYMBOL ( argv_free ) ;
/**
* argv_split - split a string at whitespace , returning an argv
* @ gfp : the GFP mask used to allocate memory
* @ 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 .
2013-04-30 03:18:10 +04:00
*
* The source string at ` str ' may be undergoing concurrent alteration via
* userspace sysctl activity ( at least ) . The argv_split ( ) implementation
* attempts to handle this gracefully by taking a local copy to work on .
2007-07-18 05:37:02 +04:00
*/
char * * argv_split ( gfp_t gfp , const char * str , int * argcp )
{
2013-04-30 03:18:10 +04:00
char * argv_str ;
bool was_space ;
char * * argv , * * argv_ret ;
int argc ;
argv_str = kstrndup ( str , KMALLOC_MAX_SIZE - 1 , gfp ) ;
if ( ! argv_str )
return NULL ;
argc = count_argc ( argv_str ) ;
argv = kmalloc ( sizeof ( * argv ) * ( argc + 2 ) , gfp ) ;
if ( ! argv ) {
kfree ( argv_str ) ;
return NULL ;
}
2007-07-18 05:37:02 +04:00
2013-04-30 03:18:10 +04:00
* argv = argv_str ;
argv_ret = + + argv ;
for ( was_space = true ; * argv_str ; argv_str + + ) {
if ( isspace ( * argv_str ) ) {
was_space = true ;
* argv_str = 0 ;
} else if ( was_space ) {
was_space = false ;
* argv + + = argv_str ;
2007-07-18 05:37:02 +04:00
}
}
2013-04-30 03:18:10 +04:00
* argv = NULL ;
2007-07-18 05:37:02 +04:00
2013-04-30 03:18:10 +04:00
if ( argcp )
* argcp = argc ;
return argv_ret ;
2007-07-18 05:37:02 +04:00
}
EXPORT_SYMBOL ( argv_split ) ;