2014-07-08 10:07:00 +08:00
/******************************************************************************
*
* Module Name : utprint - Formatted printing routines
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2015-02-05 15:20:45 +08:00
* Copyright ( C ) 2000 - 2015 , Intel Corp .
2014-07-08 10:07:00 +08:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the " NO WARRANTY " disclaimer below
* ( " Disclaimer " ) and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution .
* 3. Neither the names of the above - listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES .
*/
# include <acpi/acpi.h>
# include "accommon.h"
# define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ( " utprint " )
# define ACPI_FORMAT_SIGN 0x01
# define ACPI_FORMAT_SIGN_PLUS 0x02
# define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04
# define ACPI_FORMAT_ZERO 0x08
# define ACPI_FORMAT_LEFT 0x10
# define ACPI_FORMAT_UPPER 0x20
# define ACPI_FORMAT_PREFIX 0x40
/* Local prototypes */
static acpi_size
acpi_ut_bound_string_length ( const char * string , acpi_size count ) ;
static char * acpi_ut_bound_string_output ( char * string , const char * end , char c ) ;
static char * acpi_ut_format_number ( char * string ,
char * end ,
u64 number ,
u8 base , s32 width , s32 precision , u8 type ) ;
static char * acpi_ut_put_number ( char * string , u64 number , u8 base , u8 upper ) ;
2014-07-08 10:08:13 +08:00
/* Module globals */
static const char acpi_gbl_lower_hex_digits [ ] = " 0123456789abcdef " ;
static const char acpi_gbl_upper_hex_digits [ ] = " 0123456789ABCDEF " ;
2014-07-08 10:07:00 +08:00
/*******************************************************************************
*
* FUNCTION : acpi_ut_bound_string_length
*
* PARAMETERS : string - String with boundary
* count - Boundary of the string
*
2014-07-08 10:08:13 +08:00
* RETURN : Length of the string . Less than or equal to Count .
2014-07-08 10:07:00 +08:00
*
* DESCRIPTION : Calculate the length of a string with boundary .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_size
acpi_ut_bound_string_length ( const char * string , acpi_size count )
{
u32 length = 0 ;
while ( * string & & count ) {
length + + ;
string + + ;
count - - ;
}
return ( length ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_bound_string_output
*
* PARAMETERS : string - String with boundary
* end - Boundary of the string
* c - Character to be output to the string
*
* RETURN : Updated position for next valid character
*
* DESCRIPTION : Output a character into a string with boundary check .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * acpi_ut_bound_string_output ( char * string , const char * end , char c )
{
if ( string < end ) {
* string = c ;
}
2014-07-08 10:08:13 +08:00
+ + string ;
2014-07-08 10:07:00 +08:00
return ( string ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_put_number
*
* PARAMETERS : string - Buffer to hold reverse - ordered string
* number - Integer to be converted
* base - Base of the integer
* upper - Whether or not using upper cased digits
*
* RETURN : Updated position for next valid character
*
* DESCRIPTION : Convert an integer into a string , note that , the string holds a
* reversed ordered number without the trailing zero .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * acpi_ut_put_number ( char * string , u64 number , u8 base , u8 upper )
{
const char * digits ;
u64 digit_index ;
char * pos ;
pos = string ;
2014-07-08 10:08:13 +08:00
digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits ;
2014-07-08 10:07:00 +08:00
if ( number = = 0 ) {
* ( pos + + ) = ' 0 ' ;
} else {
while ( number ) {
( void ) acpi_ut_divide ( number , base , & number ,
& digit_index ) ;
* ( pos + + ) = digits [ digit_index ] ;
}
}
2014-07-08 10:08:13 +08:00
/* *(Pos++) = '0'; */
2014-07-08 10:07:00 +08:00
return ( pos ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_scan_number
*
* PARAMETERS : string - String buffer
* number_ptr - Where the number is returned
*
* RETURN : Updated position for next valid character
*
* DESCRIPTION : Scan a string for a decimal integer .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const char * acpi_ut_scan_number ( const char * string , u64 * number_ptr )
{
u64 number = 0 ;
while ( ACPI_IS_DIGIT ( * string ) ) {
number * = 10 ;
number + = * ( string + + ) - ' 0 ' ;
}
2014-07-08 10:08:13 +08:00
* number_ptr = number ;
2014-07-08 10:07:00 +08:00
return ( string ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_print_number
*
* PARAMETERS : string - String buffer
* number - The number to be converted
*
* RETURN : Updated position for next valid character
*
* DESCRIPTION : Print a decimal integer into a string .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const char * acpi_ut_print_number ( char * string , u64 number )
{
char ascii_string [ 20 ] ;
const char * pos1 ;
char * pos2 ;
pos1 = acpi_ut_put_number ( ascii_string , number , 10 , FALSE ) ;
pos2 = string ;
while ( pos1 ! = ascii_string ) {
* ( pos2 + + ) = * ( - - pos1 ) ;
}
2014-07-08 10:08:13 +08:00
* pos2 = 0 ;
2014-07-08 10:07:00 +08:00
return ( string ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_format_number
*
* PARAMETERS : string - String buffer with boundary
* end - Boundary of the string
* number - The number to be converted
* base - Base of the integer
* width - Field width
* precision - Precision of the integer
* type - Special printing flags
*
* RETURN : Updated position for next valid character
*
* DESCRIPTION : Print an integer into a string with any base and any precision .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * acpi_ut_format_number ( char * string ,
char * end ,
u64 number ,
u8 base , s32 width , s32 precision , u8 type )
{
2014-07-30 12:20:26 +08:00
char * pos ;
2014-07-08 10:07:00 +08:00
char sign ;
char zero ;
u8 need_prefix ;
u8 upper ;
s32 i ;
char reversed_string [ 66 ] ;
2014-07-08 10:08:13 +08:00
/* Parameter validation */
2014-07-08 10:07:00 +08:00
if ( base < 2 | | base > 16 ) {
2014-07-08 10:08:13 +08:00
return ( NULL ) ;
2014-07-08 10:07:00 +08:00
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
if ( type & ACPI_FORMAT_LEFT ) {
type & = ~ ACPI_FORMAT_ZERO ;
}
need_prefix = ( ( type & ACPI_FORMAT_PREFIX )
& & base ! = 10 ) ? TRUE : FALSE ;
upper = ( type & ACPI_FORMAT_UPPER ) ? TRUE : FALSE ;
zero = ( type & ACPI_FORMAT_ZERO ) ? ' 0 ' : ' ' ;
/* Calculate size according to sign and prefix */
sign = ' \0 ' ;
if ( type & ACPI_FORMAT_SIGN ) {
if ( ( s64 ) number < 0 ) {
sign = ' - ' ;
number = - ( s64 ) number ;
width - - ;
} else if ( type & ACPI_FORMAT_SIGN_PLUS ) {
sign = ' + ' ;
width - - ;
} else if ( type & ACPI_FORMAT_SIGN_PLUS_SPACE ) {
sign = ' ' ;
width - - ;
}
}
if ( need_prefix ) {
width - - ;
if ( base = = 16 ) {
width - - ;
}
}
/* Generate full string in reverse order */
2014-07-30 12:20:26 +08:00
pos = acpi_ut_put_number ( reversed_string , number , base , upper ) ;
i = ACPI_PTR_DIFF ( pos , reversed_string ) ;
2014-07-08 10:07:00 +08:00
/* Printing 100 using %2d gives "100", not "00" */
if ( i > precision ) {
precision = i ;
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
width - = precision ;
/* Output the string */
if ( ! ( type & ( ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT ) ) ) {
while ( - - width > = 0 ) {
string = acpi_ut_bound_string_output ( string , end , ' ' ) ;
}
}
if ( sign ) {
string = acpi_ut_bound_string_output ( string , end , sign ) ;
}
if ( need_prefix ) {
string = acpi_ut_bound_string_output ( string , end , ' 0 ' ) ;
if ( base = = 16 ) {
string = acpi_ut_bound_string_output ( string , end ,
upper ? ' X ' : ' x ' ) ;
}
}
if ( ! ( type & ACPI_FORMAT_LEFT ) ) {
while ( - - width > = 0 ) {
string = acpi_ut_bound_string_output ( string , end , zero ) ;
}
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
while ( i < = - - precision ) {
string = acpi_ut_bound_string_output ( string , end , ' 0 ' ) ;
}
while ( - - i > = 0 ) {
string = acpi_ut_bound_string_output ( string , end ,
reversed_string [ i ] ) ;
}
while ( - - width > = 0 ) {
string = acpi_ut_bound_string_output ( string , end , ' ' ) ;
}
return ( string ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_vsnprintf
*
* PARAMETERS : string - String with boundary
* size - Boundary of the string
* format - Standard printf format
* args - Argument list
*
2014-07-08 10:08:13 +08:00
* RETURN : Number of bytes actually written .
2014-07-08 10:07:00 +08:00
*
* DESCRIPTION : Formatted output to a string using argument list pointer .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
acpi_ut_vsnprintf ( char * string ,
acpi_size size , const char * format , va_list args )
{
u8 base = 10 ;
u8 type = 0 ;
s32 width = - 1 ;
s32 precision = - 1 ;
char qualifier = 0 ;
u64 number ;
char * pos ;
char * end ;
char c ;
const char * s ;
const void * p ;
s32 length ;
int i ;
pos = string ;
end = string + size ;
for ( ; * format ; + + format ) {
if ( * format ! = ' % ' ) {
pos = acpi_ut_bound_string_output ( pos , end , * format ) ;
continue ;
}
/* Process sign */
do {
+ + format ;
if ( * format = = ' # ' ) {
type | = ACPI_FORMAT_PREFIX ;
} else if ( * format = = ' 0 ' ) {
type | = ACPI_FORMAT_ZERO ;
} else if ( * format = = ' + ' ) {
type | = ACPI_FORMAT_SIGN_PLUS ;
} else if ( * format = = ' ' ) {
type | = ACPI_FORMAT_SIGN_PLUS_SPACE ;
} else if ( * format = = ' - ' ) {
type | = ACPI_FORMAT_LEFT ;
} else {
break ;
}
} while ( 1 ) ;
/* Process width */
2014-07-30 12:21:07 +08:00
width = - 1 ;
2014-07-08 10:07:00 +08:00
if ( ACPI_IS_DIGIT ( * format ) ) {
format = acpi_ut_scan_number ( format , & number ) ;
width = ( s32 ) number ;
} else if ( * format = = ' * ' ) {
+ + format ;
width = va_arg ( args , int ) ;
if ( width < 0 ) {
width = - width ;
type | = ACPI_FORMAT_LEFT ;
}
}
/* Process precision */
2014-07-30 12:21:07 +08:00
precision = - 1 ;
2014-07-08 10:07:00 +08:00
if ( * format = = ' . ' ) {
+ + format ;
if ( ACPI_IS_DIGIT ( * format ) ) {
format = acpi_ut_scan_number ( format , & number ) ;
precision = ( s32 ) number ;
} else if ( * format = = ' * ' ) {
+ + format ;
precision = va_arg ( args , int ) ;
}
if ( precision < 0 ) {
precision = 0 ;
}
}
/* Process qualifier */
2014-07-30 12:21:07 +08:00
qualifier = - 1 ;
2014-07-08 10:07:00 +08:00
if ( * format = = ' h ' | | * format = = ' l ' | | * format = = ' L ' ) {
qualifier = * format ;
+ + format ;
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
if ( qualifier = = ' l ' & & * format = = ' l ' ) {
qualifier = ' L ' ;
+ + format ;
}
}
switch ( * format ) {
case ' % ' :
pos = acpi_ut_bound_string_output ( pos , end , ' % ' ) ;
continue ;
case ' c ' :
if ( ! ( type & ACPI_FORMAT_LEFT ) ) {
while ( - - width > 0 ) {
pos =
acpi_ut_bound_string_output ( pos ,
end ,
' ' ) ;
}
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
c = ( char ) va_arg ( args , int ) ;
pos = acpi_ut_bound_string_output ( pos , end , c ) ;
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
while ( - - width > 0 ) {
pos =
acpi_ut_bound_string_output ( pos , end , ' ' ) ;
}
continue ;
case ' s ' :
s = va_arg ( args , char * ) ;
if ( ! s ) {
s = " <NULL> " ;
}
length = acpi_ut_bound_string_length ( s , precision ) ;
if ( ! ( type & ACPI_FORMAT_LEFT ) ) {
while ( length < width - - ) {
pos =
acpi_ut_bound_string_output ( pos ,
end ,
' ' ) ;
}
}
for ( i = 0 ; i < length ; + + i ) {
pos = acpi_ut_bound_string_output ( pos , end , * s ) ;
+ + s ;
}
while ( length < width - - ) {
pos =
acpi_ut_bound_string_output ( pos , end , ' ' ) ;
}
continue ;
case ' o ' :
base = 8 ;
break ;
case ' X ' :
type | = ACPI_FORMAT_UPPER ;
case ' x ' :
base = 16 ;
break ;
case ' d ' :
case ' i ' :
type | = ACPI_FORMAT_SIGN ;
case ' u ' :
break ;
case ' p ' :
if ( width = = - 1 ) {
width = 2 * sizeof ( void * ) ;
type | = ACPI_FORMAT_ZERO ;
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
p = va_arg ( args , void * ) ;
pos = acpi_ut_format_number ( pos , end ,
2014-07-08 10:08:13 +08:00
ACPI_TO_INTEGER ( p ) , 16 ,
width , precision , type ) ;
2014-07-08 10:07:00 +08:00
continue ;
default :
pos = acpi_ut_bound_string_output ( pos , end , ' % ' ) ;
if ( * format ) {
pos =
acpi_ut_bound_string_output ( pos , end ,
* format ) ;
} else {
- - format ;
}
continue ;
}
if ( qualifier = = ' L ' ) {
number = va_arg ( args , u64 ) ;
if ( type & ACPI_FORMAT_SIGN ) {
number = ( s64 ) number ;
}
} else if ( qualifier = = ' l ' ) {
number = va_arg ( args , unsigned long ) ;
if ( type & ACPI_FORMAT_SIGN ) {
number = ( s32 ) number ;
}
} else if ( qualifier = = ' h ' ) {
number = ( u16 ) va_arg ( args , int ) ;
if ( type & ACPI_FORMAT_SIGN ) {
number = ( s16 ) number ;
}
} else {
number = va_arg ( args , unsigned int ) ;
if ( type & ACPI_FORMAT_SIGN ) {
number = ( signed int ) number ;
}
}
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
pos = acpi_ut_format_number ( pos , end , number , base ,
width , precision , type ) ;
}
if ( size > 0 ) {
if ( pos < end ) {
* pos = ' \0 ' ;
} else {
end [ - 1 ] = ' \0 ' ;
}
}
return ( ACPI_PTR_DIFF ( pos , string ) ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_snprintf
*
* PARAMETERS : string - String with boundary
* size - Boundary of the string
* Format , . . . - Standard printf format
*
2014-07-08 10:08:13 +08:00
* RETURN : Number of bytes actually written .
2014-07-08 10:07:00 +08:00
*
* DESCRIPTION : Formatted output to a string .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int acpi_ut_snprintf ( char * string , acpi_size size , const char * format , . . . )
{
va_list args ;
int length ;
va_start ( args , format ) ;
length = acpi_ut_vsnprintf ( string , size , format , args ) ;
va_end ( args ) ;
return ( length ) ;
}
# ifdef ACPI_APPLICATION
/*******************************************************************************
*
* FUNCTION : acpi_ut_file_vprintf
*
* PARAMETERS : file - File descriptor
* format - Standard printf format
* args - Argument list
*
2014-07-08 10:08:13 +08:00
* RETURN : Number of bytes actually written .
2014-07-08 10:07:00 +08:00
*
* DESCRIPTION : Formatted output to a file using argument list pointer .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int acpi_ut_file_vprintf ( ACPI_FILE file , const char * format , va_list args )
{
acpi_cpu_flags flags ;
int length ;
flags = acpi_os_acquire_lock ( acpi_gbl_print_lock ) ;
length = acpi_ut_vsnprintf ( acpi_gbl_print_buffer ,
sizeof ( acpi_gbl_print_buffer ) , format , args ) ;
2014-07-08 10:08:13 +08:00
2014-07-08 10:07:00 +08:00
( void ) acpi_os_write_file ( file , acpi_gbl_print_buffer , length , 1 ) ;
acpi_os_release_lock ( acpi_gbl_print_lock , flags ) ;
return ( length ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ut_file_printf
*
* PARAMETERS : file - File descriptor
* Format , . . . - Standard printf format
*
2014-07-08 10:08:13 +08:00
* RETURN : Number of bytes actually written .
2014-07-08 10:07:00 +08:00
*
* DESCRIPTION : Formatted output to a file .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int acpi_ut_file_printf ( ACPI_FILE file , const char * format , . . . )
{
va_list args ;
int length ;
va_start ( args , format ) ;
length = acpi_ut_file_vprintf ( file , format , args ) ;
va_end ( args ) ;
return ( length ) ;
}
# endif