diff options
Diffstat (limited to 'shared/loki/SafeFormat.h')
-rw-r--r-- | shared/loki/SafeFormat.h | 682 |
1 files changed, 0 insertions, 682 deletions
diff --git a/shared/loki/SafeFormat.h b/shared/loki/SafeFormat.h deleted file mode 100644 index bd2837f9..00000000 --- a/shared/loki/SafeFormat.h +++ /dev/null @@ -1,682 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2005 by Andrei Alexandrescu -// Copyright (c) 2006 Peter Kümmel -// Permission to use, copy, modify, distribute, and sell this software for any -// 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 -// warranty. -//////////////////////////////////////////////////////////////////////////////// -#ifndef LOKI_SAFEFORMAT_INC_ -#define LOKI_SAFEFORMAT_INC_ - -// $Id: SafeFormat.h 911 2008-12-15 20:55:24Z syntheticpp $ - - -//////////////////////////////////////////////////////////////////////////////// -// 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 -//////////////////////////////////////////////////////////////////////////////// - -#include <cstdio> -#include <climits> -#include <string> -#include <cstring> -#include <stdexcept> -#include <utility> -#include <cassert> -#include <locale> -#include <iostream> - -#include <loki/LokiExport.h> - - -// long is 32 bit on 64-bit Windows! -// intptr_t used to get 64 bit on Win64 -#if defined(_WIN32) || defined(_WIN64) -# define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t -# define LOKI_SAFEFORMAT_UNSIGNED_LONG uintptr_t -#else -# define LOKI_SAFEFORMAT_SIGNED_LONG signed long -# define LOKI_SAFEFORMAT_UNSIGNED_LONG unsigned long -#endif - -// Windows headers could have min/max defined -#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; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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() - { - } - -#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) -#if (defined(_WIN32) || defined(_WIN64)) - LOKI_PRINTF_STATE_FORWARD(unsigned long) -#else - // 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_; - 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)); - } - } - 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()(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; - } - 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); - } - else - { - Fill(' ', width_ - len); - Write(s, s + len); - } - } - else - { - Write(s, s + len); - } - 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; - } - 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; - } - } - 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(); - } - - 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; - } - - 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 -#else - _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 - } - - void Fill(const Char c, size_t n) - { - for (; n > 0; --n) - { - Write(&c, &c + 1); - } - } - - 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; - } - - 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; - } - - 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; - } - // It's a "%%" - Write(begin, ++format_); - begin = ++format_; - continue; - } - if (*format_ == 0) - { - Write(begin, format_); - break; - } - ++format_; - } - } - - 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 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 ReadLeaders() - { - ReadFlags(); - ReadWidth(); - if (*format_ == '.') ReadPrecision(); - ReadModifiers(); - } - - 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; - } - - // 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> Printf(const char* format); - -LOKI_EXPORT -PrintfState<std::FILE*, char> Printf(const std::string& format); - -LOKI_EXPORT -PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const char* format); - -LOKI_EXPORT -PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const std::string& format); - -LOKI_EXPORT -PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const char* format); - -LOKI_EXPORT -PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const std::string& format); - -LOKI_EXPORT -PrintfState<std::string&, char> SPrintf(std::string& s, const char* format); - -LOKI_EXPORT -PrintfState<std::string&, char> SPrintf(std::string& s, const std::string& 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 - - -#endif // end file guardian - |