00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012 #ifndef LOKI_SAFEFORMAT_INC_
00013 #define LOKI_SAFEFORMAT_INC_
00014
00015
00016
00017
00019
00020
00021
00023
00024 #include <cstdio>
00025 #include <string>
00026 #include <stdexcept>
00027 #include <utility>
00028 #include <cassert>
00029 #include <locale>
00030 #include <iostream>
00031
00032 #include <loki/LokiExport.h>
00033
00034
00035
00036
00037 #if defined(_WIN32) || defined(_WIN64)
00038 # define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t
00039 # define LOKI_SAFEFORMAT_UNSIGNED_LONG uintptr_t
00040 #else
00041 # define LOKI_SAFEFORMAT_SIGNED_LONG signed long
00042 # define LOKI_SAFEFORMAT_UNSIGNED_LONG unsigned long
00043 #endif
00044
00045
00046 #ifdef max
00047 # undef max
00048 #endif
00049 #ifdef min
00050 # undef min
00051 #endif
00052
00053 namespace Loki
00054 {
00055
00056
00057
00058 LOKI_EXPORT
00059 void write(std::FILE* f, const char* from, const char* to);
00060
00061
00062 LOKI_EXPORT
00063 void write(std::ostream& f, const char* from, const char* to);
00064
00065
00066 LOKI_EXPORT
00067 void write(std::string& s, const char* from, const char* to);
00068
00069
00070 template <class Char>
00071 void write(std::pair<Char*, std::size_t>& s, const Char* from, const Char* to) {
00072 assert(from <= to);
00073 if(from + s.second < to)
00074 throw std::overflow_error("");
00075
00076 s.first = std::copy(from, to, s.first);
00077
00078 s.second -= to - from;
00079 }
00080
00082
00083
00084
00086
00087 template <class Device, class Char>
00088 struct PrintfState {
00089 PrintfState(Device dev, const Char * format)
00090 : device_(dev)
00091 , format_(format)
00092 , width_(0)
00093 , prec_(0)
00094 , flags_(0)
00095 , result_(0) {
00096 Advance();
00097 }
00098
00099 ~PrintfState() {
00100 }
00101
00102 #define LOKI_PRINTF_STATE_FORWARD(type) \
00103 PrintfState& operator()(type par) {\
00104 return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \
00105 }
00106
00107 LOKI_PRINTF_STATE_FORWARD(bool)
00108 LOKI_PRINTF_STATE_FORWARD(char)
00109 LOKI_PRINTF_STATE_FORWARD(signed char)
00110 LOKI_PRINTF_STATE_FORWARD(unsigned char)
00111 LOKI_PRINTF_STATE_FORWARD(signed short)
00112 LOKI_PRINTF_STATE_FORWARD(unsigned short)
00113 LOKI_PRINTF_STATE_FORWARD(signed int)
00114 LOKI_PRINTF_STATE_FORWARD(signed long)
00115 #if (defined(_WIN32) || defined(_WIN64))
00116 LOKI_PRINTF_STATE_FORWARD(unsigned long)
00117 #else
00118
00119 LOKI_PRINTF_STATE_FORWARD(unsigned int)
00120 #endif
00121
00122
00123 PrintfState& operator()(LOKI_SAFEFORMAT_UNSIGNED_LONG i) {
00124 if (result_ == -1) return *this;
00125
00126
00127 ReadFlags();
00128 if (*format_ == '*') {
00129
00130 SetWidth(static_cast<size_t>(i));
00131 ++format_;
00132 return *this;
00133 }
00134 ReadWidth();
00135
00136 if (*format_ == '.') {
00137
00138 if (format_[1] == '*') {
00139
00140 SetPrec(static_cast<size_t>(i));
00141 format_ += 2;
00142 return *this;
00143 }
00144 ReadPrecision();
00145 }
00146 ReadModifiers();
00147
00148 if (ForceShort()) {
00149
00150 const Char c = *format_;
00151 if (c == 'x' || c == 'X' || c == 'u' || c == 'o') {
00152 i = static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(static_cast<unsigned short>(i));
00153 }
00154 }
00155 FormatWithCurrentFlags(i);
00156 return *this;
00157 }
00158
00159 PrintfState& operator()(void* n) {
00160 if (result_ == -1) return *this;
00161 PrintUsing_snprintf(n,"p");
00162 return *this;
00163 }
00164
00165 PrintfState& operator()(double n) {
00166 if (result_ == -1) return *this;
00167 PrintUsing_snprintf(n,"eEfgG");
00168 return *this;
00169 }
00170
00171 PrintfState& operator()(long double n) {
00172 if (result_ == -1) return *this;
00173 PrintUsing_snprintf(n,"eEfgG");
00174 return *this;
00175 }
00176
00177
00178 PrintfState& operator()(int * pi) {
00179 return StoreCountHelper(pi);
00180 }
00181
00182
00183 PrintfState& operator()(short * pi) {
00184 return StoreCountHelper(pi);
00185 }
00186
00187
00188 PrintfState& operator()(long * pi) {
00189 return StoreCountHelper(pi);
00190 }
00191
00192 PrintfState& operator()(const std::string& stdstr) {
00193 return operator()(stdstr.c_str());
00194 }
00195
00196 PrintfState& operator()(const char *const s) {
00197 if (result_ == -1) return *this;
00198 ReadLeaders();
00199 const char fmt = *format_;
00200 if (fmt == 'p') {
00201 FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(s));
00202 return *this;
00203 }
00204 if (fmt != 's') {
00205 result_ = -1;
00206 return *this;
00207 }
00208 const size_t len = std::min(strlen(s), prec_);
00209 if (width_ > len) {
00210 if (LeftJustify()) {
00211 Write(s, s + len);
00212 Fill(' ', width_ - len);
00213 } else {
00214 Fill(' ', width_ - len);
00215 Write(s, s + len);
00216 }
00217 } else {
00218 Write(s, s + len);
00219 }
00220 Next();
00221 return *this;
00222 }
00223
00224 PrintfState& operator()(const void *const p) {
00225 return (*this)(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(p));
00226 }
00227
00228
00229 operator int() const {
00230 return static_cast<int>(result_);
00231 }
00232
00233 private:
00234 PrintfState& operator=(const PrintfState&);
00235 template <typename T>
00236 PrintfState& StoreCountHelper(T *const pi) {
00237 if (result_ == -1) return *this;
00238 ReadLeaders();
00239 const char fmt = *format_;
00240 if (fmt == 'p') {
00241 FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(pi));
00242 return *this;
00243 }
00244 if (fmt != 'n') {
00245 result_ = -1;
00246 return *this;
00247 }
00248 assert(pi != 0);
00249 *pi = result_;
00250 Next();
00251 return *this;
00252 }
00253
00254 void FormatWithCurrentFlags(const LOKI_SAFEFORMAT_UNSIGNED_LONG i) {
00255
00256 Char formatChar = *format_;
00257 bool isSigned = formatChar == 'd' || formatChar == 'i';
00258 if (formatChar == 'p') {
00259 formatChar = 'x';
00260 SetAlternateForm();
00261 isSigned = true;
00262 }
00263 if (!strchr("cdiuoxX", formatChar)) {
00264 result_ = -1;
00265 return;
00266 }
00267 Char buf[
00268 sizeof(LOKI_SAFEFORMAT_UNSIGNED_LONG) * 3
00269 + 1
00270 + 2
00271 + 1];
00272 const Char *const bufEnd = buf + (sizeof(buf) / sizeof(Char));
00273 Char * bufLast = buf + (sizeof(buf) / sizeof(Char) - 1);
00274 Char signChar = 0;
00275 unsigned int base = 10;
00276
00277 if (formatChar == 'c') {
00278
00279
00280 ResetFillZeros();
00281 *bufLast = static_cast<char>(i);
00282 } else {
00283
00284 const bool negative = isSigned && static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i) < 0;
00285 if (formatChar == 'o') base = 8;
00286 else if (formatChar == 'x' || formatChar == 'X') base = 16;
00287 bufLast = isSigned
00288 ? RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i), bufLast, base,
00289 formatChar == 'X')
00290 : RenderWithoutSign(i, bufLast, base,
00291 formatChar == 'X');
00292
00293 if (isSigned) {
00294 negative ? signChar = '-'
00295 : ShowSignAlways() ? signChar = '+'
00296 : Blank() ? signChar = ' '
00297 : 0;
00298 }
00299 }
00300
00301 size_t
00302 countDigits = bufEnd - bufLast,
00303 countZeros = prec_ != size_t(-1) && countDigits < prec_ &&
00304 formatChar != 'c'
00305 ? prec_ - countDigits
00306 : 0,
00307 countBase = base != 10 && AlternateForm() && i != 0
00308 ? (base == 16 ? 2 : countZeros > 0 ? 0 : 1)
00309 : 0,
00310 countSign = (signChar != 0),
00311 totalPrintable = countDigits + countZeros + countBase + countSign;
00312 size_t countPadLeft = 0, countPadRight = 0;
00313 if (width_ > totalPrintable) {
00314 if (LeftJustify()) {
00315 countPadRight = width_ - totalPrintable;
00316 countPadLeft = 0;
00317 } else {
00318 countPadLeft = width_ - totalPrintable;
00319 countPadRight = 0;
00320 }
00321 }
00322 if (FillZeros() && prec_ == size_t(-1)) {
00323
00324 countZeros = countPadLeft;
00325 countPadLeft = 0;
00326 }
00327
00328 Fill(' ', countPadLeft);
00329 if (signChar != 0) Write(&signChar, &signChar + 1);
00330 if (countBase > 0) Fill('0', 1);
00331 if (countBase == 2) Fill(formatChar, 1);
00332 Fill('0', countZeros);
00333 Write(bufLast, bufEnd);
00334 Fill(' ', countPadRight);
00335
00336 Next();
00337 }
00338
00339 void Write(const Char* b, const Char* e) {
00340 if (result_ < 0) return;
00341 const LOKI_SAFEFORMAT_SIGNED_LONG x = e - b;
00342 write(device_, b, e);
00343 result_ += x;
00344 }
00345
00346 template <class Value>
00347 void PrintUsing_snprintf(Value n, const char* check_fmt_char) {
00348 const Char *const fmt = format_ - 1;
00349 assert(*fmt == '%');
00350
00351 ReadLeaders();
00352
00353 if (!strchr(check_fmt_char, *format_)) {
00354 result_ = -1;
00355 return;
00356 }
00357
00358 ++format_;
00359 Char fmtBuf[128], resultBuf[1024];
00360 if (format_ >= fmt + sizeof(fmtBuf) / sizeof(Char)) {
00361 result_ = -1;
00362 return;
00363 }
00364 memcpy(fmtBuf, fmt, (format_ - fmt) * sizeof(Char));
00365 fmtBuf[format_ - fmt] = 0;
00366
00367 const int stored =
00368 #ifdef _MSC_VER
00369 #if _MSC_VER < 1400
00370 _snprintf
00371 #else
00372 _snprintf_s
00373 #endif
00374 #else
00375 snprintf
00376 #endif
00377 (resultBuf, sizeof(resultBuf) / sizeof(Char), fmtBuf, n);
00378
00379 if (stored < 0) {
00380 result_ = -1;
00381 return;
00382 }
00383 Write(resultBuf, resultBuf + strlen(resultBuf));
00384 Advance();
00385 }
00386
00387 void Fill(const Char c, size_t n) {
00388 for (; n > 0; --n) {
00389 Write(&c, &c + 1);
00390 }
00391 }
00392
00393 Char* RenderWithoutSign(LOKI_SAFEFORMAT_UNSIGNED_LONG n, char* bufLast,
00394 unsigned int base, bool uppercase) {
00395 const Char hex1st = uppercase ? 'A' : 'a';
00396 for (;;) {
00397 const LOKI_SAFEFORMAT_UNSIGNED_LONG next = n / base;
00398 #ifdef _MSC_VER
00399 #pragma warning(push)
00400 #pragma warning(disable: 4244)
00401 #endif
00402 Char c = n - next * base;
00403 #ifdef _MSC_VER
00404 #pragma warning(pop)
00405 #endif
00406 c += (c <= 9) ? '0' : hex1st - 10;
00407 *bufLast = c;
00408 n = next;
00409 if (n == 0) break;
00410 --bufLast;
00411 }
00412 return bufLast;
00413 }
00414
00415 char* RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char* bufLast, unsigned int base,
00416 bool uppercase) {
00417 if (n != LONG_MIN) {
00418 return RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n < 0 ? -n : n),
00419 bufLast, base, uppercase);
00420 }
00421
00422 char* save = bufLast;
00423 ++n;
00424 bufLast = RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n),
00425 bufLast, base, uppercase);
00426 --(*save);
00427 return bufLast;
00428 }
00429
00430 void Next() {
00431 ++format_;
00432 Advance();
00433 }
00434
00435 void Advance() {
00436 ResetAll();
00437 const Char* begin = format_;
00438 for (;;) {
00439 if (*format_ == '%') {
00440 if (format_[1] != '%') {
00441 Write(begin, format_);
00442 ++format_;
00443 break;
00444 }
00445
00446 Write(begin, ++format_);
00447 begin = ++format_;
00448 continue;
00449 }
00450 if (*format_ == 0) {
00451 Write(begin, format_);
00452 break;
00453 }
00454 ++format_;
00455 }
00456 }
00457
00458 void ReadFlags() {
00459 for (;; ++format_) {
00460 switch (*format_) {
00461 case '-': SetLeftJustify(); break;
00462 case '+': SetShowSignAlways(); break;
00463 case ' ': SetBlank(); break;
00464 case '#': SetAlternateForm(); break;
00465 case '0': SetFillZeros(); break;
00466 default: return;
00467 }
00468 }
00469 }
00470
00471 void ParseDecimalSizeT(size_t& dest) {
00472 if (!std::isdigit(*format_, std::locale())) return;
00473 size_t r = 0;
00474 do {
00475
00476 r *= 10;
00477 r += *format_ - '0';
00478 ++format_;
00479 } while (std::isdigit(*format_, std::locale()));
00480 dest = r;
00481 }
00482
00483 void ReadWidth() {
00484 ParseDecimalSizeT(width_);
00485 }
00486
00487 void ReadPrecision() {
00488 assert(*format_ == '.');
00489 ++format_;
00490 ParseDecimalSizeT(prec_);
00491 }
00492
00493 void ReadModifiers() {
00494 switch (*format_) {
00495 case 'h': SetForceShort(); ++format_; break;
00496 case 'l': ++format_; break;
00497
00498 }
00499 }
00500
00501 void ReadLeaders() {
00502 ReadFlags();
00503 ReadWidth();
00504 if (*format_ == '.') ReadPrecision();
00505 ReadModifiers();
00506 }
00507
00508 enum {
00509 leftJustify = 1,
00510 showSignAlways = 2,
00511 blank = 4,
00512 alternateForm = 8,
00513 fillZeros = 16,
00514 forceShort = 32
00515 };
00516
00517 bool LeftJustify() const { return (flags_ & leftJustify) != 0; }
00518 bool ShowSignAlways() const { return (flags_ & showSignAlways) != 0; }
00519 void SetWidth(size_t w) { width_ = w; }
00520 void SetLeftJustify() { flags_ |= leftJustify; }
00521 void SetShowSignAlways() { flags_ |= showSignAlways; }
00522 bool Blank() const { return (flags_ & blank) != 0; }
00523 bool AlternateForm() const { return (flags_ & alternateForm) != 0; }
00524 bool FillZeros() const { return (flags_ & fillZeros) != 0; }
00525 bool ForceShort() const { return (flags_ & forceShort) != 0; }
00526
00527 void SetPrec(size_t p) { prec_ = p; }
00528 void SetBlank() { flags_ |= blank; }
00529 void SetAlternateForm() { flags_ |= alternateForm; }
00530 void SetFillZeros() { flags_ |= fillZeros; }
00531 void ResetFillZeros() { flags_ &= ~fillZeros; }
00532 void SetForceShort() { flags_ |= forceShort; }
00533
00534 void ResetAll() {
00535 assert(result_ != EOF);
00536 width_ = 0;
00537 prec_ = size_t(-1);
00538 flags_ = 0;
00539 }
00540
00541
00542 Device device_;
00543 const Char* format_;
00544 size_t width_;
00545 size_t prec_;
00546 unsigned int flags_;
00547 LOKI_SAFEFORMAT_SIGNED_LONG result_;
00548 };
00549
00550 LOKI_EXPORT
00551 PrintfState<std::FILE*, char> Printf(const char* format);
00552
00553 LOKI_EXPORT
00554 PrintfState<std::FILE*, char> Printf(const std::string& format);
00555
00556 LOKI_EXPORT
00557 PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const char* format);
00558
00559 LOKI_EXPORT
00560 PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const std::string& format);
00561
00562 LOKI_EXPORT
00563 PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const char* format);
00564
00565 LOKI_EXPORT
00566 PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const std::string& format);
00567
00568 LOKI_EXPORT
00569 PrintfState<std::string&, char> SPrintf(std::string& s, const char* format);
00570
00571 LOKI_EXPORT
00572 PrintfState<std::string&, char> SPrintf(std::string& s, const std::string& format);
00573
00574 template <class T, class Char>
00575 PrintfState<T&, Char> XPrintf(T& device, const Char* format) {
00576 return PrintfState<T&, Char>(device, format);
00577 }
00578
00579 template <class T>
00580 PrintfState<T&, char> XPrintf(T& device, const std::string& format) {
00581 return PrintfState<T&, char>(device, format.c_str());
00582 }
00583
00584 template <class Char, std::size_t N>
00585 PrintfState<std::pair<Char*, std::size_t>, Char>
00586 BufPrintf(Char (&buf)[N], const Char* format) {
00587 std::pair<Char*, std::size_t> temp(buf, N);
00588 return PrintfState<std::pair<Char*, std::size_t>, Char>(temp, format);
00589 }
00590
00591 }
00592
00593
00594 #endif // end file guardian
00595