portability/dprintf.hpp

    1: #ifndef STLPLUS_DPRINTF
    2: #define STLPLUS_DPRINTF
    3: ////////////////////////////////////////////////////////////////////////////////
    4: 
    5: //   Author:    Andy Rushton
    6: //   Copyright: (c) Andy Rushton, 2007
    7: //   License:   BSD License, see ../docs/license.html
    8: 
    9: //   Provides an sprintf-like function acting on STL strings. The 'd' in dprintf
   10: //   stands for "dynamic" in that the string is a dynamic string whereas a char*
   11: //   buffer would be static (in size that is, not static in C terms).
   12: 
   13: //   The obvious solution to the problem of in-memory formatted output is to use
   14: //   sprintf(), but this is a potentially dangerous operation since it will quite
   15: //   happily charge off the end of the string it is printing to and thereby
   16: //   corrupt memory. This kind of buffer-overflow vulnerability is the source of
   17: //   most security failures exploited by virus-writers. It means that sprintf
   18: //   should *never* be used and should be made obsolete.
   19: 
   20: //   In any case, using arbitrary-sized fixed-length buffers is not part of any
   21: //   quality-orientated design philosophy.
   22: 
   23: //   Most operating systems now have a safe version of sprintf, but this is
   24: //   non-standard. The functions in this file are platform-independent interfaces
   25: //   to the underlying safe implementation.
   26: 
   27: //   I would like to make this set of functions obsolete too, since I believe the
   28: //   C runtime should be deprecated in favour of C++ runtime which uses dynamic
   29: //   strings and can handle exceptions. However, there is as yet no C++
   30: //   equivalent functionality to some of the string-handling available through
   31: //   the printf-like functions, so it has to stay for now.
   32: 
   33: //     int dprintf (std::string& buffer, const char* format, ...);
   34: 
   35: //       Formats the message by appending to the std::string buffer according to
   36: //       the formatting codes in the format string. The return int is the number
   37: //       of characters generated by this call, i.e. the increase in the length of
   38: //       the std::string.
   39: 
   40: //     int vdprintf (std::string& buffer, const char* format, va_list args);
   41: 
   42: //       As above, but using a pre-initialised va_args argument list. Useful for
   43: //       nesting dprintf calls within variable argument functions.
   44: 
   45: //     std::string dformat (const char* format, ...);
   46: 
   47: //       Similar to dprintf() above, except the result is formatted into a new
   48: //       std::string which is returned by the function. Very useful for inline
   49: //       calls within an iostream expression.
   50: 
   51: //       e.g.    cout << "Total: " << dformat("%6i",t) << endl;
   52: 
   53: //     std::string vdformat (const char* format, va_list);
   54: 
   55: //       As above, but using a pre-initialised va_args argument list. Useful for nesting
   56: //       dformat calls within variable argument functions.
   57: 
   58: //   The format string supports the following format codes as in the C runtime library:
   59: 
   60: //     % [ flags ] [ field ] [ . precision ] [ modifier ] [ conversion ]
   61: 
   62: //     flags:
   63: //       -    - left justified
   64: //       +    - print sign for +ve numbers
   65: //       ' '  - leading space where + sign would be
   66: //       0    - leading zeros to width of field
   67: //       #    - alternate format
   68: 
   69: //     field:
   70: //       a numeric argument specifying the field width - default = 0
   71: //       * means take the next va_arg as the field width - if negative then left justify
   72: 
   73: //     precision:
   74: //       a numeric argument the meaning of which depends on the conversion -
   75: //       - %s - max characters from a string - default = strlen()
   76: //       - %e, %f - decimal places to be displayed - default = 6
   77: //       - %g - significant digits to be displayed - default = 6
   78: //       - all integer conversions - minimum digits to display - default = 0
   79: //       * means take the next va_arg as the field width - if negative then left justify
   80: 
   81: //     modifier:
   82: //       h    - short or unsigned short
   83: //       l    - long or unsigned long
   84: //       L    - long double
   85: 
   86: //     conversions:
   87: //       d, i - short/int/long as decimal
   88: //       u    - short/int/long as unsigned decimal
   89: //       o    - short/int/long as unsigned octal - # adds leading 0
   90: //       x, X - short/int/long as unsigned hexadecimal - # adds leading 0x
   91: //       c    - char
   92: //       s    - char*
   93: //       f    - double/long double as fixed point
   94: //       e, E - double/long double as floating point
   95: //       g, G - double/long double as fixed point/floating point depending on value
   96: //       p    - void* as unsigned hexadecimal
   97: //       %    - literal %
   98: //       n    - int* as recipient of length of formatted string so far
   99: 
  100: ////////////////////////////////////////////////////////////////////////////////
  101: #include "portability_fixes.hpp"
  102: #include <string>
  103: #include <stdexcept>
  104: #include <stdarg.h>
  105: 
  106: namespace stlplus
  107: {
  108: 
  109:   // format by appending to a string and return the increase in length
  110:   // if there is an error, return a negative number and leave the string unchanged
  111:   int dprintf (std::string& formatted, const char* format, ...);
  112:   int vdprintf (std::string& formatted, const char* format, va_list args);
  113: 
  114:   // format into a new string and return the result
  115:   // if there is an error, throw an exception
  116:   std::string dformat (const char* format, ...) throw(std::invalid_argument);
  117:   std::string vdformat (const char* format, va_list) throw(std::invalid_argument);
  118: 
  119: } // end namespace stlplus
  120: 
  121: #endif