summaryrefslogtreecommitdiff
path: root/shared/loki/SafeFormat.h
diff options
context:
space:
mode:
Diffstat (limited to 'shared/loki/SafeFormat.h')
-rw-r--r--shared/loki/SafeFormat.h1022
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
bgstack15