2008-08-31 19:13:54 +04:00
/*
* Helpers for formatting and printing strings
*
* Copyright 31 August 2008 James Bottomley
2013-05-01 02:27:30 +04:00
* Copyright ( C ) 2013 , Intel Corporation
2008-08-31 19:13:54 +04:00
*/
# include <linux/kernel.h>
# include <linux/math64.h>
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2013-05-01 02:27:30 +04:00
# include <linux/ctype.h>
2008-08-31 19:13:54 +04:00
# include <linux/string_helpers.h>
/**
* string_get_size - get the size in the specified units
* @ size : The size to be converted
* @ units : units to use ( powers of 1000 or 1024 )
* @ buf : buffer to format to
* @ len : length of buffer
*
* This function returns a string formatted to 3 significant figures
* giving the size in the required units . Returns 0 on success or
* error on failure . @ buf is always zero terminated .
*
*/
int string_get_size ( u64 size , const enum string_size_units units ,
char * buf , int len )
{
2012-05-30 02:07:32 +04:00
static const char * units_10 [ ] = { " B " , " kB " , " MB " , " GB " , " TB " , " PB " ,
2008-08-31 19:13:54 +04:00
" EB " , " ZB " , " YB " , NULL } ;
2012-05-30 02:07:32 +04:00
static const char * units_2 [ ] = { " B " , " KiB " , " MiB " , " GiB " , " TiB " , " PiB " ,
2008-08-31 19:13:54 +04:00
" EiB " , " ZiB " , " YiB " , NULL } ;
2012-05-30 02:07:32 +04:00
static const char * * units_str [ ] = {
2008-08-31 19:13:54 +04:00
[ STRING_UNITS_10 ] = units_10 ,
[ STRING_UNITS_2 ] = units_2 ,
} ;
2012-05-30 02:07:32 +04:00
static const unsigned int divisor [ ] = {
2008-08-31 19:13:54 +04:00
[ STRING_UNITS_10 ] = 1000 ,
[ STRING_UNITS_2 ] = 1024 ,
} ;
int i , j ;
u64 remainder = 0 , sf_cap ;
char tmp [ 8 ] ;
tmp [ 0 ] = ' \0 ' ;
2008-10-14 22:34:21 +04:00
i = 0 ;
if ( size > = divisor [ units ] ) {
while ( size > = divisor [ units ] & & units_str [ units ] [ i ] ) {
remainder = do_div ( size , divisor [ units ] ) ;
i + + ;
}
2008-08-31 19:13:54 +04:00
2008-10-14 22:34:21 +04:00
sf_cap = size ;
for ( j = 0 ; sf_cap * 10 < 1000 ; j + + )
sf_cap * = 10 ;
2008-08-31 19:13:54 +04:00
2008-10-14 22:34:21 +04:00
if ( j ) {
remainder * = 1000 ;
do_div ( remainder , divisor [ units ] ) ;
snprintf ( tmp , sizeof ( tmp ) , " .%03lld " ,
( unsigned long long ) remainder ) ;
tmp [ j + 1 ] = ' \0 ' ;
}
2008-08-31 19:13:54 +04:00
}
2008-10-14 22:34:21 +04:00
snprintf ( buf , len , " %lld%s %s " , ( unsigned long long ) size ,
2008-08-31 19:13:54 +04:00
tmp , units_str [ units ] [ i ] ) ;
return 0 ;
}
EXPORT_SYMBOL ( string_get_size ) ;
2013-05-01 02:27:30 +04:00
static bool unescape_space ( char * * src , char * * dst )
{
char * p = * dst , * q = * src ;
switch ( * q ) {
case ' n ' :
* p = ' \n ' ;
break ;
case ' r ' :
* p = ' \r ' ;
break ;
case ' t ' :
* p = ' \t ' ;
break ;
case ' v ' :
* p = ' \v ' ;
break ;
case ' f ' :
* p = ' \f ' ;
break ;
default :
return false ;
}
* dst + = 1 ;
* src + = 1 ;
return true ;
}
static bool unescape_octal ( char * * src , char * * dst )
{
char * p = * dst , * q = * src ;
u8 num ;
if ( isodigit ( * q ) = = 0 )
return false ;
num = ( * q + + ) & 7 ;
while ( num < 32 & & isodigit ( * q ) & & ( q - * src < 3 ) ) {
num < < = 3 ;
num + = ( * q + + ) & 7 ;
}
* p = num ;
* dst + = 1 ;
* src = q ;
return true ;
}
static bool unescape_hex ( char * * src , char * * dst )
{
char * p = * dst , * q = * src ;
int digit ;
u8 num ;
if ( * q + + ! = ' x ' )
return false ;
num = digit = hex_to_bin ( * q + + ) ;
if ( digit < 0 )
return false ;
digit = hex_to_bin ( * q ) ;
if ( digit > = 0 ) {
q + + ;
num = ( num < < 4 ) | digit ;
}
* p = num ;
* dst + = 1 ;
* src = q ;
return true ;
}
static bool unescape_special ( char * * src , char * * dst )
{
char * p = * dst , * q = * src ;
switch ( * q ) {
case ' \" ' :
* p = ' \" ' ;
break ;
case ' \\ ' :
* p = ' \\ ' ;
break ;
case ' a ' :
* p = ' \a ' ;
break ;
case ' e ' :
* p = ' \e ' ;
break ;
default :
return false ;
}
* dst + = 1 ;
* src + = 1 ;
return true ;
}
int string_unescape ( char * src , char * dst , size_t size , unsigned int flags )
{
char * out = dst ;
while ( * src & & - - size ) {
if ( src [ 0 ] = = ' \\ ' & & src [ 1 ] ! = ' \0 ' & & size > 1 ) {
src + + ;
size - - ;
if ( flags & UNESCAPE_SPACE & &
unescape_space ( & src , & out ) )
continue ;
if ( flags & UNESCAPE_OCTAL & &
unescape_octal ( & src , & out ) )
continue ;
if ( flags & UNESCAPE_HEX & &
unescape_hex ( & src , & out ) )
continue ;
if ( flags & UNESCAPE_SPECIAL & &
unescape_special ( & src , & out ) )
continue ;
* out + + = ' \\ ' ;
}
* out + + = * src + + ;
}
* out = ' \0 ' ;
return out - dst ;
}
EXPORT_SYMBOL ( string_unescape ) ;