1 ////////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2005 by Andrei Alexandrescu
3 // Copyright (c) 2006 Peter Kümmel
4 // Permission to use, copy, modify, distribute, and sell this software for any
5 // purpose is hereby granted without fee, provided that the above copyright
6 // notice appear in all copies and that both that copyright notice and this
7 // permission notice appear in supporting documentation.
8 // The author makes no representations about the suitability of this software
9 // for any purpose. It is provided "as is" without express or implied
11 ////////////////////////////////////////////////////////////////////////////////
12 #ifndef LOKI_SAFEFORMAT_INC_
13 #define LOKI_SAFEFORMAT_INC_
15 // $Id: SafeFormat.h 911 2008-12-15 20:55:24Z syntheticpp $
18 ////////////////////////////////////////////////////////////////////////////////
19 // This file contains definitions for SafePrintf. SafeScanf coming soon (the
20 // design is similar).
21 // See Alexandrescu, Andrei: Type-safe Formatting, C/C++ Users Journal, Aug 2005
22 ////////////////////////////////////////////////////////////////////////////////
34 #include <loki/LokiExport.h>
37 // long is 32 bit on 64-bit Windows!
38 // intptr_t used to get 64 bit on Win64
39 #if defined(_WIN32) || defined(_WIN64)
40 # define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t
41 # define LOKI_SAFEFORMAT_UNSIGNED_LONG uintptr_t
43 # define LOKI_SAFEFORMAT_SIGNED_LONG signed long
44 # define LOKI_SAFEFORMAT_UNSIGNED_LONG unsigned long
47 // Windows headers could have min/max defined
58 // Crude writing method: writes straight to the file, unbuffered
59 // Must be combined with a buffer to work properly (and efficiently)
61 void write(std::FILE *f, const char *from, const char *to);
63 // Write to an ostream
65 void write(std::ostream &f, const char *from, const char *to);
69 void write(std::string &s, const char *from, const char *to);
71 // Write to a fixed-size buffer
73 void write(std::pair<Char *, std::size_t>& s, const Char *from, const Char *to)
76 if(from + s.second < to)
77 throw std::overflow_error("");
78 // s.first: position one past the final copied element
79 s.first = std::copy(from, to, s.first);
80 // remaining buffer size
81 s.second -= to - from;
84 ////////////////////////////////////////////////////////////////////////////////
85 // PrintfState class template
86 // Holds the formatting state, and implements operator() to format stuff
87 // Todo: make sure errors are handled properly
88 ////////////////////////////////////////////////////////////////////////////////
90 template <class Device, class Char>
93 PrintfState(Device dev, const Char *format)
108 #define LOKI_PRINTF_STATE_FORWARD(type) \
109 PrintfState& operator()(type par) {\
110 return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \
113 LOKI_PRINTF_STATE_FORWARD(bool)
114 LOKI_PRINTF_STATE_FORWARD(char)
115 LOKI_PRINTF_STATE_FORWARD(signed char)
116 LOKI_PRINTF_STATE_FORWARD(unsigned char)
117 LOKI_PRINTF_STATE_FORWARD(signed short)
118 LOKI_PRINTF_STATE_FORWARD(unsigned short)
119 LOKI_PRINTF_STATE_FORWARD(signed int)
120 LOKI_PRINTF_STATE_FORWARD(signed long)
121 #if (defined(_WIN32) || defined(_WIN64))
122 LOKI_PRINTF_STATE_FORWARD(unsigned long)
124 // on Windows already defined by uintptr_t
125 LOKI_PRINTF_STATE_FORWARD(unsigned int)
128 // Print (or gobble in case of the "*" specifier) an int
129 PrintfState &operator()(LOKI_SAFEFORMAT_UNSIGNED_LONG i)
131 if (result_ == -1) return *this; // don't even bother
132 // % [flags] [width] [.prec] [modifier] type_char
137 // read the width and get out
138 SetWidth(static_cast<size_t>(i));
146 // deal with precision
147 if (format_[1] == '*')
149 // read the precision and get out
150 SetPrec(static_cast<size_t>(i));
157 // input size modifier
161 const Char c = *format_;
162 if (c == 'x' || c == 'X' || c == 'u' || c == 'o')
164 i = static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(static_cast<unsigned short>(i));
167 FormatWithCurrentFlags(i);
171 PrintfState &operator()(void *n)
173 if (result_ == -1) return *this; // don't even bother
174 PrintUsing_snprintf(n,"p");
178 PrintfState &operator()(double n)
180 if (result_ == -1) return *this; // don't even bother
181 PrintUsing_snprintf(n,"eEfgG");
185 PrintfState &operator()(long double n)
187 if (result_ == -1) return *this; // don't even bother
188 PrintUsing_snprintf(n,"eEfgG");
192 // Store the number of characters printed so far
193 PrintfState &operator()(int *pi)
195 return StoreCountHelper(pi);
198 // Store the number of characters printed so far
199 PrintfState &operator()(short *pi)
201 return StoreCountHelper(pi);
204 // Store the number of characters printed so far
205 PrintfState &operator()(long *pi)
207 return StoreCountHelper(pi);
210 PrintfState &operator()(const std::string &stdstr)
212 return operator()(stdstr.c_str());
215 PrintfState &operator()(const char *const s)
217 if (result_ == -1) return *this;
219 const char fmt = *format_;
222 FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(s));
230 const size_t len = std::min(std::strlen(s), prec_);
236 Fill(' ', width_ - len);
240 Fill(' ', width_ - len);
252 PrintfState &operator()(const void *const p)
254 return (*this)(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(p));
260 return static_cast<int>(result_);
264 PrintfState &operator=(const PrintfState &);
265 template <typename T>
266 PrintfState &StoreCountHelper(T *const pi)
268 if (result_ == -1) return *this; // don't even bother
270 const char fmt = *format_;
271 if (fmt == 'p') // pointer
273 FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(pi));
287 void FormatWithCurrentFlags(const LOKI_SAFEFORMAT_UNSIGNED_LONG i)
289 // look at the format character
290 Char formatChar = *format_;
291 bool isSigned = formatChar == 'd' || formatChar == 'i';
292 if (formatChar == 'p')
294 formatChar = 'x'; // pointers go to hex
295 SetAlternateForm(); // printed with '0x' in front
296 isSigned = true; // that's what gcc does
298 if (!strchr("cdiuoxX", formatChar))
304 sizeof(LOKI_SAFEFORMAT_UNSIGNED_LONG) * 3 // digits
307 + 1]; // terminating zero
308 const Char *const bufEnd = buf + (sizeof(buf) / sizeof(Char));
309 Char *bufLast = buf + (sizeof(buf) / sizeof(Char) - 1);
311 unsigned int base = 10;
313 if (formatChar == 'c')
315 // Format only one character
316 // The 'fill with zeros' flag is ignored
318 *bufLast = static_cast<char>(i);
322 // TODO: inefficient code, refactor
323 const bool negative = isSigned && static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i) < 0;
324 if (formatChar == 'o') base = 8;
325 else if (formatChar == 'x' || formatChar == 'X') base = 16;
327 ? RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i), bufLast, base,
329 : RenderWithoutSign(i, bufLast, base,
334 negative ? signChar = '-'
335 : ShowSignAlways() ? signChar = '+'
336 : Blank() ? signChar = ' '
342 countDigits = bufEnd - bufLast,
343 countZeros = prec_ != size_t(-1) && countDigits < prec_ &&
345 ? prec_ - countDigits
347 countBase = base != 10 && AlternateForm() && i != 0
348 ? (base == 16 ? 2 : countZeros > 0 ? 0 : 1)
350 countSign = (signChar != 0),
351 totalPrintable = countDigits + countZeros + countBase + countSign;
352 size_t countPadLeft = 0, countPadRight = 0;
353 if (width_ > totalPrintable)
357 countPadRight = width_ - totalPrintable;
362 countPadLeft = width_ - totalPrintable;
366 if (FillZeros() && prec_ == size_t(-1))
368 // pad with zeros and no precision - transfer padding to precision
369 countZeros = countPadLeft;
372 // ok, all computed, ready to print to device
373 Fill(' ', countPadLeft);
374 if (signChar != 0) Write(&signChar, &signChar + 1);
375 if (countBase > 0) Fill('0', 1);
376 if (countBase == 2) Fill(formatChar, 1);
377 Fill('0', countZeros);
378 Write(bufLast, bufEnd);
379 Fill(' ', countPadRight);
384 void Write(const Char *b, const Char *e)
386 if (result_ < 0) return;
387 const LOKI_SAFEFORMAT_SIGNED_LONG x = e - b;
388 write(device_, b, e);
392 template <class Value>
393 void PrintUsing_snprintf(Value n, const char *check_fmt_char)
395 const Char *const fmt = format_ - 1;
397 // enforce format string validity
399 // enforce format spec
400 if (!strchr(check_fmt_char, *format_))
405 // format char validated, copy it to a temp and use legacy sprintf
407 Char fmtBuf[128], resultBuf[1024];
408 if (format_ >= fmt + sizeof(fmtBuf) / sizeof(Char))
413 memcpy(fmtBuf, fmt, (format_ - fmt) * sizeof(Char));
414 fmtBuf[format_ - fmt] = 0;
426 (resultBuf, sizeof(resultBuf) / sizeof(Char), fmtBuf, n);
433 Write(resultBuf, resultBuf + strlen(resultBuf));
434 Advance(); // output stuff to the next format directive
437 void Fill(const Char c, size_t n)
445 Char *RenderWithoutSign(LOKI_SAFEFORMAT_UNSIGNED_LONG n, char *bufLast,
446 unsigned int base, bool uppercase)
448 const Char hex1st = uppercase ? 'A' : 'a';
451 const LOKI_SAFEFORMAT_UNSIGNED_LONG next = n / base;
452 Char c = static_cast<Char>(n - next * base);
453 c = static_cast<Char>(c + (c <= 9 ? '0' : static_cast<Char>(hex1st - 10)));
462 char *RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char *bufLast, unsigned int base,
467 return RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n < 0 ? -n : n),
468 bufLast, base, uppercase);
470 // annoying corner case
471 char *save = bufLast;
473 bufLast = RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n),
474 bufLast, base, uppercase);
488 const Char *begin = format_;
493 if (format_[1] != '%') // It's a format specifier
495 Write(begin, format_);
500 Write(begin, ++format_);
506 Write(begin, format_);
540 void ParseDecimalSizeT(size_t &dest)
542 if (!std::isdigit(*format_, std::locale())) return;
546 // TODO: inefficient - rewrite
551 while (std::isdigit(*format_, std::locale()));
557 ParseDecimalSizeT(width_);
562 assert(*format_ == '.');
564 ParseDecimalSizeT(prec_);
578 // more (C99 and platform-specific modifiers) to come
586 if (*format_ == '.') ReadPrecision();
600 bool LeftJustify() const
602 return (flags_ & leftJustify) != 0;
604 bool ShowSignAlways() const
606 return (flags_ & showSignAlways) != 0;
608 void SetWidth(size_t w)
612 void SetLeftJustify()
614 flags_ |= leftJustify;
616 void SetShowSignAlways()
618 flags_ |= showSignAlways;
622 return (flags_ & blank) != 0;
624 bool AlternateForm() const
626 return (flags_ & alternateForm) != 0;
628 bool FillZeros() const
630 return (flags_ & fillZeros) != 0;
632 bool ForceShort() const
634 return (flags_ & forceShort) != 0;
637 void SetPrec(size_t p)
645 void SetAlternateForm()
647 flags_ |= alternateForm;
653 void ResetFillZeros()
655 flags_ &= ~fillZeros;
659 flags_ |= forceShort;
664 assert(result_ != EOF);
676 LOKI_SAFEFORMAT_SIGNED_LONG result_;
680 PrintfState<std::FILE *, char> Printf(const char *format);
683 PrintfState<std::FILE *, char> Printf(const std::string &format);
686 PrintfState<std::FILE *, char> FPrintf(std::FILE *f, const char *format);
689 PrintfState<std::FILE *, char> FPrintf(std::FILE *f, const std::string &format);
692 PrintfState<std::ostream &, char> FPrintf(std::ostream &f, const char *format);
695 PrintfState<std::ostream &, char> FPrintf(std::ostream &f, const std::string &format);
698 PrintfState<std::string &, char> SPrintf(std::string &s, const char *format);
701 PrintfState<std::string &, char> SPrintf(std::string &s, const std::string &format);
703 template <class T, class Char>
704 PrintfState<T &, Char> XPrintf(T &device, const Char *format)
706 return PrintfState<T &, Char>(device, format);
710 PrintfState<T &, char> XPrintf(T &device, const std::string &format)
712 return PrintfState<T &, char>(device, format.c_str());
715 template <class Char, std::size_t N>
716 PrintfState<std::pair<Char *, std::size_t>, Char>
717 BufPrintf(Char (&buf)[N], const Char *format)
719 std::pair<Char *, std::size_t> temp(buf, N);
720 return PrintfState<std::pair<Char *, std::size_t>, Char>(temp, format);
726 #endif // end file guardian