portability/dprintf.hpp
#ifndef STLPLUS_DPRINTF
#define STLPLUS_DPRINTF
////////////////////////////////////////////////////////////////////////////////
//
// Author: Andy Rushton
// Copyright: (c) Southampton University 1999-2004
// (c) Andy Rushton 2004 onwards
// License: BSD License, see ../docs/license.html
//
// Provides an sprintf-like function acting on STL strings. The 'd' in dprintf
// stands for "dynamic" in that the string is a dynamic string whereas a char*
// buffer would be static (in size that is, not static in C terms).
//
// The obvious solution to the problem of in-memory formatted output is to use
// sprintf(), but this is a potentially dangerous operation since it will quite
// happily charge off the end of the string it is printing to and thereby
// corrupt memory. This kind of buffer-overflow vulnerability is the source of
// most security failures exploited by virus-writers. It means that sprintf
// should *never* be used and should be made obsolete.
//
// In any case, using arbitrary-sized fixed-length buffers is not part of any
// quality-orientated design philosophy.
//
// Most operating systems now have a safe version of sprintf, but this is
// non-standard. The functions in this file are platform-independent interfaces
// to the underlying safe implementation.
//
// I would like to make this set of functions obsolete too, since I believe the
// C runtime should be deprecated in favour of C++ runtime which uses dynamic
// strings and can handle exceptions. However, there is as yet no C++
// equivalent functionality to some of the string-handling available through
// the printf-like functions, so it has to stay for now.
//
// int dprintf (std::string& buffer, const char* format, ...);
//
// Formats the message by appending to the std::string buffer according to
// the formatting codes in the format string. The return int is the number
// of characters generated by this call, i.e. the increase in the length of
// the std::string.
//
// int vdprintf (std::string& buffer, const char* format, va_list args);
//
// As above, but using a pre-initialised va_args argument list. Useful for
// nesting dprintf calls within variable argument functions.
//
// std::string dformat (const char* format, ...);
//
// Similar to dprintf() above, except the result is formatted into a new
// std::string which is returned by the function. Very useful for inline
// calls within an iostream expression.
//
// e.g. cout << "Total: " << dformat("%6i",t) << endl;
//
// std::string vdformat (const char* format, va_list);
//
// As above, but using a pre-initialised va_args argument list. Useful for nesting
// dformat calls within variable argument functions.
//
// The format string supports the following format codes as in the C runtime library:
//
// % [ flags ] [ field ] [ . precision ] [ modifier ] [ conversion ]
//
// flags:
// - - left justified
// + - print sign for +ve numbers
// ' ' - leading space where + sign would be
// 0 - leading zeros to width of field
// # - alternate format
//
// field:
// a numeric argument specifying the field width - default = 0
// * means take the next va_arg as the field width - if negative then left justify
//
// precision:
// a numeric argument the meaning of which depends on the conversion -
// - %s - max characters from a string - default = strlen()
// - %e, %f - decimal places to be displayed - default = 6
// - %g - significant digits to be displayed - default = 6
// - all integer conversions - minimum digits to display - default = 0
// * means take the next va_arg as the field width - if negative then left justify
//
// modifier:
// h - short or unsigned short
// l - long or unsigned long
// L - long double
//
// conversions:
// d, i - short/int/long as decimal
// u - short/int/long as unsigned decimal
// o - short/int/long as unsigned octal - # adds leading 0
// x, X - short/int/long as unsigned hexadecimal - # adds leading 0x
// c - char
// s - char*
// f - double/long double as fixed point
// e, E - double/long double as floating point
// g, G - double/long double as fixed point/floating point depending on value
// p - void* as unsigned hexadecimal
// % - literal %
// n - int* as recipient of length of formatted string so far
//
////////////////////////////////////////////////////////////////////////////////
#include "portability_fixes.hpp"
#include <string>
#include <stdexcept>
#include <stdarg.h>
namespace stlplus
{
// format by appending to a string and return the increase in length
// if there is an error, return a negative number and leave the string unchanged
int dprintf (std::string& formatted, const char* format, ...);
int vdprintf (std::string& formatted, const char* format, va_list args);
// format into a new string and return the result
// if there is an error, throw an exception
// exceptions: std::invalid_argument
std::string dformat (const char* format, ...) ;
// exceptions: std::invalid_argument
std::string vdformat (const char* format, va_list) ;
}
#endif