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
00019
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
00048 if(fmt[pos] == '%')
00049 {
00050 flags = PERCENT;
00051 return pos+1;
00052 }
00053
00054
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
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
00087 if(pos < s && fmt[pos] == '.')
00088 {
00089 precision = 0;
00090 pos++;
00091
00092
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
00104 if(pos < s && isalpha(fmt[pos]))
00105 conversion = fmt[pos++];
00106 else
00107 flags = BAD;
00108
00109 return pos;
00110 }
00111 };
00112
00113
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
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
00140 int old_p = f.o.precision();
00141 Char old_fill = f.o.fill();
00142 ios::fmtflags old_flags = f.o.flags();
00143
00144
00145
00146 f.o.unsetf(ios::floatfield | ios::boolalpha);
00147 f.o.setf(ios::dec);
00148 f.o.fill(' ');
00149
00150
00151
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
00234
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
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
00252
00253
00254
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
00268 o << &fmt[fpos];
00269 return;
00270 }
00271
00272
00273 o << fmt.substr(fpos, ppos - fpos);
00274
00275
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
00314 o << &fmt[fpos];
00315 return;
00316 }
00317
00318
00319 o << fmt.substr(fpos, ppos - fpos);
00320
00321
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
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