920 lines
18 KiB
C++
920 lines
18 KiB
C++
/*
|
|
Format a C++ library for typesafe string formating in printf style
|
|
(C) 2001 - 2003 by Martin Oberzalek <kingleo@gmx.at>
|
|
|
|
Examples:
|
|
std::cout << format( "Hello %s, I have $05d$ in my pocket", "world", 5 ) << std::endl;
|
|
std::cout << format( "Do not try this with printf: %s", 10101 ) << std::endl;
|
|
|
|
|
|
*/
|
|
|
|
#ifndef format_h
|
|
#define format_h
|
|
|
|
#include <string>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
|
|
/**
|
|
Can we use stringstreams or do we have to use the deprecated strstreams instead?
|
|
If we have to use strstreams, simple comment the next #define
|
|
**/
|
|
#define HAVE_STL_SSTREAM
|
|
#define NFORMAT
|
|
|
|
|
|
#if __GNUC__ == 2
|
|
#undef HAVE_STL_SSTREAM
|
|
#endif
|
|
|
|
#ifdef HAVE_STL_SSTREAM
|
|
# include <sstream>
|
|
# include <cctype>
|
|
# define IS_DIGIT( x ) std::isdigit( x )
|
|
#else
|
|
extern "C" {
|
|
# include <ctype.h>
|
|
}
|
|
# include <strstream>
|
|
# define IS_DIGIT( x ) isdigit( x )
|
|
#endif
|
|
|
|
#ifndef NFORMAT
|
|
|
|
namespace Format
|
|
{
|
|
typedef std::string::size_type ST;
|
|
|
|
class CFormat
|
|
{
|
|
public:
|
|
|
|
typedef enum Adjust
|
|
{
|
|
LEFT,
|
|
RIGHT
|
|
};
|
|
|
|
typedef enum Base
|
|
{
|
|
OCT,
|
|
DEC,
|
|
HEX
|
|
};
|
|
|
|
typedef enum Floating
|
|
{
|
|
FIXED,
|
|
SCIENTIFIC
|
|
};
|
|
|
|
bool valid;
|
|
Adjust adjust;
|
|
bool special;
|
|
bool sign;
|
|
bool grouping; // SUSv2 extension
|
|
bool conversion; // glibc 2.2 extension
|
|
bool zero;
|
|
bool precision_explicit;
|
|
bool internal;
|
|
Base base;
|
|
bool setupper;
|
|
Floating floating;
|
|
bool showbase;
|
|
|
|
int width;
|
|
int precision;
|
|
int strlength;
|
|
|
|
std::string format;
|
|
|
|
public:
|
|
CFormat() { reset(); }
|
|
|
|
void set( std::ostream& out );
|
|
|
|
private:
|
|
void reset();
|
|
};
|
|
|
|
/****************************************/
|
|
// all the errors that are thrown
|
|
// are a cause of a mistake with %* or %*m$
|
|
class Error
|
|
{
|
|
public:
|
|
std::string err;
|
|
Error( std::string s ) : err( s ) {}
|
|
};
|
|
|
|
/****************************************/
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
class Format
|
|
{
|
|
private:
|
|
struct Arg
|
|
{
|
|
bool is_int;
|
|
bool is_string;
|
|
};
|
|
|
|
Arg args[6];
|
|
|
|
std::string format;
|
|
|
|
A a;
|
|
B b;
|
|
C c;
|
|
D d;
|
|
E e;
|
|
F f;
|
|
|
|
unsigned int num_of_args;
|
|
|
|
std::string s;
|
|
|
|
public:
|
|
Format( const std::string &format, A a, B b, C c, D d, E e, F f, unsigned int num_of_args );
|
|
|
|
std::string get_string() const { return s; }
|
|
|
|
private:
|
|
void parse();
|
|
|
|
template <class N> bool is_int( N &n ) { return false; }
|
|
bool is_int( int &n ) { return true; }
|
|
bool is_int( unsigned int &n ) { return true; }
|
|
bool is_int( short &n ) { return true; }
|
|
bool is_int( unsigned short ) { return true; }
|
|
|
|
template <class S> bool is_string( S &s ) { return false; }
|
|
bool is_string( std::string& s ) { return true; }
|
|
bool is_string( const std::string& s ) { return true; }
|
|
bool is_string( char* ) { return true; }
|
|
bool is_string( const char* ) { return true; }
|
|
|
|
int get_int_arg( unsigned int num );
|
|
void gen_arg_list();
|
|
std::string use_arg( unsigned int i, const CFormat &cf );
|
|
|
|
template <class S> std::string x2s( S ss, const CFormat &cf )
|
|
{
|
|
#ifdef HAVE_STL_SSTREAM
|
|
std::stringstream str;
|
|
str << cf << ss;
|
|
std::string st = str.str();
|
|
return st;
|
|
#else
|
|
std::strstream str;
|
|
str << cf << ss << std::ends;
|
|
std::string st = str.str();
|
|
str.freeze(0);
|
|
return st;
|
|
#endif
|
|
}
|
|
|
|
};
|
|
|
|
int skip_atoi( std::string s, ST start, ST& pos );
|
|
|
|
} // namespace Format
|
|
|
|
inline std::ostream& operator<<( std::ostream& out, Format::CFormat cf )
|
|
{
|
|
cf.set( out );
|
|
return out;
|
|
}
|
|
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
Format::Format<A,B,C,D,E,F>::Format( std::string const &format, A a, B b, C c, D d, E e, F f, unsigned int num_of_args )
|
|
: format( format ), a(a), b(b), c(c), d(d), e(e), f(f), num_of_args( num_of_args )
|
|
{
|
|
if( num_of_args > 6 )
|
|
throw Error( "Number of args out of range" );
|
|
|
|
gen_arg_list();
|
|
|
|
parse();
|
|
}
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
int Format::Format<A,B,C,D,E,F>::get_int_arg( unsigned int num )
|
|
{
|
|
if( static_cast<unsigned int>(num) > num_of_args - 1 )
|
|
throw Error( "The arg you wan't to use is out of range" );
|
|
|
|
if( num < 0 )
|
|
throw Error( "negativ number for arg number not allowed" );
|
|
|
|
if( args[num].is_int )
|
|
{
|
|
switch( num )
|
|
{
|
|
case 0: return *((int*) &a); // I have to cast here cause the compiler
|
|
case 1: return *((int*) &b); // will make troubles if any of these
|
|
case 2: return *((int*) &c); // values is not an unsigned int.
|
|
case 3: return *((int*) &d); // Even if we are sure that
|
|
case 4: return *((int*) &e); // an unsigned int value will be returned
|
|
case 5: return *((int*) &f);
|
|
}
|
|
}
|
|
else
|
|
throw Error( "expecting int arg" );
|
|
|
|
return 0; // should never be reached
|
|
}
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
void Format::Format<A,B,C,D,E,F>::gen_arg_list()
|
|
{
|
|
for( unsigned int i = 0; i < num_of_args; i++ )
|
|
{
|
|
switch( i )
|
|
{
|
|
case 0:
|
|
args[i].is_int = is_int( a );
|
|
args[i].is_string = is_string( a );
|
|
break;
|
|
case 1:
|
|
args[i].is_int = is_int( b );
|
|
args[i].is_string = is_string( b );
|
|
break;
|
|
|
|
case 2:
|
|
args[i].is_int = is_int( c );
|
|
args[i].is_string = is_string( c );
|
|
break;
|
|
|
|
case 3:
|
|
args[i].is_int = is_int( d );
|
|
args[i].is_string = is_string( d );
|
|
break;
|
|
|
|
case 4:
|
|
args[i].is_int = is_int( e );
|
|
args[i].is_string = is_string( e );
|
|
break;
|
|
|
|
case 5:
|
|
args[i].is_int = is_int( f );
|
|
args[i].is_string = is_string( f );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
std::string Format::Format<A,B,C,D,E,F>::use_arg( unsigned int i, const CFormat &cf )
|
|
{
|
|
if( i > num_of_args || i < 0 )
|
|
throw Error( "out of arg range" );
|
|
|
|
switch( i )
|
|
{
|
|
case 0: return x2s( a, cf );
|
|
case 1: return x2s( b, cf );
|
|
case 2: return x2s( c, cf );
|
|
case 3: return x2s( d, cf );
|
|
case 4: return x2s( e, cf );
|
|
case 5: return x2s( f, cf );
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
void Format::Format<A,B,C,D,E,F>::parse()
|
|
{
|
|
if( format.empty() )
|
|
return;
|
|
|
|
unsigned int par = 0;
|
|
unsigned int use_par = 0;
|
|
ST pos = 0;
|
|
ST len = format.size();
|
|
s = "";
|
|
bool had_precision = false;
|
|
|
|
while( par < num_of_args && pos < len )
|
|
{ // while
|
|
|
|
use_par = par;
|
|
|
|
if( pos >= len )
|
|
break;
|
|
|
|
if( format[pos] != '%' )
|
|
{
|
|
s += format[pos];
|
|
pos++;
|
|
continue;
|
|
}
|
|
|
|
// % digit found
|
|
pos++;
|
|
|
|
if( !(pos < len ) || (format[pos] == '%') )
|
|
{
|
|
// %% -> %
|
|
s += format[pos];
|
|
pos++;
|
|
continue;
|
|
}
|
|
|
|
// format string found
|
|
|
|
ST start = pos - 1;
|
|
CFormat f;
|
|
|
|
// process flags
|
|
|
|
while( (pos < len) )
|
|
{
|
|
bool finished = false;
|
|
|
|
switch( format[pos] )
|
|
{
|
|
case '-' : f.adjust = CFormat::LEFT; break;
|
|
case '+' : f.sign = true; break;
|
|
case ' ' : f.zero = false; break;
|
|
case '#' : f.special = true; break;
|
|
case '\'': f.grouping = true; break;
|
|
case 'I' : f.conversion = true; break;
|
|
case '0' : f.zero = true; break;
|
|
default: finished = true; break;
|
|
}
|
|
|
|
if( finished )
|
|
break;
|
|
|
|
pos++;
|
|
} // while( (pos < len) )
|
|
|
|
// get argument number
|
|
if( pos < len )
|
|
{
|
|
// search for the $ digit
|
|
unsigned int dp = pos;
|
|
|
|
while( dp < len && IS_DIGIT( format[dp] ) )
|
|
dp++;
|
|
|
|
if( dp < len && format[dp] == '$' )
|
|
{
|
|
use_par = skip_atoi( format, pos, pos ) - 1;
|
|
pos = dp + 1;
|
|
}
|
|
}
|
|
|
|
// get field with
|
|
if( pos < len )
|
|
{
|
|
if( IS_DIGIT( format[pos] ) )
|
|
f.width = skip_atoi( format, pos, pos );
|
|
else if( format[pos] == '*' )
|
|
{
|
|
pos++;
|
|
|
|
// search for the $ digit
|
|
unsigned int dp = pos;
|
|
|
|
while( dp < len && IS_DIGIT( format[dp] ) )
|
|
dp++;
|
|
|
|
if( dp < len && format[dp] == '$' )
|
|
{
|
|
f.width = get_int_arg( skip_atoi( format, pos, pos ) - 1 );
|
|
// skip $ sign
|
|
pos++;
|
|
}
|
|
else
|
|
{
|
|
f.width = get_int_arg( par );
|
|
|
|
if( use_par == par )
|
|
use_par++;
|
|
|
|
par++;
|
|
}
|
|
|
|
if( f.width < 0 )
|
|
{
|
|
f.width *= -1;
|
|
f.adjust = CFormat::LEFT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// precision
|
|
if( pos < len )
|
|
{
|
|
if( format[pos] == '.' )
|
|
{
|
|
pos++;
|
|
if( !(pos < len) )
|
|
return;
|
|
|
|
had_precision = true;
|
|
|
|
if( IS_DIGIT( format[pos] ) )
|
|
f.precision = skip_atoi( format, pos, pos );
|
|
else if( format[pos] == '*' )
|
|
{
|
|
pos++;
|
|
|
|
|
|
// search for the $ digit
|
|
unsigned int dp = pos;
|
|
|
|
while( dp < len && IS_DIGIT( format[dp] ) )
|
|
dp++;
|
|
|
|
if( dp < len && format[dp] == '$' )
|
|
{
|
|
f.precision = get_int_arg( skip_atoi( format, pos, pos ) - 1 );
|
|
// skip $ sign
|
|
pos++;
|
|
}
|
|
else
|
|
{
|
|
f.precision = get_int_arg( par );
|
|
|
|
if( use_par == par )
|
|
use_par++;
|
|
|
|
par++;
|
|
}
|
|
|
|
if( f.precision == 0)
|
|
f.precision_explicit = true;
|
|
|
|
if( f.precision < 0 )
|
|
f.precision = 0;
|
|
}
|
|
else
|
|
f.precision = 0;
|
|
}
|
|
|
|
}
|
|
|
|
// lenght modifier
|
|
/*
|
|
they will be ignored
|
|
cause we know the types of the parameter
|
|
*/
|
|
if( (pos < len) )
|
|
{
|
|
bool hh = false;
|
|
bool ll = false;
|
|
bool found = false;
|
|
|
|
switch( format[pos] )
|
|
{
|
|
case 'h': hh = true; found = true; break;
|
|
case 'l': ll = true; found = true; break;
|
|
case 'L':
|
|
case 'q':
|
|
case 'j':
|
|
case 'z':
|
|
case 't': found = true; break;
|
|
default: break;
|
|
}
|
|
|
|
if(found )
|
|
{
|
|
pos++;
|
|
|
|
if( pos < len )
|
|
if( hh == true )
|
|
{
|
|
if( format[pos] == 'h' )
|
|
pos++;
|
|
}
|
|
else if( ll = true )
|
|
if( format[pos] == 'l' )
|
|
pos++;
|
|
}
|
|
}
|
|
|
|
// conversion specifier
|
|
|
|
if( pos < len )
|
|
{
|
|
bool invalid = false;
|
|
switch( format[pos] )
|
|
{
|
|
case 'd':
|
|
case 'i':
|
|
f.base = CFormat::DEC;
|
|
if( f.zero && (f.adjust != CFormat::LEFT) )
|
|
f.internal = true;
|
|
break;
|
|
|
|
case 'X': f.setupper = true;
|
|
case 'x':
|
|
f.base = CFormat::HEX;
|
|
if( f.special )
|
|
f.showbase = true;
|
|
break;
|
|
|
|
case 'o':
|
|
f.base = CFormat::OCT;
|
|
if( f.special )
|
|
f.showbase = true;
|
|
break;
|
|
|
|
|
|
case 'E':
|
|
f.setupper = true;
|
|
|
|
case 'e':
|
|
if( f.special )
|
|
f.sign = true;
|
|
f.floating = CFormat::SCIENTIFIC;
|
|
break;
|
|
|
|
case 'F': // not supported
|
|
case 'f':
|
|
if( f.special )
|
|
f.sign = true;
|
|
f.floating = CFormat::FIXED;
|
|
break;
|
|
|
|
case 's':
|
|
if( f.zero )
|
|
f.zero = false;
|
|
break;
|
|
|
|
|
|
// unsupported modifiers
|
|
|
|
|
|
case 'G':
|
|
case 'g':
|
|
|
|
case 'A':
|
|
case 'a':
|
|
|
|
case 'c':
|
|
|
|
case 'C':
|
|
case 'S':
|
|
case 'P':
|
|
case 'n': break;
|
|
|
|
default: invalid = true;
|
|
}
|
|
|
|
if( !invalid )
|
|
f.valid = true;
|
|
}
|
|
|
|
if( f.valid )
|
|
{
|
|
std::string str;
|
|
int upar = par;
|
|
|
|
if( use_par != par )
|
|
upar = use_par;
|
|
|
|
if( f.base == CFormat::HEX && had_precision && f.special )
|
|
{
|
|
CFormat f2;
|
|
f2.base = f.base;
|
|
std::string s = use_arg( upar, f2 );
|
|
f.strlength = s.size();
|
|
// printf( "str: %s\n", s.c_str() );
|
|
}
|
|
|
|
str = use_arg( upar, f );
|
|
|
|
// cut string
|
|
if( had_precision && args[upar].is_string )
|
|
str = str.substr( 0, f.precision );
|
|
|
|
s += str;
|
|
|
|
if( use_par == par )
|
|
par++;
|
|
}
|
|
else
|
|
{
|
|
// copy the invalid format string
|
|
for( ST i = start; i<= pos; i++ )
|
|
if( i < len )
|
|
s += format[i];
|
|
}
|
|
|
|
pos++;
|
|
|
|
} // while
|
|
|
|
if( pos < len )
|
|
{
|
|
while( pos < len )
|
|
{
|
|
s += format[pos];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
#else // ifndef NFORMAT
|
|
|
|
/// converts anything to a string
|
|
template<class T>std::string x2s( T what )
|
|
{
|
|
#ifdef HAVE_STL_SSTREAM
|
|
|
|
std::stringstream str;
|
|
|
|
str << what;
|
|
std::string s( str.str() );
|
|
return s;
|
|
|
|
#else
|
|
|
|
std::strstream str;
|
|
|
|
str << what << std::ends;
|
|
|
|
std::string s( str.str() );
|
|
|
|
str.freeze(0);
|
|
|
|
return s;
|
|
#endif
|
|
}
|
|
|
|
#include <cstdio>
|
|
|
|
namespace Format
|
|
{
|
|
|
|
template <class T> const char* convert( T t ) { return x2s( t ).c_str(); }
|
|
|
|
#define DEF( TYPE ) \
|
|
inline TYPE convert( TYPE t ) { return t; }
|
|
|
|
DEF( unsigned )
|
|
DEF( int )
|
|
DEF( char )
|
|
DEF( char* )
|
|
DEF( const char* )
|
|
DEF( short )
|
|
DEF( double )
|
|
DEF( float )
|
|
DEF( long )
|
|
|
|
#undef DEF
|
|
|
|
|
|
template<class A, class B, class C, class D, class E, class F>
|
|
class Format
|
|
{
|
|
std::string s;
|
|
|
|
public:
|
|
Format( const std::string &format, A a, B b, C c, D d, E e, F f, unsigned int num_of_args )
|
|
{
|
|
#define D( T ) convert( T )
|
|
unsigned buffer_size = 256;
|
|
|
|
bool cont = false;
|
|
|
|
do {
|
|
|
|
cont = false;
|
|
|
|
char *buffer = new char[buffer_size];
|
|
int n = 0;
|
|
|
|
switch( num_of_args )
|
|
{
|
|
case 1: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ) ); break;
|
|
case 2: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ), D( b ) ); break;
|
|
case 3: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ), D( b ), D( c ) ); break;
|
|
case 4: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ), D( b ), D( c ), D( d ) ); break;
|
|
case 5: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ), D( b ), D( c ), D( d ), D( e ) ); break;
|
|
case 6: n = std::sprintf( buffer, format.c_str(),
|
|
D( a ), D( b ), D( c ), D( d ), D( e ), D( f ) ); break;
|
|
}
|
|
|
|
|
|
if( (unsigned) n >= buffer_size - 2 )
|
|
{
|
|
buffer_size *= 2;
|
|
cont = true;
|
|
n = 0;
|
|
}
|
|
|
|
for( int i = 0; i < n; i++ )
|
|
s += buffer[i];
|
|
|
|
delete[] buffer;
|
|
|
|
} while( cont );
|
|
#undef D
|
|
}
|
|
|
|
std::string get_string() const { return s; }
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
template <class A, class B, class C, class D, class E, class F>
|
|
inline std::string format( std::string fs, A a, B b, C c, D d, E e, F f )
|
|
{
|
|
return Format::Format<A,B,C,D,E,F>( fs, a, b, c, d, e, f, 6).get_string();
|
|
}
|
|
|
|
template <class A, class B, class C, class D, class E>
|
|
inline std::string format( std::string fs, A a, B b, C c, D d, E e )
|
|
{
|
|
return Format::Format<A,B,C,D,E,char>( fs, a, b, c, d, e, 0, 5).get_string();
|
|
}
|
|
|
|
template <class A, class B, class C, class D>
|
|
inline std::string format( std::string fs, A a, B b, C c, D d)
|
|
{
|
|
return Format::Format<A,B,C,D,char,char>( fs, a, b, c, d, 0, 0, 4).get_string();
|
|
}
|
|
|
|
template <class A, class B, class C>
|
|
inline std::string format( std::string fs, A a, B b, C c )
|
|
{
|
|
return Format::Format<A,B,C,char,char,char>( fs, a, b, c, 0, 0, 0, 3).get_string();
|
|
}
|
|
|
|
template <class A, class B>
|
|
inline std::string format( std::string fs, A a, B b )
|
|
{
|
|
return Format::Format<A,B,char,char,char,char>( fs, a, b, 0, 0, 0, 0, 2).get_string();
|
|
}
|
|
|
|
template <class A>
|
|
inline std::string format( std::string fs, A a)
|
|
{
|
|
return Format::Format<A,char,char,char,char,char>( fs, a, 0, 0, 0, 0, 0, 1).get_string();
|
|
}
|
|
|
|
|
|
namespace Format
|
|
{
|
|
template<typename ostream> class PrintF
|
|
{
|
|
private:
|
|
|
|
int level;
|
|
int dlevel;
|
|
|
|
int dmodule;
|
|
int module;
|
|
|
|
|
|
public:
|
|
|
|
ostream &out;
|
|
|
|
public:
|
|
|
|
PrintF( ostream &out = std::cout, int module = -1, int debug_level = -1 )
|
|
: level( debug_level ), dlevel( debug_level ),
|
|
dmodule( module), module( module), out( out )
|
|
{}
|
|
|
|
void set_debug_level( int dlevel_ ) { dlevel = dlevel_; }
|
|
void set_module( int module_ ) { dmodule = module_; }
|
|
|
|
PrintF operator()( int module_ )
|
|
{
|
|
PrintF printf( *this );
|
|
printf.module = module_;
|
|
|
|
return printf;
|
|
}
|
|
|
|
PrintF operator[]( int level_ )
|
|
{
|
|
PrintF printf( *this );
|
|
printf.level = level_;
|
|
|
|
return printf;
|
|
}
|
|
|
|
template<typename T> PrintF& operator<<( const T &t )
|
|
{
|
|
if( check() )
|
|
out << t;
|
|
|
|
return *this;
|
|
}
|
|
|
|
// io manipulator overloading
|
|
PrintF& operator<<(ostream& (*f)(ostream&))
|
|
{
|
|
if( check() )
|
|
out << f;
|
|
|
|
return *this;
|
|
}
|
|
|
|
PrintF& operator()( std::string fs )
|
|
{
|
|
if( check() )
|
|
out << fs;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
template<typename A> PrintF& operator()( std::string fs, const A &a )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a );
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename A, typename B>
|
|
PrintF& operator()( std::string fs, const A &a, const B &b )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a, b );
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename A, typename B, typename C>
|
|
PrintF& operator()( std::string fs, const A &a, const B &b, const C &c )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a, b, c );
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename A, typename B, typename C, typename D>
|
|
PrintF& operator()( std::string fs, const A &a, const B &b, const C &c, const D &d )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a, b, c, d );
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename A, typename B, typename C, typename D, typename E>
|
|
PrintF& operator()( std::string fs, const A &a, const B &b, const C &c, const D &d, const E &e )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a, b, c, d, e );
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename A, typename B, typename C, typename D, typename E, typename F>
|
|
PrintF& operator()( std::string fs, const A &a, const B &b, const C &c, const D &d, const E &e, const F &f )
|
|
{
|
|
if( check() )
|
|
out << format( fs, a, b, c, d, e, f );
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool check( int module, int level ) const
|
|
{
|
|
if( module == dmodule || dmodule == -1 )
|
|
{
|
|
if( dlevel == -1 )
|
|
return true;
|
|
|
|
if( level <= dlevel )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
|
|
bool check() const { return check( module, level ); }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
#undef IS_DIGIT
|
|
|
|
#endif
|