@ -35,11 +35,18 @@
# include <cmath>
# include <cstdarg>
# ifdef _WIN32
# ifdef __MINGW32__
# if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
# endif
# endif
# if FMT_USE_WINDOWS_H
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
# endif
using fmt : : internal : : Arg ;
@ -88,13 +95,14 @@ using fmt::internal::Arg;
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static inline fmt : : internal : : N one < > strerror_r ( int , char * , . . . ) {
return fmt : : internal : : N one < > ( ) ;
static inline fmt : : internal : : N ull < > strerror_r ( int , char * , . . . ) {
return fmt : : internal : : N ull < > ( ) ;
}
static inline fmt : : internal : : N one < > strerror_s ( char * , std : : size_t , . . . ) {
return fmt : : internal : : N one < > ( ) ;
static inline fmt : : internal : : N ull < > strerror_s ( char * , std : : size_t , . . . ) {
return fmt : : internal : : N ull < > ( ) ;
}
namespace fmt {
namespace {
# ifndef _MSC_VER
@ -125,6 +133,7 @@ struct IntChecker {
unsigned max = INT_MAX ;
return value < = max ;
}
static bool fits_in_int ( bool ) { return true ; }
} ;
template < >
@ -150,7 +159,7 @@ typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// Buffer should be at least of size 1.
int safe_strerror (
int error_code , char * & buffer , std : : size_t buffer_size ) FMT_NOEXCEPT {
assert ( buffer ! = 0 & & buffer_size ! = 0 ) ;
FMT_ASSERT ( buffer ! = 0 & & buffer_size ! = 0 , " invalid buffer " ) ;
class StrError {
private :
@ -177,7 +186,7 @@ int safe_strerror(
}
// Handle the case when strerror_r is not available.
int handle ( fmt : : internal : : N one < > ) {
int handle ( fmt : : internal : : N ull < > ) {
return fallback ( strerror_s ( buffer_ , buffer_size_ , error_code_ ) ) ;
}
@ -189,17 +198,20 @@ int safe_strerror(
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback ( fmt : : internal : : N one < > ) {
int fallback ( fmt : : internal : : N ull < > ) {
errno = 0 ;
buffer_ = strerror ( error_code_ ) ;
return errno ;
}
public :
StrError ( int err or _code, char * & buf fer , std : : size_t buf fer _size)
: error_code_ ( err or _code) , buffer_ ( buf fer ) , buffer_size_ ( buf fer _size) { }
StrError ( int err _code, char * & buf , std : : size_t buf _size)
: error_code_ ( err _code) , buffer_ ( buf ) , buffer_size_ ( buf _size) { }
int run ( ) { return handle ( strerror_r ( error_code_ , buffer_ , buffer_size_ ) ) ; }
int run ( ) {
strerror_r ( 0 , 0 , " " ) ; // Suppress a warning about unused strerror_r.
return handle ( strerror_r ( error_code_ , buffer_ , buffer_size_ ) ) ;
}
} ;
return StrError ( error_code , buffer , buffer_size ) . run ( ) ;
}
@ -259,6 +271,11 @@ int parse_nonnegative_int(const Char *&s) {
return value ;
}
template < typename Char >
inline bool is_name_start ( Char c ) {
return ( ' a ' < = c & & c < = ' z ' ) | | ( ' A ' < = c & & c < = ' Z ' ) | | ' _ ' = = c ;
}
inline void require_numeric_argument ( const Arg & arg , char spec ) {
if ( arg . type > Arg : : LAST_NUMERIC_TYPE ) {
std : : string message =
@ -379,24 +396,139 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
arg_ . int_value = static_cast < char > ( value ) ;
}
} ;
} // namespace
namespace internal {
template < typename Impl , typename Char >
class BasicArgFormatter : public ArgVisitor < Impl , void > {
private :
BasicWriter < Char > & writer_ ;
FormatSpec & spec_ ;
FMT_DISALLOW_COPY_AND_ASSIGN ( BasicArgFormatter ) ;
protected :
BasicWriter < Char > & writer ( ) { return writer_ ; }
const FormatSpec & spec ( ) const { return spec_ ; }
public :
BasicArgFormatter ( BasicWriter < Char > & w , FormatSpec & s )
: writer_ ( w ) , spec_ ( s ) { }
template < typename T >
void visit_any_int ( T value ) { writer_ . write_int ( value , spec_ ) ; }
template < typename T >
void visit_any_double ( T value ) { writer_ . write_double ( value , spec_ ) ; }
void visit_bool ( bool value ) {
if ( spec_ . type_ ) {
writer_ . write_int ( value , spec_ ) ;
return ;
}
const char * str_value = value ? " true " : " false " ;
Arg : : StringValue < char > str = { str_value , strlen ( str_value ) } ;
writer_ . write_str ( str , spec_ ) ;
}
void visit_char ( int value ) {
if ( spec_ . type_ & & spec_ . type_ ! = ' c ' ) {
spec_ . flags_ | = CHAR_FLAG ;
writer_ . write_int ( value , spec_ ) ;
return ;
}
if ( spec_ . align_ = = ALIGN_NUMERIC | | spec_ . flags_ ! = 0 )
FMT_THROW ( FormatError ( " invalid format specifier for char " ) ) ;
typedef typename BasicWriter < Char > : : CharPtr CharPtr ;
Char fill = internal : : CharTraits < Char > : : cast ( spec_ . fill ( ) ) ;
CharPtr out = CharPtr ( ) ;
if ( spec_ . width_ > 1 ) {
out = writer_ . grow_buffer ( spec_ . width_ ) ;
if ( spec_ . align_ = = ALIGN_RIGHT ) {
std : : fill_n ( out , spec_ . width_ - 1 , fill ) ;
out + = spec_ . width_ - 1 ;
} else if ( spec_ . align_ = = ALIGN_CENTER ) {
out = writer_ . fill_padding ( out , spec_ . width_ , 1 , fill ) ;
} else {
std : : fill_n ( out + 1 , spec_ . width_ - 1 , fill ) ;
}
} else {
out = writer_ . grow_buffer ( 1 ) ;
}
* out = internal : : CharTraits < Char > : : cast ( value ) ;
}
void visit_string ( Arg : : StringValue < char > value ) {
writer_ . write_str ( value , spec_ ) ;
}
using ArgVisitor < Impl , void > : : visit_wstring ;
void visit_wstring ( Arg : : StringValue < Char > value ) {
writer_ . write_str ( value , spec_ ) ;
}
void visit_pointer ( const void * value ) {
if ( spec_ . type_ & & spec_ . type_ ! = ' p ' )
report_unknown_type ( spec_ . type_ , " pointer " ) ;
spec_ . flags_ = HASH_FLAG ;
spec_ . type_ = ' x ' ;
writer_ . write_int ( reinterpret_cast < uintptr_t > ( value ) , spec_ ) ;
}
} ;
// This function template is used to prevent compile errors when handling
// incompatible string arguments, e.g. handling a wide string in a narrow
// string formatter.
// An argument formatter.
template < typename Char >
Arg : : StringValue < Char > ignore_incompatible_str ( Arg : : StringValue < wchar_t > ) ;
class ArgFormatter : public BasicArgFormatter < ArgFormatter < Char > , Char > {
private :
BasicFormatter < Char > & formatter_ ;
const Char * format_ ;
template < >
inline Arg : : StringValue < char > ignore_incompatible_str (
Arg : : StringValue < wchar_t > ) { return Arg : : StringValue < char > ( ) ; }
public :
ArgFormatter ( BasicFormatter < Char > & f , FormatSpec & s , const Char * fmt )
: BasicArgFormatter < ArgFormatter < Char > , Char > ( f . writer ( ) , s ) ,
formatter_ ( f ) , format_ ( fmt ) { }
template < >
inline Arg : : StringValue < wchar_t > ignore_incompatible_str (
Arg : : StringValue < wchar_t > s ) { return s ; }
} // namespace
void visit_custom ( Arg : : CustomValue c ) {
c . format ( & formatter_ , c . value , & format_ ) ;
}
} ;
template < typename Char >
class PrintfArgFormatter :
public BasicArgFormatter < PrintfArgFormatter < Char > , Char > {
public :
PrintfArgFormatter ( BasicWriter < Char > & w , FormatSpec & s )
: BasicArgFormatter < PrintfArgFormatter < Char > , Char > ( w , s ) { }
void visit_char ( int value ) {
const FormatSpec & fmt_spec = this - > spec ( ) ;
BasicWriter < Char > & w = this - > writer ( ) ;
if ( fmt_spec . type_ & & fmt_spec . type_ ! = ' c ' )
w . write_int ( value , fmt_spec ) ;
typedef typename BasicWriter < Char > : : CharPtr CharPtr ;
CharPtr out = CharPtr ( ) ;
if ( fmt_spec . width_ > 1 ) {
Char fill = ' ' ;
out = w . grow_buffer ( fmt_spec . width_ ) ;
if ( fmt_spec . align_ ! = ALIGN_LEFT ) {
std : : fill_n ( out , fmt_spec . width_ - 1 , fill ) ;
out + = fmt_spec . width_ - 1 ;
} else {
std : : fill_n ( out + 1 , fmt_spec . width_ - 1 , fill ) ;
}
} else {
out = w . grow_buffer ( 1 ) ;
}
* out = static_cast < Char > ( value ) ;
}
} ;
} // namespace internal
} // namespace fmt
FMT_FUNC void fmt : : SystemError : : init (
int err_code , StringRef format_str , ArgList args ) {
int err_code , C StringRef format_str , ArgList args ) {
error_code_ = err_code ;
MemoryWriter w ;
internal : : format_system_error ( w , err_code , format ( format_str , args ) ) ;
@ -477,19 +609,23 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
static_cast < unsigned > ( code ) , type ) ) ) ;
}
# if def _WIN32
# if FMT_USE_WINDOWS_H
FMT_FUNC fmt : : internal : : UTF8ToUTF16 : : UTF8ToUTF16 ( fmt : : StringRef s ) {
int length = MultiByteToWideChar (
CP_UTF8 , MB_ERR_INVALID_CHARS , s . c_str ( ) , - 1 , 0 , 0 ) ;
static const char ERROR_MSG [ ] = " cannot convert string from UTF-8 to UTF-16 " ;
if ( s . size ( ) > INT_MAX )
FMT_THROW ( WindowsError ( ERROR_INVALID_PARAMETER , ERROR_MSG ) ) ;
int s_size = static_cast < int > ( s . size ( ) ) ;
int length = MultiByteToWideChar (
CP_UTF8 , MB_ERR_INVALID_CHARS , s . data ( ) , s_size , 0 , 0 ) ;
if ( length = = 0 )
FMT_THROW ( WindowsError ( GetLastError ( ) , ERROR_MSG ) ) ;
buffer_ . resize ( length ) ;
buffer_ . resize ( length + 1 ) ;
length = MultiByteToWideChar (
CP_UTF8 , MB_ERR_INVALID_CHARS , s . c_str ( ) , - 1 , & buffer_ [ 0 ] , length ) ;
CP_UTF8 , MB_ERR_INVALID_CHARS , s . data( ) , s_size , & buffer_ [ 0 ] , length ) ;
if ( length = = 0 )
FMT_THROW ( WindowsError ( GetLastError ( ) , ERROR_MSG ) ) ;
buffer_ [ length ] = 0 ;
}
FMT_FUNC fmt : : internal : : UTF16ToUTF8 : : UTF16ToUTF8 ( fmt : : WStringRef s ) {
@ -500,19 +636,23 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
}
FMT_FUNC int fmt : : internal : : UTF16ToUTF8 : : convert ( fmt : : WStringRef s ) {
int length = WideCharToMultiByte ( CP_UTF8 , 0 , s . c_str ( ) , - 1 , 0 , 0 , 0 , 0 ) ;
if ( s . size ( ) > INT_MAX )
return ERROR_INVALID_PARAMETER ;
int s_size = static_cast < int > ( s . size ( ) ) ;
int length = WideCharToMultiByte ( CP_UTF8 , 0 , s . data ( ) , s_size , 0 , 0 , 0 , 0 ) ;
if ( length = = 0 )
return GetLastError ( ) ;
buffer_ . resize ( length ) ;
buffer_ . resize ( length + 1 ) ;
length = WideCharToMultiByte (
CP_UTF8 , 0 , s . c_str( ) , - 1 , & buffer_ [ 0 ] , length , 0 , 0 ) ;
CP_UTF8 , 0 , s . data( ) , s_size , & buffer_ [ 0 ] , length , 0 , 0 ) ;
if ( length = = 0 )
return GetLastError ( ) ;
buffer_ [ length ] = 0 ;
return 0 ;
}
FMT_FUNC void fmt : : WindowsError : : init (
int err_code , StringRef format_str , ArgList args ) {
int err_code , C StringRef format_str , ArgList args ) {
error_code_ = err_code ;
MemoryWriter w ;
internal : : format_windows_error ( w , err_code , format ( format_str , args ) ) ;
@ -520,30 +660,6 @@ FMT_FUNC void fmt::WindowsError::init(
base = std : : runtime_error ( w . str ( ) ) ;
}
# endif
FMT_FUNC void fmt : : internal : : format_system_error (
fmt : : Writer & out , int error_code ,
fmt : : StringRef message ) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer < char , INLINE_BUFFER_SIZE > buffer ;
buffer . resize ( INLINE_BUFFER_SIZE ) ;
for ( ; ; ) {
char * system_message = & buffer [ 0 ] ;
int result = safe_strerror ( error_code , system_message , buffer . size ( ) ) ;
if ( result = = 0 ) {
out < < message < < " : " < < system_message ;
return ;
}
if ( result ! = ERANGE )
break ; // Can't get error message, report error code instead.
buffer . resize ( buffer . size ( ) * 2 ) ;
}
} FMT_CATCH ( . . . ) { }
format_error_code ( out , error_code , message ) ;
}
# ifdef _WIN32
FMT_FUNC void fmt : : internal : : format_windows_error (
fmt : : Writer & out , int error_code ,
fmt : : StringRef message ) FMT_NOEXCEPT {
@ -572,81 +688,74 @@ FMT_FUNC void fmt::internal::format_windows_error(
} FMT_CATCH ( . . . ) { }
format_error_code ( out , error_code , message ) ;
}
# endif
// An argument formatter.
template < typename Char >
class fmt : : internal : : ArgFormatter :
public fmt : : internal : : ArgVisitor < fmt : : internal : : ArgFormatter < Char > , void > {
private :
fmt : : BasicFormatter < Char > & formatter_ ;
fmt : : BasicWriter < Char > & writer_ ;
fmt : : FormatSpec & spec_ ;
const Char * format_ ;
FMT_DISALLOW_COPY_AND_ASSIGN ( ArgFormatter ) ;
public :
ArgFormatter (
fmt : : BasicFormatter < Char > & f , fmt : : FormatSpec & s , const Char * fmt )
: formatter_ ( f ) , writer_ ( f . writer ( ) ) , spec_ ( s ) , format_ ( fmt ) { }
# endif // FMT_USE_WINDOWS_H
template < typename T >
void visit_any_int ( T value ) { writer_ . write_int ( value , spec_ ) ; }
template < typename T >
void visit_any_double ( T value ) { writer_ . write_double ( value , spec_ ) ; }
void visit_char ( int value ) {
if ( spec_ . type_ & & spec_ . type_ ! = ' c ' ) {
spec_ . flags_ | = CHAR_FLAG ;
writer_ . write_int ( value , spec_ ) ;
FMT_FUNC void fmt : : internal : : format_system_error (
fmt : : Writer & out , int error_code ,
fmt : : StringRef message ) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer < char , INLINE_BUFFER_SIZE > buffer ;
buffer . resize ( INLINE_BUFFER_SIZE ) ;
for ( ; ; ) {
char * system_message = & buffer [ 0 ] ;
int result = safe_strerror ( error_code , system_message , buffer . size ( ) ) ;
if ( result = = 0 ) {
out < < message < < " : " < < system_message ;
return ;
}
if ( spec_ . align_ = = ALIGN_NUMERIC | | spec_ . flags_ ! = 0 )
FMT_THROW ( FormatError ( " invalid format specifier for char " ) ) ;
typedef typename fmt : : BasicWriter < Char > : : CharPtr CharPtr ;
Char fill = static_cast < Char > ( spec_ . fill ( ) ) ;
if ( spec_ . precision_ = = 0 ) {
std : : fill_n ( writer_ . grow_buffer ( spec_ . width_ ) , spec_ . width_ , fill ) ;
return ;
if ( result ! = ERANGE )
break ; // Can't get error message, report error code instead.
buffer . resize ( buffer . size ( ) * 2 ) ;
}
CharPtr out = CharPtr ( ) ;
if ( spec_ . width_ > 1 ) {
out = writer_ . grow_buffer ( spec_ . width_ ) ;
if ( spec_ . align_ = = fmt : : ALIGN_RIGHT ) {
std : : fill_n ( out , spec_ . width_ - 1 , fill ) ;
out + = spec_ . width_ - 1 ;
} else if ( spec_ . align_ = = fmt : : ALIGN_CENTER ) {
out = writer_ . fill_padding ( out , spec_ . width_ , 1 , fill ) ;
} else {
std : : fill_n ( out + 1 , spec_ . width_ - 1 , fill ) ;
} FMT_CATCH ( . . . ) { }
format_error_code ( out , error_code , message ) ;
}
template < typename Char >
void fmt : : internal : : ArgMap < Char > : : init ( const ArgList & args ) {
if ( ! map_ . empty ( ) )
return ;
typedef internal : : NamedArg < Char > NamedArg ;
const NamedArg * named_arg = 0 ;
bool use_values =
args . type ( ArgList : : MAX_PACKED_ARGS - 1 ) = = internal : : Arg : : NONE ;
if ( use_values ) {
for ( unsigned i = 0 ; /*nothing*/ ; + + i ) {
internal : : Arg : : Type arg_type = args . type ( i ) ;
switch ( arg_type ) {
case internal : : Arg : : NONE :
return ;
case internal : : Arg : : NAMED_ARG :
named_arg = static_cast < const NamedArg * > ( args . values_ [ i ] . pointer ) ;
map_ . insert ( Pair ( named_arg - > name , * named_arg ) ) ;
break ;
default :
/*nothing*/ ;
}
} else {
out = writer_ . grow_buffer ( 1 ) ;
}
* out = static_cast < Char > ( value ) ;
return ;
}
void visit_string ( Arg : : StringValue < char > value ) {
writer_ . write_str ( value , spec_ ) ;
for ( unsigned i = 0 ; i ! = ArgList : : MAX_PACKED_ARGS ; + + i ) {
internal : : Arg : : Type arg_type = args . type ( i ) ;
if ( arg_type = = internal : : Arg : : NAMED_ARG ) {
named_arg = static_cast < const NamedArg * > ( args . args_ [ i ] . pointer ) ;
map_ . insert ( Pair ( named_arg - > name , * named_arg ) ) ;
}
void visit_wstring ( Arg : : StringValue < wchar_t > value ) {
writer_ . write_str ( ignore_incompatible_str < Char > ( value ) , spec_ ) ;
}
void visit_pointer ( const void * value ) {
if ( spec_ . type_ & & spec_ . type_ ! = ' p ' )
fmt : : internal : : report_unknown_type ( spec_ . type_ , " pointer " ) ;
spec_ . flags_ = fmt : : HASH_FLAG ;
spec_ . type_ = ' x ' ;
writer_ . write_int ( reinterpret_cast < uintptr_t > ( value ) , spec_ ) ;
for ( unsigned i = ArgList : : MAX_PACKED_ARGS ; /*nothing*/ ; + + i ) {
switch ( args . args_ [ i ] . type ) {
case internal : : Arg : : NONE :
return ;
case internal : : Arg : : NAMED_ARG :
named_arg = static_cast < const NamedArg * > ( args . args_ [ i ] . pointer ) ;
map_ . insert ( Pair ( named_arg - > name , * named_arg ) ) ;
break ;
default :
/*nothing*/ ;
}
void visit_custom ( Arg : : CustomValue c ) {
c . format ( & formatter_ , c . value , & format_ ) ;
}
} ;
}
template < typename Char >
void fmt : : internal : : FixedBuffer < Char > : : grow ( std : : size_t ) {
@ -675,6 +784,19 @@ void fmt::BasicWriter<Char>::write_str(
write_str ( str_value , str_size , spec ) ;
}
template < typename Char >
inline Arg fmt : : BasicFormatter < Char > : : get_arg (
BasicStringRef < Char > arg_name , const char * & error ) {
if ( check_no_auto_index ( error ) ) {
map_ . init ( args ( ) ) ;
const Arg * arg = map_ . find ( arg_name ) ;
if ( arg )
return * arg ;
error = " argument not found " ;
}
return Arg ( ) ;
}
template < typename Char >
inline Arg fmt : : BasicFormatter < Char > : : parse_arg_index ( const Char * & s ) {
const char * error = 0 ;
@ -687,11 +809,33 @@ inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
return arg ;
}
template < typename Char >
inline Arg fmt : : BasicFormatter < Char > : : parse_arg_name ( const Char * & s ) {
assert ( is_name_start ( * s ) ) ;
const Char * start = s ;
Char c ;
do {
c = * + + s ;
} while ( is_name_start ( c ) | | ( ' 0 ' < = c & & c < = ' 9 ' ) ) ;
const char * error = 0 ;
Arg arg = get_arg ( fmt : : BasicStringRef < Char > ( start , s - start ) , error ) ;
if ( error )
FMT_THROW ( fmt : : FormatError ( error ) ) ;
return arg ;
}
FMT_FUNC Arg fmt : : internal : : FormatterBase : : do_get_arg (
unsigned arg_index , const char * & error ) {
Arg arg = args_ [ arg_index ] ;
if ( arg . type = = Arg : : NONE )
switch ( arg . type ) {
case Arg : : NONE :
error = " argument index out of range " ;
break ;
case Arg : : NAMED_ARG :
arg = * static_cast < const internal : : Arg * > ( arg . pointer ) ;
default :
/*nothing*/ ;
}
return arg ;
}
@ -702,14 +846,19 @@ inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
return Arg ( ) ;
}
inline bool fmt : : internal : : FormatterBase : : check_no_auto_index (
const char * & error ) {
if ( next_arg_index_ > 0 ) {
error = " cannot switch from automatic to manual argument indexing " ;
return false ;
}
next_arg_index_ = - 1 ;
return true ;
}
inline Arg fmt : : internal : : FormatterBase : : get_arg (
unsigned arg_index , const char * & error ) {
if ( next_arg_index_ < = 0 ) {
next_arg_index_ = - 1 ;
return do_get_arg ( arg_index , error ) ;
}
error = " cannot switch from automatic to manual argument indexing " ;
return Arg ( ) ;
return check_no_auto_index ( error ) ? do_get_arg ( arg_index , error ) : Arg ( ) ;
}
template < typename Char >
@ -787,10 +936,8 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
template < typename Char >
void fmt : : internal : : PrintfFormatter < Char > : : format (
BasicWriter < Char > & writer , BasicStringRef < Char > format_str ,
const ArgList & args ) {
BasicWriter < Char > & writer , BasicCStringRef < Char > format_str ) {
const Char * start = format_str . c_str ( ) ;
set_args ( args ) ;
const Char * s = start ;
while ( * s ) {
Char c = * s + + ;
@ -881,73 +1028,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
start = s ;
// Format argument.
switch ( arg . type ) {
case Arg : : INT :
writer . write_int ( arg . int_value , spec ) ;
break ;
case Arg : : UINT :
writer . write_int ( arg . uint_value , spec ) ;
break ;
case Arg : : LONG_LONG :
writer . write_int ( arg . long_long_value , spec ) ;
break ;
case Arg : : ULONG_LONG :
writer . write_int ( arg . ulong_long_value , spec ) ;
break ;
case Arg : : CHAR : {
if ( spec . type_ & & spec . type_ ! = ' c ' )
writer . write_int ( arg . int_value , spec ) ;
typedef typename BasicWriter < Char > : : CharPtr CharPtr ;
CharPtr out = CharPtr ( ) ;
if ( spec . width_ > 1 ) {
Char fill = ' ' ;
out = writer . grow_buffer ( spec . width_ ) ;
if ( spec . align_ ! = ALIGN_LEFT ) {
std : : fill_n ( out , spec . width_ - 1 , fill ) ;
out + = spec . width_ - 1 ;
} else {
std : : fill_n ( out + 1 , spec . width_ - 1 , fill ) ;
}
} else {
out = writer . grow_buffer ( 1 ) ;
}
* out = static_cast < Char > ( arg . int_value ) ;
break ;
}
case Arg : : DOUBLE :
writer . write_double ( arg . double_value , spec ) ;
break ;
case Arg : : LONG_DOUBLE :
writer . write_double ( arg . long_double_value , spec ) ;
break ;
case Arg : : CSTRING :
arg . string . size = 0 ;
writer . write_str ( arg . string , spec ) ;
break ;
case Arg : : STRING :
writer . write_str ( arg . string , spec ) ;
break ;
case Arg : : WSTRING :
writer . write_str ( ignore_incompatible_str < Char > ( arg . wstring ) , spec ) ;
break ;
case Arg : : POINTER :
if ( spec . type_ & & spec . type_ ! = ' p ' )
internal : : report_unknown_type ( spec . type_ , " pointer " ) ;
spec . flags_ = HASH_FLAG ;
spec . type_ = ' x ' ;
writer . write_int ( reinterpret_cast < uintptr_t > ( arg . pointer ) , spec ) ;
break ;
case Arg : : CUSTOM : {
if ( spec . type_ )
internal : : report_unknown_type ( spec . type_ , " object " ) ;
const void * str_format = " s " ;
arg . custom . format ( & writer , arg . custom . value , & str_format ) ;
break ;
}
default :
assert ( false ) ;
break ;
}
internal : : PrintfArgFormatter < Char > ( writer , spec ) . visit ( arg ) ;
}
write ( writer , start , s ) ;
}
@ -1019,16 +1100,47 @@ const Char *fmt::BasicFormatter<Char>::format(
+ + s ;
}
// Parse width and zero flag.
if ( ' 0 ' < = * s & & * s < = ' 9 ' ) {
// Parse zero flag.
if ( * s = = ' 0 ' ) {
require_numeric_argument ( arg , ' 0 ' ) ;
spec . align_ = ALIGN_NUMERIC ;
spec . fill_ = ' 0 ' ;
+ + s ;
}
// Zero may be parsed again as a part of the width, but it is simpler
// and more efficient than checking if the next char is a digit.
// Parse width.
if ( ' 0 ' < = * s & & * s < = ' 9 ' ) {
spec . width_ = parse_nonnegative_int ( s ) ;
} else if ( * s = = ' { ' ) {
+ + s ;
Arg width_arg = is_name_start ( * s ) ?
parse_arg_name ( s ) : parse_arg_index ( s ) ;
if ( * s + + ! = ' } ' )
FMT_THROW ( FormatError ( " invalid format string " ) ) ;
ULongLong value = 0 ;
switch ( width_arg . type ) {
case Arg : : INT :
if ( width_arg . int_value < 0 )
FMT_THROW ( FormatError ( " negative width " ) ) ;
value = width_arg . int_value ;
break ;
case Arg : : UINT :
value = width_arg . uint_value ;
break ;
case Arg : : LONG_LONG :
if ( width_arg . long_long_value < 0 )
FMT_THROW ( FormatError ( " negative width " ) ) ;
value = width_arg . long_long_value ;
break ;
case Arg : : ULONG_LONG :
value = width_arg . ulong_long_value ;
break ;
default :
FMT_THROW ( FormatError ( " width is not integer " ) ) ;
}
if ( value > INT_MAX )
FMT_THROW ( FormatError ( " number is too big " ) ) ;
spec . width_ = static_cast < int > ( value ) ;
}
// Parse precision.
@ -1039,7 +1151,8 @@ const Char *fmt::BasicFormatter<Char>::format(
spec . precision_ = parse_nonnegative_int ( s ) ;
} else if ( * s = = ' { ' ) {
+ + s ;
const Arg & precision_arg = parse_arg_index ( s ) ;
Arg precision_arg =
is_name_start ( * s ) ? parse_arg_name ( s ) : parse_arg_index ( s ) ;
if ( * s + + ! = ' } ' )
FMT_THROW ( FormatError ( " invalid format string " ) ) ;
ULongLong value = 0 ;
@ -1069,7 +1182,7 @@ const Char *fmt::BasicFormatter<Char>::format(
} else {
FMT_THROW ( FormatError ( " missing precision specifier " ) ) ;
}
if ( arg . type < Arg : : LAST_INTEGER_TYPE | | arg . type = = Arg : : POINTER ) {
if ( arg . type < = Arg : : LAST_INTEGER_TYPE | | arg . type = = Arg : : POINTER ) {
FMT_THROW ( FormatError (
fmt : : format ( " precision not allowed in {} format specifier " ,
arg . type = = Arg : : POINTER ? " pointer " : " integer " ) ) ) ;
@ -1083,7 +1196,6 @@ const Char *fmt::BasicFormatter<Char>::format(
if ( * s + + ! = ' } ' )
FMT_THROW ( FormatError ( " missing '}' in format string " ) ) ;
start_ = s ;
// Format argument.
internal : : ArgFormatter < Char > ( * this , spec , s - 1 ) . visit ( arg ) ;
@ -1091,25 +1203,24 @@ const Char *fmt::BasicFormatter<Char>::format(
}
template < typename Char >
void fmt : : BasicFormatter < Char > : : format (
BasicStringRef < Char > format_str , const ArgList & args ) {
const Char * s = start_ = format_str . c_str ( ) ;
set_args ( args ) ;
void fmt : : BasicFormatter < Char > : : format ( BasicCStringRef < Char > format_str ) {
const Char * s = format_str . c_str ( ) ;
const Char * start = s ;
while ( * s ) {
Char c = * s + + ;
if ( c ! = ' { ' & & c ! = ' } ' ) continue ;
if ( * s = = c ) {
write ( writer_ , start _ , s ) ;
start _ = + + s ;
write ( writer_ , start , s ) ;
start = + + s ;
continue ;
}
if ( c = = ' } ' )
FMT_THROW ( FormatError ( " unmatched '}' in format string " ) ) ;
write ( writer_ , start _ , s - 1 ) ;
Arg arg = parse_arg_index( s ) ;
s = format ( s , arg ) ;
write ( writer_ , start , s - 1 ) ;
Arg arg = is_name_start( * s ) ? parse_arg_name ( s ) : parse_arg_index( s ) ;
s tart = s = format ( s , arg ) ;
}
write ( writer_ , start _ , s ) ;
write ( writer_ , start , s ) ;
}
FMT_FUNC void fmt : : report_system_error (
@ -1117,30 +1228,30 @@ FMT_FUNC void fmt::report_system_error(
report_error ( internal : : format_system_error , error_code , message ) ;
}
# if def _WIN32
# if FMT_USE_WINDOWS_H
FMT_FUNC void fmt : : report_windows_error (
int error_code , fmt : : StringRef message ) FMT_NOEXCEPT {
report_error ( internal : : format_windows_error , error_code , message ) ;
}
# endif
FMT_FUNC void fmt : : print ( std : : FILE * f , StringRef format_str , ArgList args ) {
FMT_FUNC void fmt : : print ( std : : FILE * f , C StringRef format_str , ArgList args ) {
MemoryWriter w ;
w . write ( format_str , args ) ;
std : : fwrite ( w . data ( ) , 1 , w . size ( ) , f ) ;
}
FMT_FUNC void fmt : : print ( StringRef format_str , ArgList args ) {
FMT_FUNC void fmt : : print ( C StringRef format_str , ArgList args ) {
print ( stdout , format_str , args ) ;
}
FMT_FUNC void fmt : : print ( std : : ostream & os , StringRef format_str , ArgList args ) {
FMT_FUNC void fmt : : print ( std : : ostream & os , C StringRef format_str , ArgList args ) {
MemoryWriter w ;
w . write ( format_str , args ) ;
os . write ( w . data ( ) , w . size ( ) ) ;
}
FMT_FUNC void fmt : : print_colored ( Color c , StringRef format , ArgList args ) {
FMT_FUNC void fmt : : print_colored ( Color c , C StringRef format , ArgList args ) {
char escape [ ] = " \x1b [30m " ;
escape [ 3 ] = ' 0 ' + static_cast < char > ( c ) ;
std : : fputs ( escape , stdout ) ;
@ -1148,7 +1259,7 @@ FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
std : : fputs ( RESET_COLOR , stdout ) ;
}
FMT_FUNC int fmt : : fprintf ( std : : FILE * f , StringRef format , ArgList args ) {
FMT_FUNC int fmt : : fprintf ( std : : FILE * f , C StringRef format , ArgList args ) {
MemoryWriter w ;
printf ( w , format , args ) ;
std : : size_t size = w . size ( ) ;
@ -1157,6 +1268,8 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
# ifndef FMT_HEADER_ONLY
template struct fmt : : internal : : BasicData < void > ;
// Explicit instantiations for char.
template void fmt : : internal : : FixedBuffer < char > : : grow ( std : : size_t ) ;
@ -1164,11 +1277,10 @@ template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
template const char * fmt : : BasicFormatter < char > : : format (
const char * & format_str , const fmt : : internal : : Arg & arg ) ;
template void fmt : : BasicFormatter < char > : : format (
BasicStringRef < char > format , const ArgList & args ) ;
template void fmt : : BasicFormatter < char > : : format ( CStringRef format ) ;
template void fmt : : internal : : PrintfFormatter < char > : : format (
BasicWriter < char > & writer , BasicStringRef< char > format , const ArgList & args ) ;
BasicWriter < char > & writer , CStringRef format ) ;
template int fmt : : internal : : CharTraits < char > : : format_float (
char * buffer , std : : size_t size , const char * format ,
@ -1186,11 +1298,10 @@ template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
const wchar_t * & format_str , const fmt : : internal : : Arg & arg ) ;
template void fmt : : BasicFormatter < wchar_t > : : format (
Basic StringRef< wchar_t > format , const ArgList & args ) ;
Basic C StringRef< wchar_t > format ) ;
template void fmt : : internal : : PrintfFormatter < wchar_t > : : format (
BasicWriter < wchar_t > & writer , BasicStringRef < wchar_t > format ,
const ArgList & args ) ;
BasicWriter < wchar_t > & writer , WCStringRef format ) ;
template int fmt : : internal : : CharTraits < wchar_t > : : format_float (
wchar_t * buffer , std : : size_t size , const wchar_t * format ,