2011-03-23 02:34:40 +03:00
/*
* Convert integer string representation to an integer .
* If an integer doesn ' t fit into specified type , - E is returned .
*
* Integer starts with optional sign .
* kstrtou * ( ) functions do not accept sign " - " .
*
* Radix 0 means autodetection : leading " 0x " implies radix 16 ,
* leading " 0 " implies radix 8 , otherwise radix is 10.
* Autodetection hints work after optional sign , but not before .
*
* If - E is returned , result is not touched .
*/
# include <linux/ctype.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/math64.h>
# include <linux/module.h>
# include <linux/types.h>
static inline char _tolower ( const char c )
{
return c | 0x20 ;
}
static int _kstrtoull ( const char * s , unsigned int base , unsigned long long * res )
{
unsigned long long acc ;
int ok ;
if ( base = = 0 ) {
if ( s [ 0 ] = = ' 0 ' ) {
if ( _tolower ( s [ 1 ] ) = = ' x ' & & isxdigit ( s [ 2 ] ) )
base = 16 ;
else
base = 8 ;
} else
base = 10 ;
}
if ( base = = 16 & & s [ 0 ] = = ' 0 ' & & _tolower ( s [ 1 ] ) = = ' x ' )
s + = 2 ;
acc = 0 ;
ok = 0 ;
while ( * s ) {
unsigned int val ;
if ( ' 0 ' < = * s & & * s < = ' 9 ' )
val = * s - ' 0 ' ;
else if ( ' a ' < = _tolower ( * s ) & & _tolower ( * s ) < = ' f ' )
val = _tolower ( * s ) - ' a ' + 10 ;
2011-04-15 02:22:02 +04:00
else if ( * s = = ' \n ' & & * ( s + 1 ) = = ' \0 ' )
break ;
else
2011-03-23 02:34:40 +03:00
return - EINVAL ;
if ( val > = base )
return - EINVAL ;
if ( acc > div_u64 ( ULLONG_MAX - val , base ) )
return - ERANGE ;
acc = acc * base + val ;
ok = 1 ;
s + + ;
}
if ( ! ok )
return - EINVAL ;
* res = acc ;
return 0 ;
}
int kstrtoull ( const char * s , unsigned int base , unsigned long long * res )
{
if ( s [ 0 ] = = ' + ' )
s + + ;
return _kstrtoull ( s , base , res ) ;
}
EXPORT_SYMBOL ( kstrtoull ) ;
int kstrtoll ( const char * s , unsigned int base , long long * res )
{
unsigned long long tmp ;
int rv ;
if ( s [ 0 ] = = ' - ' ) {
rv = _kstrtoull ( s + 1 , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( ( long long ) ( - tmp ) > = 0 )
return - ERANGE ;
* res = - tmp ;
} else {
rv = kstrtoull ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( ( long long ) tmp < 0 )
return - ERANGE ;
* res = tmp ;
}
return 0 ;
}
EXPORT_SYMBOL ( kstrtoll ) ;
/* Internal, do not use. */
int _kstrtoul ( const char * s , unsigned int base , unsigned long * res )
{
unsigned long long tmp ;
int rv ;
rv = kstrtoull ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( unsigned long long ) ( unsigned long ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( _kstrtoul ) ;
/* Internal, do not use. */
int _kstrtol ( const char * s , unsigned int base , long * res )
{
long long tmp ;
int rv ;
rv = kstrtoll ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( long long ) ( long ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( _kstrtol ) ;
int kstrtouint ( const char * s , unsigned int base , unsigned int * res )
{
unsigned long long tmp ;
int rv ;
rv = kstrtoull ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( unsigned long long ) ( unsigned int ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtouint ) ;
int kstrtoint ( const char * s , unsigned int base , int * res )
{
long long tmp ;
int rv ;
rv = kstrtoll ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( long long ) ( int ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtoint ) ;
int kstrtou16 ( const char * s , unsigned int base , u16 * res )
{
unsigned long long tmp ;
int rv ;
rv = kstrtoull ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( unsigned long long ) ( u16 ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtou16 ) ;
int kstrtos16 ( const char * s , unsigned int base , s16 * res )
{
long long tmp ;
int rv ;
rv = kstrtoll ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( long long ) ( s16 ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtos16 ) ;
int kstrtou8 ( const char * s , unsigned int base , u8 * res )
{
unsigned long long tmp ;
int rv ;
rv = kstrtoull ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( unsigned long long ) ( u8 ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtou8 ) ;
int kstrtos8 ( const char * s , unsigned int base , s8 * res )
{
long long tmp ;
int rv ;
rv = kstrtoll ( s , base , & tmp ) ;
if ( rv < 0 )
return rv ;
if ( tmp ! = ( long long ) ( s8 ) tmp )
return - ERANGE ;
* res = tmp ;
return 0 ;
}
EXPORT_SYMBOL ( kstrtos8 ) ;