portability/dprintf.hpp
Printf-like Functions for Dynamic Strings

Introduction

A "better" version of sprintf() and form() which provide printf-style formatting to the string class. In fact, they simply overcome some of the limitations of these functions, in particular they avoid the use of fixed char* buffers which can cause memory corruption or even a crash on overflow.

It is called dprintf because the obvious name (sprintf) was already taken. The 'd' stands for dynamic in that it writes to a dynamic string and therefore has no buffer overflow problems.

Interface

int dprintf (string&, const char* format, ...);

This is a bit like sprintf() but acting on strings, it formats the message by appending to the string (using the += operator) 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 string.

Note: you should never use sprintf in any program, since it writes to a string without any check on the string length. It can therefore overflow and crash the program. This kind of function just isn't worth using.

string dformat (const char* format, ...);

Similar to dprintf() above, except the result is formatted into a new string which is returned by the function. Very useful for inline calls within a TextIO expression. This is a replacement for the old form() function which relies on a fixed-size static char* which is not only prone to overflow but is also not thread-safe. An example of its use with TextIO:

std::cout << "Total: " << dformat("%6i",t) << std::endl;

This produces an integer formatted into a 6-character wide field. See the next section for the full set of formats provided.

Formats

The result supports the following "C" format codes:

%[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

For example:

dprintf(d, "%*i", width, value);

This formats the integer in variable value in a field width defined by the variable width.

precision:

A numeric argument the meaning of which depends on the conversion

%s - maximum number of 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 - # flag adds leading 0
x, X - short/int/long as unsigned hexadecimal - # flag adds leading 0x
c    - char
s    - char*
C    - wchar_t
S    - wchar_t*
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

Meta-Characters

The result also supports the following "C" meta-characters:

\b   - backspace
\f   - formfeed
\n   - newline
\r   - carriage return
\t   - tab
\v   - vertical tab
\\   - backslash
\?   - question mark
\'   - single quote
\"   - double quote

The \000 and \x00 representations of octal and hexadecimal codes are not yet supported.