We have seen that the structure returned by localeconv
as well as
the values given to nl_langinfo
allow to retrieve the various
pieces of locale specific information to format numbers and monetary
amounts. But we have also seen that the rules underlying this
information are quite complex.
Therefore the X/Open standards introduce a function which uses this information from the locale and so makes it is for the user to format numbers according to these rules.
strfmon
function is similar to the strftime
function
in that it takes a description of a buffer (with size), a format string
and values to write into a buffer a textual representation of the values
according to the format string. As for strftime
the function
also returns the number of bytes written into the buffer.
There are two difference: strfmon
can take more than one argument
and of course the format specification is different. The format string
consists as for strftime
of normal text which is simply printed
and format specifiers, which here are also introduced using `%'.
Following the `%' the function allows similar to printf
a
sequence of flags and other specifications before the format character:
LC_MONETARY
category of the locale selected at program runtime.
The next part of a specification is an, again optional, specification of the field width. The width is given by digits following the flags. If no width is specified it is assumed to be @math{0}. The width value is used after it is determined how much space the printed result needs. If it does not require fewer characters than specified by the width value nothing happens. Otherwise the output is extended to use as many characters as the width says by filling with spaces. At which side depends on whether the `-' flag was given or not. If it was given, the spaces are added at the right, making the output right-justified and vice versa.
So far the format looks familiar as it is similar to printf
or
strftime
formats. But the next two fields introduce something
new. The first one, if available, is introduced by a `#' character
which is followed by a decimal digit string. The value of the digit
string specifies the width the formatted digits left to the radix
character. This does not include the grouping character needed
if the `^' flag is not given. If the space needed to print the
number does not fill the whole width the field is padded at the left
side with the fill character which can be selected using the `='
flag and which by default is a space. For example, if the field width
is selected as 6 and the number is @math{123}, the fill character is
`*' the result will be `***123'.
The next field is introduced by a `.' (period) and consists of
another decimal digit string. Its value describes the number of
characters printed after the radix character. The default is
selected from the current locale (frac_digits
,
int_frac_digits
, see see section Generic Numeric Formatting Parameters). If the exact
representation needs more digits than those specified by the field width
the displayed value is rounded. In case the number of fractional digits
is selected to be zero, no radix character is printed.
As a GNU extension the strfmon
implementation in the GNU libc
allows as the next field an optional `L' as a format modifier. If
this modifier is given the argument is expected to be a long
double
instead of a double
value.
Finally as the last component of the format there must come a format specifying. There are three specifiers defined:
As it is done for printf
, the function reads the format string
from left to right and uses the values passed to the function following
the format string. The values are expected to be either of type
double
or long double
, depending on the presence of the
modifier `L'. The result is stored in the buffer pointed to by
s. At most maxsize characters are stored.
The return value of the function is the number of characters stored in
s, including the terminating NUL byte. If the number of
characters stored would exceed maxsize the function returns
@math{-1} and the content of the buffer s is unspecified. In this
case errno
is set to E2BIG
.
A few examples should make it clear how to use this function. It is
assumed that all the following pieces of code are executed in a program
which uses the locale valid for the USA (en_US
). The simplest
form of the format is this:
strfmon (buf, 100, "@%n@%n@%n@", 123.45, -567.89, 12345.678);
The output produced is
"@$123.45@-$567.89@$12,345.68@"
We can notice several things here. First, the width for all formats is
different. We have not specified a width in the format string and so
this is no wonder. Second, the third number is printed using thousands
separators. The thousands separator for the en_US
locale is a
comma. Beside this the number is rounded. The @math{.678} are rounded
to @math{.68} since the format does not specify a precision and the
default value in the locale is @math{2}. A last thing is that the
national currency symbol is printed since `%n' was used, not
`i'. The next example shows how we can align the output.
strfmon (buf, 100, "@%=*11n@%=*11n@%=*11n@", 123.45, -567.89, 12345.678);
The output this time is:
"@ $123.45@ -$567.89@ $12,345.68@"
Two things stand out. First, all fields have the same width (eleven characters) since this is the width given in the format and since no number required more characters to be printed. The second important point is that the fill character is not used. This is correct since the white space was not used to fill the space specified by the right precision, but instead it is used to fill to the given width. The difference becomes obvious if we now add a right width specification.
strfmon (buf, 100, "@%=*11#5n@%=*11#5n@%=*11#5n@", 123.45, -567.89, 12345.678);
The output is
"@ $***123.45@-$***567.89@ $12,456.68@"
Here we can see that all the currency symbols are now aligned and the space between the currency sign and the number is filled with the selected fill character. Please note that although the right precision is selected to be @math{5} and @math{123.45} has three characters right of the radix character, the space is filled with three asterisks. This is correct since as explained above, the right precision does not count the characters used for the thousands separators in. One last example should explain the remaining functionality.
strfmon (buf, 100, "@%=0(16#5.3i@%=0(16#5.3i@%=0(16#5.3i@", 123.45, -567.89, 12345.678);
This rather complex format string produces the following output:
"@ USD 000123,450 @(USD 000567.890)@ USD 12,345.678 @"
The most noticeable change is the use of the alternative style to
represent negative numbers. In financial circles it is often done using
parentheses and this is what the `(' flag selected. The fill character
is now `0'. Please note that this `0' character is not
regarded as a numeric zero and therefore the first and second number are
not printed using a thousands separator. Since we use in the format the
specifier `i' instead of `n' now the international form of the
currency symbol is used. This is a four letter string, in this case
"USD "
. The last point is that since the left precision is
selected to be three the first and second number are printed with an
extra zero at the end and the third number is printed unrounded.
Go to the first, previous, next, last section, table of contents.