# The Boost Format library

The `<boost/format.hpp>` format class provides printf-like formatting, in a type-safe manner which allows output of user-defined types.
(It does not depend on other boost libraries)

- Synopsis
- How it works
- Examples
- Syntax
  - printf format-specification syntax
  - Incompatibilities with printf
- Manipulators and the internal stream state
- User-defined types
- Exceptions
- Alternatives

## Synopsis

A format object is constructed from a format-string, and is then given arguments through repeated calls to operator%.
Each of those arguments are then converted to strings, who are in turn combined into one string, according to the format-string.

>     cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50;
>          // prints "writing toto,  x=40.230 : 50-th try"

## How it works

1. When you call format(s), where s is the format-string, it constructs an object, which parses the format string and look for all directives in it and prepares internal structures for the next step.
2. Then, either immediately, as in

   >     cout << format("%2% %1%") % 36 % 77 )

   or later on, as in

   >     format fmter("%2% %1%");
   >     fmter % 36; fmter % 77;

   you feed variables into the formatter.
   those variables are dumped into an internal stream, which state is set according to the given formatting options in the format-string -if there are any-, and the format object stores the string results for the last step.
3. Once all arguments have been fed you can dump the format object to a stream, or get its string value by using the str() member function, or the free function str(const format& ) in namespace boost::io. The result string stays accessible in the format object until another argument is passed, at which time it is reinitialised.

   >     // fmter was previously created and fed arguments, it can print the result :
   >     cout << fmter ;

   >     // You can take the string result :
   >     string s  = fmter.str();

   >     // possibly several times :
   >     s = fmter.str( );

   >     // You can also do all steps at once :
   >     cout << boost::format("%2% %1%") % 36 % 77;
   >     string s2 = boost::io::str( format("%2% %1%") % 36 % 77 );

4. Optionnally, after step 3, you can re-use a format object and restart at step2 : fmter % 18 % 39;
   to format new variables with the same format-string, saving the expensive processing involved at step 1.

All in all, the format class translates a format-string (with eventually printf-like directives) into operations on an internal stream, and finally returns the result of the formatting, as a string, or directly into an output stream.

## Examples

>     using namespace std;
>     using boost::format;
>     using boost::io::group;
>     using boost::io::str;

- Simple output, with reordering :

  >     cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.

  It prints : "11 22 333 22 11 \n"
- More precise formatting, with Posix-printf positional directives :

  >     cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;     // Posix-Printf style

  It prints : "(x,y) = ( -23, +35) \n"
- classical printf directive, no reordering :

  >     cout << format("writing %s,  x=%s : %d-th step \n") % "toto" % 40.23 % 50;

  It prints : "writing toto, x=40.23 : 50-th step \n"
- Several ways to express the same thing :

  >     cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35;
  >     cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35;

  >     cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;
  >     cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35;

  all those print : "(x,y) = ( -23, +35) \n"
- Using manipulators to modify the format-string :

  >     format fmter("_%1$+5d_ %1$d \n");

  >     format fmter2("_%1%_ %1% \n");
  >     fmter2.modify_item(1, group(showpos, setw(5)) );

  >     cout << fmter % 101 ;
  >     cout << fmter2 % 101 ;

  Both print the same : "_ +101_ 101 \n"
- Using manipulators with arguments :

  >     cout << format("_%1%_ %1% \n") % group(showpos, setw(5), 101);

  The manipulators are applied at each occurence of %1%, and thus it prints : "_ +101_ +101 \n"
- New formatting feature : 'absolute tabulations', useful in loops, to insure a field is printed at the same position from one line to the next, even if the widthes of the previous arguments can vary a lot.

  >     for(unsigned int i=0; i < names.size(); ++i)
  >         cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];

  For some vector names, surnames, and tel (see sample_new_features.cpp) it prints :

  >     Marc-François Michel, Durand,           +33 (0) 123 456 789
  >     Jean, de Lattre de Tassigny,            +33 (0) 987 654 321

## Sample Files

The program sample_formats.cpp demonstrates simple uses of format.

sample_new_features.cpp illustrates the few formatting features that were added to printf's syntax such as simple positional directives, centered alignment, and 'tabulations'.

sample_advanced.cpp demonstrates uses of advanced features, like reusing, and modifying, format objects, etc..

And sample_userType.cpp shows the behaviour of the format library on user-defined types.

## Syntax

boost::format( format-string ) % arg1 % arg2 % ... % argN

The format-string contains text in which special directives will be replaced by strings resulting from the formatting of the given arguments.
The legacy syntax in the C and C++ worlds is the one used by printf, and thus format can use directly printf format-strings, and produce the same result (in almost all cases. see Incompatibilities with printf for details)
This core syntax was extended, to allow new features, but also to adapt to the C++ streams context. Thus, format accepts several forms of directives in format-strings :

