Main Page | Modules | Namespace List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

printf.h

Go to the documentation of this file.
00001 #ifndef TAG_PRINTF_H
00002 #define TAG_PRINTF_H
00003 
00004 #include <iostream>
00005 #include <iomanip>
00006 #include <sstream>
00007 #include <string>
00008 #include <cctype>
00009 
00010 #include <tag/tuple.h>
00011 
00012 namespace tag
00013 {
00014     #ifndef DOXYGEN_IGNORE_INTERNAL
00015     namespace Internal
00016     {
00017 
00018         // Code for parsing and interpreting printf style format specifiers.
00019         //Code for groking format strings
00020         struct format
00021         {
00022             enum
00023             {
00024                 ALT = 1, ZP=2, LEFT=4, SPACE=8, SIGN=16, PERCENT=32, BAD=64,
00025                 NO_PRECISION=-1, NO_WIDTH=-1
00026             };
00027 
00028             int flags;
00029             int  width, precision;
00030             char conversion;
00031 
00032             inline int parse(const std::string& fmt, int pos)
00033             {
00034                 flags=0;
00035                 width=NO_WIDTH;
00036                 precision=NO_PRECISION;
00037                 conversion=0;
00038 
00039                 int s = fmt.size();
00040 
00041                 if(pos == s)
00042                 {
00043                     flags |= BAD;
00044                     return 0;
00045                 }
00046 
00047                 //Check for literal
00048                 if(fmt[pos] == '%')
00049                 {
00050                     flags = PERCENT;
00051                     return pos+1;
00052                 }
00053 
00054                 //Get flags (if any)
00055                 for(; pos < s; pos++)
00056                 {
00057                     char c = fmt[pos];
00058 
00059                     if(c == '#')
00060                         flags |= ALT;
00061                     else if(c == '0')
00062                         flags |= ZP;
00063                     else if(c == ' ')
00064                         flags |= SPACE;
00065                     else if(c == '-')
00066                         flags |= LEFT;
00067                     else if(c == '+')
00068                         flags |= SIGN;
00069                     else
00070                         break;
00071                 }
00072 
00073                 //Get width
00074                 for(; pos < s; pos++)
00075                 {
00076                     char c = fmt[pos];
00077                     if(isdigit(c))
00078                         if(width == NO_WIDTH)
00079                             width = c - '0';
00080                         else
00081                             width = width * 10 + (c-'0');
00082                     else
00083                         break;
00084                 }
00085 
00086                 //Check for a precison
00087                 if(pos < s && fmt[pos] == '.')
00088                 {
00089                     precision = 0;
00090                     pos++;
00091 
00092                     //Get width
00093                     for(; pos < s; pos++)
00094                     {
00095                         char c = fmt[pos];
00096                         if(isdigit(c))
00097                             precision = precision * 10 + (c-'0');
00098                         else
00099                             break;
00100                     }
00101                 }
00102 
00103                 //Now, this should be the conversion
00104                 if(pos < s && isalpha(fmt[pos]))
00105                     conversion = fmt[pos++];
00106                 else
00107                     flags = BAD;
00108 
00109                 return pos;
00110             }
00111         };
00112 
00113         //To make it looks like ostream << format works
00114         template<class Char, class Traits> struct bound_format
00115         {
00116             bound_format(std::basic_ostream<Char, Traits>& os, const format& ff)
00117             :o(os), f(ff)
00118             {}
00119 
00120             std::basic_ostream<Char, Traits>& o;
00121             const format& f;
00122         };
00123 
00124 
00125         template<class Char, class Traits> bound_format<Char, Traits> operator<<(std::basic_ostream<Char, Traits>& o, const format& f)
00126         {
00127             return bound_format<Char, Traits>(o, f);
00128         }
00129 
00130         //Evaluate the result of osteram << format << X
00131         template<class Char, class Traits, class C> std::basic_ostream<Char, Traits>& operator<<(bound_format<Char,Traits> f, const C& c)
00132         {
00133             using std::ios;
00134             using namespace std;
00135 
00136             bool precision_is_max_width=0;
00137 
00138 
00139             //Save old stream state.
00140             int old_p = f.o.precision();
00141             Char old_fill = f.o.fill();
00142             ios::fmtflags old_flags = f.o.flags();
00143 
00144             //Conversion specific tricks
00145             //Defaults
00146             f.o.unsetf(ios::floatfield | ios::boolalpha);
00147             f.o.setf(ios::dec);
00148             f.o.fill(' ');
00149 
00150             //Process conversion characters. These can affect the formatting
00151             //parameters below.
00152             switch(f.f.conversion)
00153             {
00154                 case 'f':
00155                 case 'F':
00156                     f.o.setf(ios::fixed);
00157                     break;
00158 
00159                 case 'e':
00160                 case 'E':
00161                     f.o.setf(ios::scientific);
00162                     break;
00163 
00164                 case 'g':
00165                 case 'G':
00166                     f.o.unsetf(ios::floatfield);
00167                     break;
00168 
00169                 case 'x':
00170                 case 'X':
00171                     f.o << hex;
00172                     break;
00173 
00174                 case 'o':
00175                 case 'O':
00176                     f.o << oct;
00177                     break;
00178 
00179                 case 'b':
00180                 case 'B':
00181                     f.o << boolalpha;
00182                     break;
00183 
00184                 case 's':
00185                 case 'S':
00186                     precision_is_max_width=1;
00187                     break;
00188 
00189                 case 'k':
00190                 case 'K':
00191                     return f.o;
00192                     break;
00193             }
00194 
00195 
00196 
00197             if(f.f.width != format::NO_WIDTH)
00198                 f.o.width(f.f.width);
00199 
00200             if(f.f.flags & format::ZP && !(f.f.flags & format::LEFT))
00201                 f.o.fill('0');
00202 
00203             if(f.f.flags & format::SIGN)
00204                 f.o.setf(ios::showpos);
00205             else
00206                 f.o.unsetf(ios::showpos);
00207 
00208             if(f.f.flags & format::LEFT)
00209                 f.o.setf(ios::left);
00210             else
00211                 f.o.setf(ios::internal);
00212 
00213             if(f.f.flags * format::ALT)
00214                 f.o.setf(ios::showbase | ios::showpoint);
00215             else
00216                 f.o.unsetf(ios::showbase | ios::showpoint);
00217 
00218 
00219             if(isupper(f.f.conversion))
00220                 f.o.setf(ios::uppercase);
00221             else
00222                 f.o.unsetf(ios::uppercase);
00223 
00224 
00225             if(f.f.precision != format::NO_PRECISION && ! precision_is_max_width)
00226                 f.o.precision(f.f.precision);
00227 
00228             if(precision_is_max_width && f.f.precision != format::NO_PRECISION)
00229             {
00230                 ostringstream tmp;
00231                 tmp.copyfmt(f.o);
00232 
00233                 //Since we're doing the truncation by hand, then there should be
00234                 //no width specification
00235                 tmp << setw(0) << c;
00236 
00237                 f.o << tmp.str().substr(0, f.f.precision);
00238             }
00239             else
00240                 f.o << c;
00241 
00242 
00243             //Reset values
00244             f.o.precision(old_p);
00245             f.o.fill(old_fill);
00246             f.o.setf(old_flags);
00247 
00248             return f.o;
00249         }
00250 
00251         //This parses a format tring and uses it to print a typelist. The typelist has to be
00252         //accessed in reverse order, since the last element added to the typelist is the
00253         //one at the start of the list. Since lists are produced with (Fmt, a, b, c), that means
00254         //that c would be accessed first. To make it look like printf, a needs to be accessed first.
00255         template<class C, class D, int i, int max> struct print_typelist
00256         {
00257             static void print(std::ostream& o, const std::string& fmt, int fpos, const T_list<C,D>& l)
00258             {
00259                 unsigned int ppos;
00260 
00261                 while(1)
00262                 {
00263                     ppos = fmt.find('%', fpos);
00264 
00265                     if(ppos == fmt.npos)
00266                     {
00267                         //No more format specifiers, so output the rest of the string
00268                         o <<  &fmt[fpos];
00269                         return;
00270                     }
00271 
00272                     //else output the strung up to the specifier
00273                     o  << fmt.substr(fpos, ppos - fpos);
00274 
00275                     //Parse the format string
00276                     format f;
00277                     int pos = f.parse(fmt, ppos+1);
00278 
00279                     if(f.flags & format::PERCENT)
00280                     {
00281                         o << '%';
00282                         fpos = pos;
00283                         continue;
00284                     }
00285                     else if(f.flags & format::BAD)
00286                     {
00287                         o  << "<Malformed format>" << &fmt[ppos];
00288                         return ;
00289                     }
00290                     else
00291                     {
00292                         o << f << l.template index<i>();
00293                         print_typelist<C,D, i+1, max>::print(o, fmt, pos, l);
00294                         return;
00295                     }
00296                 }
00297             }
00298 
00299         };
00300 
00301         template<class C, class D, int max> struct print_typelist<C, D, max, max>
00302         {
00303             static void print(std::ostream& o, const std::string& fmt, int fpos, const T_list<C,D>& l)
00304             {
00305                 unsigned int ppos;
00306 
00307                 while(1)
00308                 {
00309                     ppos = fmt.find('%', fpos);
00310 
00311                     if(ppos == fmt.npos)
00312                     {
00313                         //No more format specifiers, so output the rest of the string
00314                         o <<  &fmt[fpos];
00315                         return;
00316                     }
00317 
00318                     //else output the strung up to the specifier
00319                     o  << fmt.substr(fpos, ppos - fpos);
00320 
00321                     //Parse the format string
00322                     format f;
00323                     int pos = f.parse(fmt, ppos+1);
00324 
00325                     if(f.flags & format::PERCENT)
00326                     {
00327                         o << '%';
00328                         fpos = pos;
00329                         continue;
00330                     }
00331                     else if(f.flags & format::BAD)
00332                     {
00333                         o  << "<Malformed format>" << &fmt[ppos];
00334                         return ;
00335                     }
00336                     else
00337                     {
00338                         o << "<Missing value>";
00339                         fpos = pos;
00340                         continue;
00341                     }
00342                 }
00343             }
00344         };
00345     }
00346     #endif
00347 
00348 
00353 
00441     template<class A, class B, class C, class D> void vfPrintf(std::basic_ostream<A, B>& o, const std::string fmt, const T_list<C,D>& l)
00442     {
00443         Internal::print_typelist<C, D, 0, T_list<C,D>::elements >::print(o, fmt, 0, l);
00444     }
00445 
00450     template<class C, class D> void vPrintf(const std::string fmt, const T_list<C,D>& l)
00451     {
00452         vfPrintf(std::cout, fmt, l);
00453     }
00454 
00460     template<class C, class D> std::string vsPrintf(const std::string& fmt, const T_list<C,D>& l)
00461     {
00462         std::ostringstream o;
00463         vfPrintf(o, fmt, l);
00464         return o.str();
00465     }
00466 
00475     static const T_ListEnd Fmt=TupleHead;
00476 
00477     //Old cvs version has by-hand variable argument list up to 10 args
00478 }
00479 
00485 #define Printf(A, ...) vPrintf(A, (tag::Fmt,## __VA_ARGS__))
00486 
00493 #define fPrintf(A,B, ...) vfPrintf(A,B, (tag::Fmt,## __VA_ARGS__))
00494 
00501 #define sPrintf(A, ...) vsPrintf(A, (tag::Fmt,## __VA_ARGS__))
00502 #endif

Generated on Wed Aug 8 14:30:35 2007 for TooN Algorithm Library - tag by  doxygen 1.3.9.1