diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:10:11 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:10:11 +0200 |
commit | c0cdb2ad99a1e2a6ade5ce76c91177a79258e669 (patch) | |
tree | 4701a015385d9a6a5a4ba99a8f1f5d400fff26b1 /shared/loki/SafeFormat.h | |
parent | 3.13 (diff) | |
download | FreeFileSync-c0cdb2ad99a1e2a6ade5ce76c91177a79258e669.tar.gz FreeFileSync-c0cdb2ad99a1e2a6ade5ce76c91177a79258e669.tar.bz2 FreeFileSync-c0cdb2ad99a1e2a6ade5ce76c91177a79258e669.zip |
3.14
Diffstat (limited to 'shared/loki/SafeFormat.h')
-rw-r--r-- | shared/loki/SafeFormat.h | 1022 |
1 files changed, 557 insertions, 465 deletions
diff --git a/shared/loki/SafeFormat.h b/shared/loki/SafeFormat.h index 9d948581..2734e972 100644 --- a/shared/loki/SafeFormat.h +++ b/shared/loki/SafeFormat.h @@ -5,8 +5,8 @@ // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. -// The author makes no representations about the suitability of this software -// for any purpose. It is provided "as is" without express or implied +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied // warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_SAFEFORMAT_INC_ @@ -16,8 +16,8 @@ //////////////////////////////////////////////////////////////////////////////// -// This file contains definitions for SafePrintf. SafeScanf coming soon (the -// design is similar). +// This file contains definitions for SafePrintf. SafeScanf coming soon (the +// design is similar). // See Alexandrescu, Andrei: Type-safe Formatting, C/C++ Users Journal, Aug 2005 //////////////////////////////////////////////////////////////////////////////// @@ -45,328 +45,375 @@ #endif // Windows headers could have min/max defined -#ifdef max -# undef max -#endif -#ifdef min -# undef min -#endif +#ifdef max +# undef max +#endif +#ifdef min +# undef min +#endif namespace Loki { - // Crude writing method: writes straight to the file, unbuffered - // Must be combined with a buffer to work properly (and efficiently) - LOKI_EXPORT - void write(std::FILE* f, const char* from, const char* to); - - // Write to an ostream - LOKI_EXPORT - void write(std::ostream& f, const char* from, const char* to); - - // Write to a string - LOKI_EXPORT - void write(std::string& s, const char* from, const char* to); - - // Write to a fixed-size buffer - template <class Char> - void write(std::pair<Char*, std::size_t>& s, const Char* from, const Char* to) { - assert(from <= to); - if(from + s.second < to) - throw std::overflow_error(""); - // s.first: position one past the final copied element - s.first = std::copy(from, to, s.first); - // remaining buffer size - s.second -= to - from; +// Crude writing method: writes straight to the file, unbuffered +// Must be combined with a buffer to work properly (and efficiently) +LOKI_EXPORT +void write(std::FILE* f, const char* from, const char* to); + +// Write to an ostream +LOKI_EXPORT +void write(std::ostream& f, const char* from, const char* to); + +// Write to a string +LOKI_EXPORT +void write(std::string& s, const char* from, const char* to); + +// Write to a fixed-size buffer +template <class Char> +void write(std::pair<Char*, std::size_t>& s, const Char* from, const Char* to) +{ + assert(from <= to); + if(from + s.second < to) + throw std::overflow_error(""); + // s.first: position one past the final copied element + s.first = std::copy(from, to, s.first); + // remaining buffer size + s.second -= to - from; +} + +//////////////////////////////////////////////////////////////////////////////// +// PrintfState class template +// Holds the formatting state, and implements operator() to format stuff +// Todo: make sure errors are handled properly +//////////////////////////////////////////////////////////////////////////////// + +template <class Device, class Char> +struct PrintfState +{ + PrintfState(Device dev, const Char* format) + : device_(dev) + , format_(format) + , width_(0) + , prec_(0) + , flags_(0) + , result_(0) + { + Advance(); } - //////////////////////////////////////////////////////////////////////////////// - // PrintfState class template - // Holds the formatting state, and implements operator() to format stuff - // Todo: make sure errors are handled properly - //////////////////////////////////////////////////////////////////////////////// - - template <class Device, class Char> - struct PrintfState { - PrintfState(Device dev, const Char * format) - : device_(dev) - , format_(format) - , width_(0) - , prec_(0) - , flags_(0) - , result_(0) { - Advance(); - } - - ~PrintfState() { - } + ~PrintfState() + { + } - #define LOKI_PRINTF_STATE_FORWARD(type) \ +#define LOKI_PRINTF_STATE_FORWARD(type) \ PrintfState& operator()(type par) {\ return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \ } - LOKI_PRINTF_STATE_FORWARD(bool) - LOKI_PRINTF_STATE_FORWARD(char) - LOKI_PRINTF_STATE_FORWARD(signed char) - LOKI_PRINTF_STATE_FORWARD(unsigned char) - LOKI_PRINTF_STATE_FORWARD(signed short) - LOKI_PRINTF_STATE_FORWARD(unsigned short) - LOKI_PRINTF_STATE_FORWARD(signed int) - LOKI_PRINTF_STATE_FORWARD(signed long) + LOKI_PRINTF_STATE_FORWARD(bool) + LOKI_PRINTF_STATE_FORWARD(char) + LOKI_PRINTF_STATE_FORWARD(signed char) + LOKI_PRINTF_STATE_FORWARD(unsigned char) + LOKI_PRINTF_STATE_FORWARD(signed short) + LOKI_PRINTF_STATE_FORWARD(unsigned short) + LOKI_PRINTF_STATE_FORWARD(signed int) + LOKI_PRINTF_STATE_FORWARD(signed long) #if (defined(_WIN32) || defined(_WIN64)) - LOKI_PRINTF_STATE_FORWARD(unsigned long) + LOKI_PRINTF_STATE_FORWARD(unsigned long) #else - // on Windows already defined by uintptr_t - LOKI_PRINTF_STATE_FORWARD(unsigned int) + // on Windows already defined by uintptr_t + LOKI_PRINTF_STATE_FORWARD(unsigned int) #endif - // Print (or gobble in case of the "*" specifier) an int - PrintfState& operator()(LOKI_SAFEFORMAT_UNSIGNED_LONG i) { - if (result_ == -1) return *this; // don't even bother - // % [flags] [width] [.prec] [modifier] type_char - // Fetch the flags - ReadFlags(); - if (*format_ == '*') { - // read the width and get out - SetWidth(static_cast<size_t>(i)); - ++format_; + // Print (or gobble in case of the "*" specifier) an int + PrintfState& operator()(LOKI_SAFEFORMAT_UNSIGNED_LONG i) + { + if (result_ == -1) return *this; // don't even bother + // % [flags] [width] [.prec] [modifier] type_char + // Fetch the flags + ReadFlags(); + if (*format_ == '*') + { + // read the width and get out + SetWidth(static_cast<size_t>(i)); + ++format_; + return *this; + } + ReadWidth(); + // precision + if (*format_ == '.') + { + // deal with precision + if (format_[1] == '*') + { + // read the precision and get out + SetPrec(static_cast<size_t>(i)); + format_ += 2; return *this; } - ReadWidth(); - // precision - if (*format_ == '.') { - // deal with precision - if (format_[1] == '*') { - // read the precision and get out - SetPrec(static_cast<size_t>(i)); - format_ += 2; - return *this; - } - ReadPrecision(); - } - ReadModifiers(); - // input size modifier - if (ForceShort()) { - // short int - const Char c = *format_; - if (c == 'x' || c == 'X' || c == 'u' || c == 'o') { - i = static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(static_cast<unsigned short>(i)); - } + ReadPrecision(); + } + ReadModifiers(); + // input size modifier + if (ForceShort()) + { + // short int + const Char c = *format_; + if (c == 'x' || c == 'X' || c == 'u' || c == 'o') + { + i = static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(static_cast<unsigned short>(i)); } - FormatWithCurrentFlags(i); - return *this; } + FormatWithCurrentFlags(i); + return *this; + } - PrintfState& operator()(void* n) { - if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"p"); - return *this; - } - - PrintfState& operator()(double n) { - if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"eEfgG"); - return *this; - } + PrintfState& operator()(void* n) + { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"p"); + return *this; + } - PrintfState& operator()(long double n) { - if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"eEfgG"); - return *this; - } + PrintfState& operator()(double n) + { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"eEfgG"); + return *this; + } - // Store the number of characters printed so far - PrintfState& operator()(int * pi) { - return StoreCountHelper(pi); - } - - // Store the number of characters printed so far - PrintfState& operator()(short * pi) { - return StoreCountHelper(pi); - } - - // Store the number of characters printed so far - PrintfState& operator()(long * pi) { - return StoreCountHelper(pi); + PrintfState& operator()(long double n) + { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"eEfgG"); + return *this; + } + + // Store the number of characters printed so far + PrintfState& operator()(int* pi) + { + return StoreCountHelper(pi); + } + + // Store the number of characters printed so far + PrintfState& operator()(short* pi) + { + return StoreCountHelper(pi); + } + + // Store the number of characters printed so far + PrintfState& operator()(long* pi) + { + return StoreCountHelper(pi); + } + + PrintfState& operator()(const std::string& stdstr) + { + return operator()(stdstr.c_str()); + } + + PrintfState& operator()(const char* const s) + { + if (result_ == -1) return *this; + ReadLeaders(); + const char fmt = *format_; + if (fmt == 'p') + { + FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(s)); + return *this; } - - PrintfState& operator()(const std::string& stdstr) { - return operator()(stdstr.c_str()); + if (fmt != 's') + { + result_ = -1; + return *this; } - - PrintfState& operator()(const char *const s) { - if (result_ == -1) return *this; - ReadLeaders(); - const char fmt = *format_; - if (fmt == 'p') { - FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(s)); - return *this; - } - if (fmt != 's') { - result_ = -1; - return *this; + const size_t len = std::min(std::strlen(s), prec_); + if (width_ > len) + { + if (LeftJustify()) + { + Write(s, s + len); + Fill(' ', width_ - len); } - const size_t len = std::min(std::strlen(s), prec_); - if (width_ > len) { - if (LeftJustify()) { - Write(s, s + len); - Fill(' ', width_ - len); - } else { - Fill(' ', width_ - len); - Write(s, s + len); - } - } else { + else + { + Fill(' ', width_ - len); Write(s, s + len); } - Next(); - return *this; } - - PrintfState& operator()(const void *const p) { - return (*this)(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(p)); + else + { + Write(s, s + len); } - - // read the result - operator int() const { - return static_cast<int>(result_); + Next(); + return *this; + } + + PrintfState& operator()(const void* const p) + { + return (*this)(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(p)); + } + + // read the result + operator int() const + { + return static_cast<int>(result_); + } + +private: + PrintfState& operator=(const PrintfState&); + template <typename T> + PrintfState& StoreCountHelper(T* const pi) + { + if (result_ == -1) return *this; // don't even bother + ReadLeaders(); + const char fmt = *format_; + if (fmt == 'p') // pointer + { + FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(pi)); + return *this; } - - private: - PrintfState& operator=(const PrintfState&); - template <typename T> - PrintfState& StoreCountHelper(T *const pi) { - if (result_ == -1) return *this; // don't even bother - ReadLeaders(); - const char fmt = *format_; - if (fmt == 'p') { // pointer - FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(pi)); - return *this; - } - if (fmt != 'n') { - result_ = -1; - return *this; - } - assert(pi != 0); - *pi = result_; - Next(); + if (fmt != 'n') + { + result_ = -1; return *this; } + assert(pi != 0); + *pi = result_; + Next(); + return *this; + } - void FormatWithCurrentFlags(const LOKI_SAFEFORMAT_UNSIGNED_LONG i) { - // look at the format character - Char formatChar = *format_; - bool isSigned = formatChar == 'd' || formatChar == 'i'; - if (formatChar == 'p') { - formatChar = 'x'; // pointers go to hex - SetAlternateForm(); // printed with '0x' in front - isSigned = true; // that's what gcc does - } - if (!strchr("cdiuoxX", formatChar)) { - result_ = -1; - return; - } - Char buf[ - sizeof(LOKI_SAFEFORMAT_UNSIGNED_LONG) * 3 // digits - + 1 // sign or ' ' - + 2 // 0x or 0X - + 1]; // terminating zero - const Char *const bufEnd = buf + (sizeof(buf) / sizeof(Char)); - Char * bufLast = buf + (sizeof(buf) / sizeof(Char) - 1); - Char signChar = 0; - unsigned int base = 10; - - if (formatChar == 'c') { - // Format only one character - // The 'fill with zeros' flag is ignored - ResetFillZeros(); - *bufLast = static_cast<char>(i); - } else { - // TODO: inefficient code, refactor - const bool negative = isSigned && static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i) < 0; - if (formatChar == 'o') base = 8; - else if (formatChar == 'x' || formatChar == 'X') base = 16; - bufLast = isSigned - ? RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i), bufLast, base, - formatChar == 'X') - : RenderWithoutSign(i, bufLast, base, - formatChar == 'X'); - // Add the sign - if (isSigned) { - negative ? signChar = '-' - : ShowSignAlways() ? signChar = '+' - : Blank() ? signChar = ' ' - : 0; - } - } - // precision - size_t - countDigits = bufEnd - bufLast, - countZeros = prec_ != size_t(-1) && countDigits < prec_ && - formatChar != 'c' - ? prec_ - countDigits - : 0, - countBase = base != 10 && AlternateForm() && i != 0 - ? (base == 16 ? 2 : countZeros > 0 ? 0 : 1) - : 0, - countSign = (signChar != 0), - totalPrintable = countDigits + countZeros + countBase + countSign; - size_t countPadLeft = 0, countPadRight = 0; - if (width_ > totalPrintable) { - if (LeftJustify()) { - countPadRight = width_ - totalPrintable; - countPadLeft = 0; - } else { - countPadLeft = width_ - totalPrintable; - countPadRight = 0; - } + void FormatWithCurrentFlags(const LOKI_SAFEFORMAT_UNSIGNED_LONG i) + { + // look at the format character + Char formatChar = *format_; + bool isSigned = formatChar == 'd' || formatChar == 'i'; + if (formatChar == 'p') + { + formatChar = 'x'; // pointers go to hex + SetAlternateForm(); // printed with '0x' in front + isSigned = true; // that's what gcc does + } + if (!strchr("cdiuoxX", formatChar)) + { + result_ = -1; + return; + } + Char buf[ + sizeof(LOKI_SAFEFORMAT_UNSIGNED_LONG) * 3 // digits + + 1 // sign or ' ' + + 2 // 0x or 0X + + 1]; // terminating zero + const Char* const bufEnd = buf + (sizeof(buf) / sizeof(Char)); + Char* bufLast = buf + (sizeof(buf) / sizeof(Char) - 1); + Char signChar = 0; + unsigned int base = 10; + + if (formatChar == 'c') + { + // Format only one character + // The 'fill with zeros' flag is ignored + ResetFillZeros(); + *bufLast = static_cast<char>(i); + } + else + { + // TODO: inefficient code, refactor + const bool negative = isSigned && static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i) < 0; + if (formatChar == 'o') base = 8; + else if (formatChar == 'x' || formatChar == 'X') base = 16; + bufLast = isSigned + ? RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i), bufLast, base, + formatChar == 'X') + : RenderWithoutSign(i, bufLast, base, + formatChar == 'X'); + // Add the sign + if (isSigned) + { + negative ? signChar = '-' + : ShowSignAlways() ? signChar = '+' + : Blank() ? signChar = ' ' + : 0; } - if (FillZeros() && prec_ == size_t(-1)) { - // pad with zeros and no precision - transfer padding to precision - countZeros = countPadLeft; + } + // precision + size_t + countDigits = bufEnd - bufLast, + countZeros = prec_ != size_t(-1) && countDigits < prec_ && + formatChar != 'c' + ? prec_ - countDigits + : 0, + countBase = base != 10 && AlternateForm() && i != 0 + ? (base == 16 ? 2 : countZeros > 0 ? 0 : 1) + : 0, + countSign = (signChar != 0), + totalPrintable = countDigits + countZeros + countBase + countSign; + size_t countPadLeft = 0, countPadRight = 0; + if (width_ > totalPrintable) + { + if (LeftJustify()) + { + countPadRight = width_ - totalPrintable; countPadLeft = 0; } - // ok, all computed, ready to print to device - Fill(' ', countPadLeft); - if (signChar != 0) Write(&signChar, &signChar + 1); - if (countBase > 0) Fill('0', 1); - if (countBase == 2) Fill(formatChar, 1); - Fill('0', countZeros); - Write(bufLast, bufEnd); - Fill(' ', countPadRight); - // done, advance - Next(); + else + { + countPadLeft = width_ - totalPrintable; + countPadRight = 0; + } } - - void Write(const Char* b, const Char* e) { - if (result_ < 0) return; - const LOKI_SAFEFORMAT_SIGNED_LONG x = e - b; - write(device_, b, e); - result_ += x; + if (FillZeros() && prec_ == size_t(-1)) + { + // pad with zeros and no precision - transfer padding to precision + countZeros = countPadLeft; + countPadLeft = 0; } + // ok, all computed, ready to print to device + Fill(' ', countPadLeft); + if (signChar != 0) Write(&signChar, &signChar + 1); + if (countBase > 0) Fill('0', 1); + if (countBase == 2) Fill(formatChar, 1); + Fill('0', countZeros); + Write(bufLast, bufEnd); + Fill(' ', countPadRight); + // done, advance + Next(); + } - template <class Value> - void PrintUsing_snprintf(Value n, const char* check_fmt_char) { - const Char *const fmt = format_ - 1; - assert(*fmt == '%'); - // enforce format string validity - ReadLeaders(); - // enforce format spec - if (!strchr(check_fmt_char, *format_)) { - result_ = -1; - return; - } - // format char validated, copy it to a temp and use legacy sprintf - ++format_; - Char fmtBuf[128], resultBuf[1024]; - if (format_ >= fmt + sizeof(fmtBuf) / sizeof(Char)) { - result_ = -1; - return; - } - memcpy(fmtBuf, fmt, (format_ - fmt) * sizeof(Char)); - fmtBuf[format_ - fmt] = 0; + void Write(const Char* b, const Char* e) + { + if (result_ < 0) return; + const LOKI_SAFEFORMAT_SIGNED_LONG x = e - b; + write(device_, b, e); + result_ += x; + } - const int stored = + template <class Value> + void PrintUsing_snprintf(Value n, const char* check_fmt_char) + { + const Char* const fmt = format_ - 1; + assert(*fmt == '%'); + // enforce format string validity + ReadLeaders(); + // enforce format spec + if (!strchr(check_fmt_char, *format_)) + { + result_ = -1; + return; + } + // format char validated, copy it to a temp and use legacy sprintf + ++format_; + Char fmtBuf[128], resultBuf[1024]; + if (format_ >= fmt + sizeof(fmtBuf) / sizeof(Char)) + { + result_ = -1; + return; + } + memcpy(fmtBuf, fmt, (format_ - fmt) * sizeof(Char)); + fmtBuf[format_ - fmt] = 0; + + const int stored = #ifdef _MSC_VER #if _MSC_VER < 1400 _snprintf @@ -374,214 +421,259 @@ namespace Loki _snprintf_s #endif #else - snprintf -#endif - (resultBuf, sizeof(resultBuf) / sizeof(Char), fmtBuf, n); - - if (stored < 0) { - result_ = -1; - return; - } - Write(resultBuf, resultBuf + strlen(resultBuf)); - Advance(); // output stuff to the next format directive - } + snprintf +#endif + (resultBuf, sizeof(resultBuf) / sizeof(Char), fmtBuf, n); - void Fill(const Char c, size_t n) { - for (; n > 0; --n) { - Write(&c, &c + 1); - } + if (stored < 0) + { + result_ = -1; + return; } - - Char* RenderWithoutSign(LOKI_SAFEFORMAT_UNSIGNED_LONG n, char* bufLast, - unsigned int base, bool uppercase) { - const Char hex1st = uppercase ? 'A' : 'a'; - for (;;) { - const LOKI_SAFEFORMAT_UNSIGNED_LONG next = n / base; - Char c = static_cast<Char>(n - next * base); - c = static_cast<Char>(c + (c <= 9 ? '0' : static_cast<Char>(hex1st - 10))); - *bufLast = c; - n = next; - if (n == 0) break; - --bufLast; - } - return bufLast; + Write(resultBuf, resultBuf + strlen(resultBuf)); + Advance(); // output stuff to the next format directive + } + + void Fill(const Char c, size_t n) + { + for (; n > 0; --n) + { + Write(&c, &c + 1); } + } - char* RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char* bufLast, unsigned int base, - bool uppercase) { - if (n != LONG_MIN) { - return RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n < 0 ? -n : n), - bufLast, base, uppercase); - } - // annoying corner case - char* save = bufLast; - ++n; - bufLast = RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n), - bufLast, base, uppercase); - --(*save); - return bufLast; + Char* RenderWithoutSign(LOKI_SAFEFORMAT_UNSIGNED_LONG n, char* bufLast, + unsigned int base, bool uppercase) + { + const Char hex1st = uppercase ? 'A' : 'a'; + for (;;) + { + const LOKI_SAFEFORMAT_UNSIGNED_LONG next = n / base; + Char c = static_cast<Char>(n - next * base); + c = static_cast<Char>(c + (c <= 9 ? '0' : static_cast<Char>(hex1st - 10))); + *bufLast = c; + n = next; + if (n == 0) break; + --bufLast; } - - void Next() { - ++format_; - Advance(); + return bufLast; + } + + char* RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char* bufLast, unsigned int base, + bool uppercase) + { + if (n != LONG_MIN) + { + return RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n < 0 ? -n : n), + bufLast, base, uppercase); } - - void Advance() { - ResetAll(); - const Char* begin = format_; - for (;;) { - if (*format_ == '%') { - if (format_[1] != '%') { // It's a format specifier - Write(begin, format_); - ++format_; - break; - } - // It's a "%%" - Write(begin, ++format_); - begin = ++format_; - continue; - } - if (*format_ == 0) { + // annoying corner case + char* save = bufLast; + ++n; + bufLast = RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n), + bufLast, base, uppercase); + --(*save); + return bufLast; + } + + void Next() + { + ++format_; + Advance(); + } + + void Advance() + { + ResetAll(); + const Char* begin = format_; + for (;;) + { + if (*format_ == '%') + { + if (format_[1] != '%') // It's a format specifier + { Write(begin, format_); + ++format_; break; } - ++format_; + // It's a "%%" + Write(begin, ++format_); + begin = ++format_; + continue; } - } - - void ReadFlags() { - for (;; ++format_) { - switch (*format_) { - case '-': SetLeftJustify(); break; - case '+': SetShowSignAlways(); break; - case ' ': SetBlank(); break; - case '#': SetAlternateForm(); break; - case '0': SetFillZeros(); break; - default: return; - } + if (*format_ == 0) + { + Write(begin, format_); + break; } - } - - void ParseDecimalSizeT(size_t& dest) { - if (!std::isdigit(*format_, std::locale())) return; - size_t r = 0; - do { - // TODO: inefficient - rewrite - r *= 10; - r += *format_ - '0'; - ++format_; - } while (std::isdigit(*format_, std::locale())); - dest = r; - } - - void ReadWidth() { - ParseDecimalSizeT(width_); - } - - void ReadPrecision() { - assert(*format_ == '.'); ++format_; - ParseDecimalSizeT(prec_); - } - - void ReadModifiers() { - switch (*format_) { - case 'h': SetForceShort(); ++format_; break; - case 'l': ++format_; break; - // more (C99 and platform-specific modifiers) to come + } + } + + void ReadFlags() + { + for (;; ++format_) + { + switch (*format_) + { + case '-': + SetLeftJustify(); + break; + case '+': + SetShowSignAlways(); + break; + case ' ': + SetBlank(); + break; + case '#': + SetAlternateForm(); + break; + case '0': + SetFillZeros(); + break; + default: + return; } } - - void ReadLeaders() { - ReadFlags(); - ReadWidth(); - if (*format_ == '.') ReadPrecision(); - ReadModifiers(); + } + + void ParseDecimalSizeT(size_t& dest) + { + if (!std::isdigit(*format_, std::locale())) return; + size_t r = 0; + do + { + // TODO: inefficient - rewrite + r *= 10; + r += *format_ - '0'; + ++format_; } - - enum { - leftJustify = 1, - showSignAlways = 2, - blank = 4, - alternateForm = 8, - fillZeros = 16, - forceShort = 32 - }; - - bool LeftJustify() const { return (flags_ & leftJustify) != 0; } - bool ShowSignAlways() const { return (flags_ & showSignAlways) != 0; } - void SetWidth(size_t w) { width_ = w; } - void SetLeftJustify() { flags_ |= leftJustify; } - void SetShowSignAlways() { flags_ |= showSignAlways; } - bool Blank() const { return (flags_ & blank) != 0; } - bool AlternateForm() const { return (flags_ & alternateForm) != 0; } - bool FillZeros() const { return (flags_ & fillZeros) != 0; } - bool ForceShort() const { return (flags_ & forceShort) != 0; } - - void SetPrec(size_t p) { prec_ = p; } - void SetBlank() { flags_ |= blank; } - void SetAlternateForm() { flags_ |= alternateForm; } - void SetFillZeros() { flags_ |= fillZeros; } - void ResetFillZeros() { flags_ &= ~fillZeros; } - void SetForceShort() { flags_ |= forceShort; } - - void ResetAll() { - assert(result_ != EOF); - width_ = 0; - prec_ = size_t(-1); - flags_ = 0; + while (std::isdigit(*format_, std::locale())); + dest = r; + } + + void ReadWidth() + { + ParseDecimalSizeT(width_); + } + + void ReadPrecision() + { + assert(*format_ == '.'); + ++format_; + ParseDecimalSizeT(prec_); + } + + void ReadModifiers() + { + switch (*format_) + { + case 'h': + SetForceShort(); + ++format_; + break; + case 'l': + ++format_; + break; + // more (C99 and platform-specific modifiers) to come } + } + + void ReadLeaders() + { + ReadFlags(); + ReadWidth(); + if (*format_ == '.') ReadPrecision(); + ReadModifiers(); + } - // state - Device device_; - const Char* format_; - size_t width_; - size_t prec_; - unsigned int flags_; - LOKI_SAFEFORMAT_SIGNED_LONG result_; + enum + { + leftJustify = 1, + showSignAlways = 2, + blank = 4, + alternateForm = 8, + fillZeros = 16, + forceShort = 32 }; - LOKI_EXPORT - PrintfState<std::FILE*, char> Printf(const char* format); + bool LeftJustify() const { return (flags_ & leftJustify) != 0; } + bool ShowSignAlways() const { return (flags_ & showSignAlways) != 0; } + void SetWidth(size_t w) { width_ = w; } + void SetLeftJustify() { flags_ |= leftJustify; } + void SetShowSignAlways() { flags_ |= showSignAlways; } + bool Blank() const { return (flags_ & blank) != 0; } + bool AlternateForm() const { return (flags_ & alternateForm) != 0; } + bool FillZeros() const { return (flags_ & fillZeros) != 0; } + bool ForceShort() const { return (flags_ & forceShort) != 0; } + + void SetPrec(size_t p) { prec_ = p; } + void SetBlank() { flags_ |= blank; } + void SetAlternateForm() { flags_ |= alternateForm; } + void SetFillZeros() { flags_ |= fillZeros; } + void ResetFillZeros() { flags_ &= ~fillZeros; } + void SetForceShort() { flags_ |= forceShort; } + + void ResetAll() + { + assert(result_ != EOF); + width_ = 0; + prec_ = size_t(-1); + flags_ = 0; + } - LOKI_EXPORT - PrintfState<std::FILE*, char> Printf(const std::string& format); + // state + Device device_; + const Char* format_; + size_t width_; + size_t prec_; + unsigned int flags_; + LOKI_SAFEFORMAT_SIGNED_LONG result_; +}; - LOKI_EXPORT - PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const char* format); +LOKI_EXPORT +PrintfState<std::FILE*, char> Printf(const char* format); - LOKI_EXPORT - PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const std::string& format); +LOKI_EXPORT +PrintfState<std::FILE*, char> Printf(const std::string& format); - LOKI_EXPORT - PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const char* format); +LOKI_EXPORT +PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const char* format); - LOKI_EXPORT - PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const std::string& format); +LOKI_EXPORT +PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const std::string& format); - LOKI_EXPORT - PrintfState<std::string&, char> SPrintf(std::string& s, const char* format); +LOKI_EXPORT +PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const char* format); - LOKI_EXPORT - PrintfState<std::string&, char> SPrintf(std::string& s, const std::string& format); +LOKI_EXPORT +PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const std::string& format); - template <class T, class Char> - PrintfState<T&, Char> XPrintf(T& device, const Char* format) { - return PrintfState<T&, Char>(device, format); - } +LOKI_EXPORT +PrintfState<std::string&, char> SPrintf(std::string& s, const char* format); - template <class T> - PrintfState<T&, char> XPrintf(T& device, const std::string& format) { - return PrintfState<T&, char>(device, format.c_str()); - } +LOKI_EXPORT +PrintfState<std::string&, char> SPrintf(std::string& s, const std::string& format); - template <class Char, std::size_t N> - PrintfState<std::pair<Char*, std::size_t>, Char> - BufPrintf(Char (&buf)[N], const Char* format) { - std::pair<Char*, std::size_t> temp(buf, N); - return PrintfState<std::pair<Char*, std::size_t>, Char>(temp, format); - } +template <class T, class Char> +PrintfState<T&, Char> XPrintf(T& device, const Char* format) +{ + return PrintfState<T&, Char>(device, format); +} + +template <class T> +PrintfState<T&, char> XPrintf(T& device, const std::string& format) +{ + return PrintfState<T&, char>(device, format.c_str()); +} + +template <class Char, std::size_t N> +PrintfState<std::pair<Char*, std::size_t>, Char> +BufPrintf(Char (&buf)[N], const Char* format) +{ + std::pair<Char*, std::size_t> temp(buf, N); + return PrintfState<std::pair<Char*, std::size_t>, Char>(temp, format); +} }// namespace Loki |