- Legacy printf format strings : %spec where spec is a printf format specification
  spec passes formatting options, like width, alignment, numerical base used for formatting numbers, as well as other specific flags. But the classical type-specification flag of printf has a weaker meaning in format. It merely sets the appropriate flags on the internal stream, and/or formatting parameters, but does not require the corresponding argument to be of a specific type.
  e.g. : the specification 2$x, meaning "print argument number 2, which is an integral number, in hexa" for printf, merely means "print argument 2 with stream basefield flags set to hex" for format.
- %|spec| where spec is a printf format specification.
  The brackets are introduced, to improve the readability of the format-string, but primarily, to make the type-conversion character optional in spec. This information is not necessary with C++ variables, but with direct printf syntax, it is necessary to always give a type-conversion character, merely because this character is crucial to determine the end of a format-specification.
  e.g. : "%|-5|" will format the next variable with width set to 5, and left-alignment just like the following printf directives : "%-5g", "%-5f", "%-5s" ..
- %N%
  This simple positional notation requests the formatting of the N-th argument - wihout any formatting option.
  (It's merely a shortcut to Printf's positional directives (like "%N$s"), but a major benefit is that it's much more readable, and does not use a "type-conversion" character)

On top of the standard printf format specifications, new features were implemented, like centered alignment. See new format specification for details.

### printf format specifications

The printf format specifications supported by Boost.format follows the Unix98 Open-group printf precise syntax, rather than the standard C printf, which does not support positional arguments. (Common flags have the same meaning in both, so it should not be a headache for anybody)
Note that it is an error to use positional format specifications (e.g. %3$+d) mixed with non-positional ones (e.g. %+d) in the same format string.
In the Open-group specification, referring to the same argument several times (e.g. "%1$d %1$d") has undefined behaviour. Boost.format's behaviour in such cases is to allow each argument to be reffered to any number of times. The only constraint is that it expects exactly P arguments, P being the maximum argument number used in the format string. (e.g., for "%1$d %10$d", P == 10 ).
Supplying more, or less, than P arguments raises an exception. (unless it was set otherwise, see exceptions)

A specification spec has the form : [ N$ ] [ flags ] [ width ] [ . precision ] type-char
Fields insided square brackets are optional. Each of those fields are explained one by one in the following list :

- N $ (optional field) specifies that the format specification applies to the N-th argument. (it is called a positional format specification)
  If this is not present, arguments are taken one by one. (and it is then an error to later supply an argument number)
- flags is a sequences of any of those :

  > Flag | Meaning | effect on internal stream
  > '-' | left alignment | N/A (applied later on the string)
  > '=' | centered alignment | N/A (applied later on the string) Inexistent in printf (added feature)
  > '+' | show sign even for positive numbers | sets showpos
  > '#' | show numerical base, and decimal point | sets showbase and showpoint
  > '0' | pad with 0's (inserted after sign or base indicator) | if not left-aligned, calls setfill('0') and sets internal Extra actions are taken after stream conversion to handle user-defined output.
  > ' ' | if the string does not begin with + or -, insert a space before the converted string | N/A (applied later on the string) Different to printf's behaviour : it is not affected by internal alignment

- width specifies a minimal width for the string resulting form the conversion. If necessary, the string will be padded with alignment and fill characters either set on the stream via manipulators, or specified by the format-string (e.g. flags '0', '-', ..)
  Note that width is not just set on the conversion stream. To support output of user-defined types (that might call operator<< many times on several members), the width is handled after stream conversion of the whole argument object, in the format class code.
- precision (preceded by a point), sets the stream's precision
  - When outputting a floatting type number, it sets the maximum number of digits
    - after decimal point when in fixed or scientific mode
    - in total when in default mode ('general mode', like %g)
  - When used with type-char s or S it takes another meaning : the conversion string is truncated to the precision first chars. (Note that the eventual padding to width is done after truncation.)
- type-char. it does not impose the concerned argument to be of a restricted set of types, but merely sets the flags that are associated with this type specification.

  > Type-Char | Meaning | effect on stream
  > p or x | hexadecimal output | sets hex
  > o | octal output | sets oct
  > e | scientific float format | sets floatfield bits to scientific
  > f | fixed float format | sets floatfield bits to fixed
  > g | general -default- float format | unset all floatfield bits
  > X, E or G | same effect as their lowercase counterparts, but using uppercase letters for number outputs. (exponents, hex digits, ..) | same effects as 'x', 'e', or 'g', plus uppercase
  > d, i or u | decimal type output | sets basefield bits to dec
  > s or S | string output | precision specification is unset, and its value goes to an internal field for later 'truncation'. (see precision explanation above)
  > c or C | 1-character output | only the first character of the conversion string is used.
  > % | print the character % | N/A

  > Note that the 'n' type specification is ignored (and so is the corresponding argument), because it does not fit in this context.
  > Also, printf 'l', 'L', or 'h' modifiers (to indicate wide, long or short types) are supported (and simply have no effect on the internal stream).

### new format-specifications

- as stated in the flags table, a centered alignment flag ' = ' was added.
- %{n t} , where n is a positive number, inserts an absolute tabulation. It means that format will, if needed, fill the string with characters, until the length of the string created so far reaches n characters. (see examples )
- %{n T X} inserts a tabulation in the same way, but using X as fill character instead of the current 'fill' char of the stream (which is space for a stream in default state)

## Differences of behaviour vs printf

Suppose you have variables x1, x2 (built_in types, supported by C's printf),
and a format string s intended for use with a printf function this way :

>     printf(s, x1, x2);

In almost all cases, the result will be the same as with this command :

>     cout << format(s) % x1 % x2;

But because some printf format specifications don't translate well into stream formatting options, there are a few notable imperfections in the way Boost.format emulates printf.
In any case, the format class should quietly ignore the unsupported options, so that printf format-strings are always accepted by format and produce almost the same output as printf.
Here is the full list of such differences :

- '0' and ' ' options : printf ignores these options for non numeric conversions, but format applies them to all types of variables. (so it is possible to use those options on user-defined types, e.g. a Rational class, etc..)
- precision for integral types arguments has a special meaning for printf :
  printf( "(%5.3d)" , 7 ) ; prints « ( 007) »
  While format, like streams, ignores the precision parameter for integral types conversions.
- the ' printf option (format with thousands grouping characters)) has no effect in format.
- Width or precision set to asterisk (*) are used by printf to read this field from an argument. e.g. printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);
  This class does not support this mechanism for now. so such precision or width fields are quietly ignored by the parsing.

Also, note that the special 'n' type-specification (used to tell printf to save in a variable the number of characters output by the formatting) has no effect in format.
Thus format strings containing this type-specification should produce the same converted string by printf or format. It will not cause differences in the formatted strings between printf and format.
To get the number of characters in the formatted string using Boost.Format, do as follows :

>     format formatter("%+5d");
>     cout << formatter % x;
>     unsigned int n = formatter.str().size();

## User-defined types output

All flags which are translated into modification to the stream state act recursively within user-defined types. ( the flags remain active, and so does the desired format option, for each of the '<<' operations that might be called by the user-defined class)
e.g., with a reasonable class Rational, we would have something like :

>     Rational ratio(16,9);
>     cerr << format("%#x \n")  % ratio;  // -> "0x10/0x9 \n"

It's a different story for other formatting options. For example, setting width applies to the final output produced by the object, not to each of its internal outputs, and that's fortunate :

>     cerr << format("%-8d")  % ratio;  // -> "16/9    "      and not    "16      /9       "
>     cerr << format("%=8d")  % ratio;  // -> "  16/9  "      and not    "   16   /    9   "

But so does the 0 and ' ' options (contrarily to '+' which is directly translated to the stream state by showpos. But no such flags exist for the zero and space printf options)
and that is less natural :

>     cerr << format("%+08d \n")  % ratio;  // -> "+00016/9"
>     cerr << format("% 08d \n")  % ratio;  // -> "000 16/9"

### Manipulators, and internal stream state

The internal stream state of format is saved before and restored after output of an argument; therefore, the modifiers are not sticky and affect only the argument they are applied to.
The default state for streams, as stated by the standard, is : precision 6, width 0, right alignment, and decimal flag set.

The state of the internal format stream can be changed by manipulators passed along with the argument; via the group function, like that :

>     cout << format("%1% %2% %1%\n") % group(hex, showbase, 40) % 50; // prints "0x28 50 0x28\n"

When passing N items inside a 'group' Boost.format needs to process manipulators diferently from regular argument, and thus using group is subject to the following constraints :

1. the object to be printed must be passed as the last item in the group
2. the first N-1 items are treated as manipulators, and if they do produce output, it is discarded

Such manipulators are passed to the streams right before the following argument, at every occurence. Note that formatting options specified within the format string are overridden by stream state modifiers passed this way. For instance in the following code, the hex manipulator has priority over the d type-specification in the format-string which would set decimal output :

>     cout << format("%1$d %2% %1%\n") % group(hex, showbase, 40) % 50;
>     // prints "0x28 50 0x28\n"

## Alternatives

- printf is the classical alternative, that is not type safe and not extendable to user-defined types.
- ofrstream.cc by Karl Nelson's design was a big source of inspiration to this format class.
- format.hpp By Rüdiger Loo. It was a previous proposition for a boost::format class. It was an other source for this one, complementary to Karl's, in simplicity of design, and minimalistic "%1 %2" syntax - which this class borrowed.
- James Kanze's library has a format class (in srcode/Extended/format ) which looks very well polished. Its design has in common with this class the use of internal stream for the actual conversions, as well as using operators to pass arguments. (but his class, as ofrstream, uses operator<< rather than operator% )
- Karl Nelson's library was intented as demonstration of alternative solutions in discussions on Boost's list for the design of Boost.format.

## Exceptions

Boost.format enforces a number of rules on the usage of format objects. The format-string must obeys the syntax described above, the user must supply exactly the right number of arguments before outputting to the final destination, and if using modify_item or bind_arg, items and arguments index must not be out of range.
When format detects that one of these rules is not satisfied, it raises a corresponding exception, so that the mistakes don't go unnoticed and unhandled.
But the user can change this behaviour to fit his needs, and select which types of errors may raise exceptions using the following functions :

>     unsigned char exceptions(unsigned char newexcept); // query and set
>     unsigned char exceptions() const;                  // just query

The user can compute the argument newexcept by combining the following atoms using binary arithmetic :

- boost::io::bad_format_string_bit selects errors due to ill-formed format-strings.
- boost::io::too_few_args_bit selects errors due to asking for the srting result before all arguments are passed.
- boost::io::too_many_args_bit selects errors due to passing too many arguments.
- boost::io::out_of_range_bit select errors due to out of range index supplied by the user when calling modify_item or other functions taking an item index (or an argument index)
- boost::io::all_error_bits selects all errors
- boost::io::no_error_bits selects no error.

For instance, if you don't want Boost.format to detect bad number of arguments, you can define a specific wrapper function for building format objects with the right exceptions settings :

>     boost::format  my_fmt(const std::string & f_string) {
>         using namespace boost::io;
>         format fmter(f_string);
>         fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit )  );
>         return fmter;
>     }

