2005-04-17 02:20:36 +04:00
/*
* lib / parser . c - simple parser for mount , etc . options .
*
* This source code is licensed under the GNU General Public License ,
* Version 2. See the file COPYING for more details .
*/
# include <linux/ctype.h>
# include <linux/module.h>
# include <linux/parser.h>
# include <linux/slab.h>
# include <linux/string.h>
/**
* match_one : - Determines if a string matches a simple pattern
* @ s : the string to examine for presense of the pattern
* @ p : the string containing the pattern
* @ args : array of % MAX_OPT_ARGS & substring_t elements . Used to return match
* locations .
*
* Description : Determines if the pattern @ p is present in string @ s . Can only
* match extremely simple token = arg style patterns . If the pattern is found ,
* the location ( s ) of the arguments will be returned in the @ args array .
*/
2007-05-03 14:10:39 +04:00
static int match_one ( char * s , const char * p , substring_t args [ ] )
2005-04-17 02:20:36 +04:00
{
char * meta ;
int argc = 0 ;
if ( ! p )
return 1 ;
while ( 1 ) {
int len = - 1 ;
meta = strchr ( p , ' % ' ) ;
if ( ! meta )
return strcmp ( p , s ) = = 0 ;
if ( strncmp ( p , s , meta - p ) )
return 0 ;
s + = meta - p ;
p = meta + 1 ;
if ( isdigit ( * p ) )
2007-05-03 14:10:39 +04:00
len = simple_strtoul ( p , ( char * * ) & p , 10 ) ;
2005-04-17 02:20:36 +04:00
else if ( * p = = ' % ' ) {
if ( * s + + ! = ' % ' )
return 0 ;
p + + ;
continue ;
}
if ( argc > = MAX_OPT_ARGS )
return 0 ;
args [ argc ] . from = s ;
switch ( * p + + ) {
2009-12-15 05:01:08 +03:00
case ' s ' : {
size_t str_len = strlen ( s ) ;
if ( str_len = = 0 )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-12-15 05:01:08 +03:00
if ( len = = - 1 | | len > str_len )
len = str_len ;
2005-04-17 02:20:36 +04:00
args [ argc ] . to = s + len ;
break ;
2009-12-15 05:01:08 +03:00
}
2005-04-17 02:20:36 +04:00
case ' d ' :
simple_strtol ( s , & args [ argc ] . to , 0 ) ;
goto num ;
case ' u ' :
simple_strtoul ( s , & args [ argc ] . to , 0 ) ;
goto num ;
case ' o ' :
simple_strtoul ( s , & args [ argc ] . to , 8 ) ;
goto num ;
case ' x ' :
simple_strtoul ( s , & args [ argc ] . to , 16 ) ;
num :
if ( args [ argc ] . to = = args [ argc ] . from )
return 0 ;
break ;
default :
return 0 ;
}
s = args [ argc ] . to ;
argc + + ;
}
}
/**
* match_token : - Find a token ( and optional args ) in a string
* @ s : the string to examine for token / argument pairs
* @ table : match_table_t describing the set of allowed option tokens and the
* arguments that may be associated with them . Must be terminated with a
* & struct match_token whose pattern is set to the NULL pointer .
* @ args : array of % MAX_OPT_ARGS & substring_t elements . Used to return match
* locations .
*
* Description : Detects which if any of a set of token strings has been passed
* to it . Tokens can include up to MAX_OPT_ARGS instances of basic c - style
* format identifiers which will be taken into account when matching the
* tokens , and whose locations will be returned in the @ args array .
*/
2008-10-13 13:46:57 +04:00
int match_token ( char * s , const match_table_t table , substring_t args [ ] )
2005-04-17 02:20:36 +04:00
{
2007-05-03 14:10:39 +04:00
const struct match_token * p ;
2005-04-17 02:20:36 +04:00
for ( p = table ; ! match_one ( s , p - > pattern , args ) ; p + + )
;
return p - > token ;
}
/**
* match_number : scan a number in the given base from a substring_t
* @ s : substring to be scanned
* @ result : resulting integer on success
* @ base : base to use when converting string
*
* Description : Given a & substring_t and a base , attempts to parse the substring
* as a number in that base . On success , sets @ result to the integer represented
* by the string and returns 0. Returns either - ENOMEM or - EINVAL on failure .
*/
static int match_number ( substring_t * s , int * result , int base )
{
char * endp ;
char * buf ;
int ret ;
buf = kmalloc ( s - > to - s - > from + 1 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
memcpy ( buf , s - > from , s - > to - s - > from ) ;
buf [ s - > to - s - > from ] = ' \0 ' ;
* result = simple_strtol ( buf , & endp , base ) ;
ret = 0 ;
if ( endp = = buf )
ret = - EINVAL ;
kfree ( buf ) ;
return ret ;
}
/**
* match_int : - scan a decimal representation of an integer from a substring_t
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
* Description : Attempts to parse the & substring_t @ s as a decimal integer . On
* success , sets @ result to the integer represented by the string and returns 0.
* Returns either - ENOMEM or - EINVAL on failure .
*/
int match_int ( substring_t * s , int * result )
{
return match_number ( s , result , 0 ) ;
}
/**
* match_octal : - scan an octal representation of an integer from a substring_t
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
* Description : Attempts to parse the & substring_t @ s as an octal integer . On
* success , sets @ result to the integer represented by the string and returns
* 0. Returns either - ENOMEM or - EINVAL on failure .
*/
int match_octal ( substring_t * s , int * result )
{
return match_number ( s , result , 8 ) ;
}
/**
* match_hex : - scan a hex representation of an integer from a substring_t
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
* Description : Attempts to parse the & substring_t @ s as a hexadecimal integer .
* On success , sets @ result to the integer represented by the string and
* returns 0. Returns either - ENOMEM or - EINVAL on failure .
*/
int match_hex ( substring_t * s , int * result )
{
return match_number ( s , result , 16 ) ;
}
/**
2008-02-26 18:57:11 +03:00
* match_strlcpy : - Copy the characters from a substring_t to a sized buffer
* @ dest : where to copy to
* @ src : & substring_t to copy
* @ size : size of destination buffer
2005-04-17 02:20:36 +04:00
*
2008-02-26 18:57:11 +03:00
* Description : Copy the characters in & substring_t @ src to the
* c - style string @ dest . Copy no more than @ size - 1 characters , plus
* the terminating NUL . Return length of @ src .
2005-04-17 02:20:36 +04:00
*/
2008-02-26 18:57:11 +03:00
size_t match_strlcpy ( char * dest , const substring_t * src , size_t size )
2005-04-17 02:20:36 +04:00
{
2008-02-26 18:57:11 +03:00
size_t ret = src - > to - src - > from ;
if ( size ) {
size_t len = ret > = size ? size - 1 : ret ;
memcpy ( dest , src - > from , len ) ;
dest [ len ] = ' \0 ' ;
}
return ret ;
2005-04-17 02:20:36 +04:00
}
/**
* match_strdup : - allocate a new string with the contents of a substring_t
* @ s : & substring_t to copy
*
* Description : Allocates and returns a string filled with the contents of
* the & substring_t @ s . The caller is responsible for freeing the returned
* string with kfree ( ) .
*/
2007-05-03 14:10:39 +04:00
char * match_strdup ( const substring_t * s )
2005-04-17 02:20:36 +04:00
{
2008-02-26 18:57:11 +03:00
size_t sz = s - > to - s - > from + 1 ;
char * p = kmalloc ( sz , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( p )
2008-02-26 18:57:11 +03:00
match_strlcpy ( p , s , sz ) ;
2005-04-17 02:20:36 +04:00
return p ;
}
EXPORT_SYMBOL ( match_token ) ;
EXPORT_SYMBOL ( match_int ) ;
EXPORT_SYMBOL ( match_octal ) ;
EXPORT_SYMBOL ( match_hex ) ;
2008-02-26 18:57:11 +03:00
EXPORT_SYMBOL ( match_strlcpy ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( match_strdup ) ;