It is then allowed to give more arguments than needed (they are simply ignored) :

>     cout << my_fmt(" %1% %2% \n") % 1 % 2 % 3 % 4 % 5;

And if we ask for the result before all arguments are supplied, the corresponding part of the result is simply empty

>     cout << my_fmt(" _%2%_ _%1%_ \n") % 1 ;
>     // prints      " __ _1_ \n"

## Extract

>     namespace boost {

>     template<class charT, class Traits=std::char_traits<charT> >
>     class basic_format
>     {
>     public:
>       typedef std::basic_string<charT, Traits> string_t,
>       basic_format(const charT* str);
>       basic_format(const charT* str, const std::locale & loc);
>       basic_format(const string_t& s);
>       basic_format(const string_t& s, const std::locale & loc);

>       string_t str() const;

>       // pass arguments through those operators :
>       template<class T>  basic_format&   operator%(T& x);
>       template<class T>  basic_format&   operator%(const T& x);

>       // dump buffers to ostream :
>       friend std::basic_ostream<charT, Traits>&
>       operator<< <> ( std::basic_ostream<charT, Traits>& , basic_format& );

>     // ............  this is just an extract .......
>     }; // basic_format

>     typedef basic_format<char >          format;
>     typedef basic_format<wchar_t >      wformat;

>     namespace io {
>     // free function for ease of use :
>     template<class charT, class Traits>
>     std::basic_string<charT,Traits>  str(const basic_format<charT,Traits>& f) {
>           return f.str();
>     }
>     } //namespace io

>     } // namespace boost

## Rationale

This class's goal is to bring a better, C++, type-safe and type-extendable printf equivalent to be used with streams.

Precisely, format was designed to provide the following features :

- support positional arguments (required for internationalisation)
- accept an unlimited number of arguments.
- make formatting commands visually natural.
- support the use of manipulators to modify the display of an argument. in addition to the format-string syntax.
- accept any types of variables, by relying on streams for the actual conversion to string. This specifically concerns user-defined types, for which the formatting options effects should be intuitively natural.
- provide printf-compatibility, as much as it makes sense in a type-safe and type-extendable context.

In the process of the design, many issues were faced, and some choices were made, that might not be intuitively right. But in each case they were taken for some reasons.

## Credits

The author of Boost format is Samuel Krempp. He used ideas from both Rüdiger Loos' and Karl Nelson's formatting classes.

February 19, 2002

© Copyright Samuel Krempp 2002. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.