Text formatting details
For text formatting, CIF features the fmt
standard library function. This page describes all the details of using that function. For more introductory information and examples of the use of the fmt
function for print output, see the Text formatting tutorial.
Format patterns
The fmt
function requires at least one argument, the format pattern. The remaining arguments of the function are the values that can be inserted into the format pattern, to allow variable output. For instance, consider:
fmt("%s %s", x, y)
Here, "%s %s"
is the format pattern, x
is the first value, and y
is the second value.
The first argument, the format pattern, must be a string literal. That is, it must be text between double quotes ("
).
The real usefulness of format patterns comes from the inclusion of the values into the format pattern. The values can be included by inserting format specifiers (e.g. %s
) into the format pattern. Multiple values may be used by including multiple format specifiers. The first format specifier includes the first value, the second format specifier includes the second value, etc.
The result of fmt
applied to it arguments is the text of the format pattern, with the format specifiers replaced by their corresponding values.
Format specifiers can be customized to influence how their corresponding values are to be inserted. For instance, consider:
fmt("%s %.2e", x, y)
Then, assuming variable x
has value 3
and variable y
has value 5.6
, the result of the fmt
function is 3 5.60e+00
.
Specifiers
Format patterns support various types of format specifiers, each performing a different kind of conversion on its corresponding value. The following table lists the available conversions, the types of values that they support, and a short description of the output of the conversion:
Conversion  Supported types  Output 


Either 


Same as 


Decimal integer notation. 


Hexadecimal integer notation, using 


Hexadecimal integer notation, using 


Computerized scientific notation, using 


Computerized scientific notation, using 


Decimal number notation. 


General scientific notation, using 


General scientific notation, using 

any type 
General textual representation. 

any type 
General textual representation, in upper case. 
For the %d
, %x
, and %X
specifiers, int
typed values are supported, as are integer types with ranges (e.g. int[0..5]
). The %s
and %S
specifiers support values of any type.
The output of the %B
specifier is identical to the output of the %b
specifier, where all letters in the output are converted to upper case letters. This duality (lower case specifier conversion versus upper case specifier conversion) is present in all conversions that can have letters in their output.
Specifier syntax
Specifiers can be customized to influence the conversion of their corresponding values to text. The general syntax of specifiers is:
%[value_index$][flags][width][.precision]conversion
All specifiers start with a percentage character (%
).
They are optionally followed by a value index. If the value index is specified, it must be followed by a dollar sign ($
). The value index is a positive decimal integer indicating the position of the value in the value list. The first value is referenced by 1$
, the second by 2$
, etc. Index zero and indices starting with zero are not allowed.
The index is followed by optional flags. Flags are characters that modify the output, and may be specified in any order. Each flag may only be specified once per specifier. The set of valid flags depends on the conversion.
After the flags, an optional width may be specified. The width is a nonnegative decimal integer indicating the minimum number of characters that should be included in the result, for that specific specifier.
After the width, a precision may optionally be specified. A precision is always preceded by a dot (.
). The precision is a nonnegative decimal integer used to restrict the number of characters. The specific behavior depends on the conversion.
Specifiers always end with the character indicating the conversion to perform.
Implicit and explicit indexing
By default, format specifiers are processed in order. The first specifier then implicitly uses the first value, the second specifier implicitly uses the second value, etc. However, if an explicit value index is given, that explicit index indicates the value to use, and the specifier with the explicit index does not influence subsequent implicit indexing. That is, consider the following:
fmt("%s %1$s %3$f %d %f %1$s", 1, 2, 3.0);
The first specifier (%s
) does not specify an explicit index, and thus implicitly uses the first value. The second specifier (%1$s
) explicitly specifies index 1
and thus uses the first value. The third specifier (%3$f
) explicitly specifies index 3
and thus uses the third value. The fourth specifier (%d
) is the second specifier to not explicitly specify an index, and thus implicitly uses the second value. The fifth specifier (%f
) is the third specifier to not explicitly specify an index, and thus implicitly uses the third value. Finally, the sixth specifier (%1$s
) explicitly specifies index 1
, and thus uses the first value. The result of the formatting is:
1 1 3.000000 2 3.000000 1
Flags
The following flags are available:
Flag  b/B  d  x/X  e/E  f  g/G  s/S  Effect 


yes 
yes 
yes 
yes 
yes 
yes 
yes 
The result will be leftjustified. 

no 
yes 
no 
yes 
yes 
yes 
no 
The result will always include a sign. 
(space) 
no 
yes 
no 
yes 
yes 
yes 
no 
The result will include a leading space for nonnegative values. 

no 
yes 
yes 
yes 
yes 
yes 
no 
The result will be zeropadded. 

no 
yes 
no 
no 
yes 
yes 
no 
The result will include commas ( 
The first column shows the available flags, the minus (
), the plus (+
), the space, the zero (0
), and the comma (,
). The middle columns indicate for each of the different conversions, whether the flags are supported. The last column gives short descriptions of the effects of the flags.
The 
flag can be used to leftjustify the text in case a width is used, as the default is to rightjustify. It is supported by all format specifiers. The 
flag requires the use of a width, and can not be combined with the 0
flag.
The +
flag can be used to always include a sign. It only applies to certain numeric format specifiers. That is, by default nonnegative numbers don’t have a sign, and negative numbers start with a 
character. By including the +
flag, nonnegative numbers start with a +
character, and negative numbers still start with a 
character. The +
and space flags can not be combined.
The space flag can be used force a leading space to be included for nonnegative values. It only applies to certain numeric format specifiers. That is, by default nonnegative numbers don’t have a sign, and negative numbers start with a 
character. By including the space flag, nonnegative numbers start with a space character, and negative numbers still start with a 
character. The +
and space flags can not be combined.
The 0
flag can be used to zero pad numbers, in case a width is used, the text is rightjustified, and the text is shorter than the width. It only applies to certain numeric format specifiers. The 0
flag requires the use of a width, and can not be combined with leftjustification (the 
flag).
The ,
flag can be used to include commas (,
) as grouping separators. It only applies to certain numeric format specifiers. That is, by default numbers are just a sequence of digits. By using the ,
flag, longer numbers are placed in groups of thousands and the 'thousands separator' (the ,
character) occurs every three digits. For instance, 12345678
would then become 12,345,678
.
Further details on the effects of flags are given in the sections describing the individual conversions.
Width
The width is a nonnegative decimal integer indicating the minimum number of characters that should be included in the result, for that specific specifier. If no width is given, there is no minimum number of characters.
If the textual representation of the value is shorter than the width, the text is rightjustified. That is, the text will be padded by spaces to the left of the text until the total number of characters equals the width. To leftjustify the text, use the 
flag in combination with a width. This results in padding with spaces to the right of the text.
If the 0
flag is specified, and the textual representation of the value is shorter than the width, 0
padding is used (to the left, as the 
flag may not be used when the 0
flag is used). See the sections describing the individual number related specifiers for further details.
If the text is longer than the width, the whole text is included in the result (it is not truncated), and the width essentially has no effect.
%b
and %B
specifiers
The %b
and %B
specifiers convert boolean values to text. The specifiers only support boolean values. The specifiers support explicit indices, widths, and the 
flag. They don’t supports any of the other flags, and precisions.
The resulting text is constructed as follows:
Value
true
results in the texttrue
, and valuefalse
results in the textfalse
.For the
%B
specifier, the text is converted to upper case, i.e.TRUE
andFALSE
respectively.If a width is specified, and the resulting text so far is shorter than that width, spaces are added until the given width is reached. If the

flag is given, spaces are added to the right, otherwise spaces are added to the left.
Here are some examples, assuming b
has value true
:
fmt("%b", b); // true
fmt("%B", b); // TRUE
fmt("_%10b_", b); // _ true_
fmt("_%10b_", b); // _true _
%d
specifier
The %d
specifier converts integer numbers to text, using decimal representations of integers. The specifier only support integer values (int
typed values, and values of integer types with ranges, such as int[0..5]
). The specifier supports explicit indices, widths, and all flags. It doesn’t support precisions.
The resulting text is constructed as follows:
The resulting text is initialized to the decimal representation of the absolute value of the integer number. It thus consists of only the digits
0
through9
.If the
,
flag is given, thousand separators (,
characters) are inserted as needed, for longer numbers.If the number is negative, it is prefixed with a

character.If the number is nonnegative, and the space flag is given, a space is added before the text.
If the number is nonnegative, and the
+
flag is given, a+
character is added before the text.If a width is given, the text so far is shorter than the width, and the
0
flag is given, then0
characters are added before the other digits, and after any nondigit characters, until the desired width is reached.If a width is given, the text so far is shorter than the width, and the

flag is given, then space characters are added before the result, until the desired width is reached.If a width is given, the text so far is shorter than the width, and neither the
0
flag nor the
flag is given, then space characters are added after the result, until the desired width is reached.
Here are some examples, assuming x
has value 12345
and y
has value 2345
:
fmt("%d", x); // 12345
fmt("%,d", x); // 12,345
fmt("_%10d_", x); // _ 12345_
fmt("_%10d_", x); // _12345 _
fmt("_%0,10d_", x); // _000012,345_
fmt("_% 10d_", x); // _ 12345 _
fmt("_% 10d_", y); // _2345 _
fmt("_%+10d_", x); // _+12345 _
fmt("_%+10d_", y); // _2345 _
fmt("_%3d_", x); // _12345_
%x
and %X
specifiers
The %x
and %X
specifiers convert integer numbers to text, using hexadecimal representations of integers. The specifiers only support integer values (int
typed values, and values of integer types with ranges, such as int[0..5]
). The specifiers supports explicit indices, widths, and the 
and 0
flags. They don’t supports any of the other flags, and precisions.
The resulting text is constructed as follows:
The signed integer number in range [2,147,483,648 .. 2,147,483,647] is first converted to an unsigned integer number in range [0 .. 4,294,967,295]. That is, for negative numbers, 2^{32} is added.
The resulting text is initialized to the hexadecimal representation of the unsigned integer number. It thus consists the digits
0
through9
and lettersa
throughf
.For the
%X
specifier, the text is converted to upper case, i.e. lettersa
throughf
are converted to lettersA
throughF
.If a width is given, the text so far is shorter than the width, and the
0
flag is given, then0
characters are added before the result, until the desired width is reached.If a width is given, the text so far is shorter than the width, and the

flag is given, then space characters are added before the result, until the desired width is reached.If a width is given, the text so far is shorter than the width, and neither the
0
flag nor the
flag is given, then space characters are added after the result, until the desired width is reached.
Here are some examples, assuming a
has value 5543
and b
has value 1
:
fmt("%x", a); // 15a7
fmt("0x%x", a); // 0x15a7
fmt("0x%X", a); // 0x15A7
fmt("0x%X", b); // 0xFFFFFFFF
fmt("_%10x_", a); // _ 15a7_
fmt("_%10x_", a); // _15a7 _
fmt("_%3x_", a); // _15a7_
%e
and %E
specifiers
The %e
and %E
specifiers convert real numbers to text, using computerized scientific notation. The specifiers only support real values. The specifiers supports explicit indices, widths, the 
, +
, space, and 0
flags, and precisions. They don’t supports any of the other flags.
Real numbers include a decimal mark, a symbol used to separate the integer part from the fractional part of number, when written in decimal form. This decimal mark is denoted by a dot (.
).
The resulting text is constructed as follows:
The decimal mark of the real number is shifted to ensure that at most one nonzero digit occurs to the left of it. That is, for real numbers
0.012
,0.12
,1.2
,12.0
, and120.0
, the decimal mark is shifted 2, 1, 0, 1, and 2 digits to the left, respectively. This results in the following real numbers:1.2
,1.2
,1.2
,1.2
, and1.2
. For zero, the decimal mark is not shifted.The single decimal digit before the decimal mark is included in the result. If there is no digit before the decimal mark (in case the real number is zero), a single
0
digit is included in the result.If the precision is specified and is not zero, or if the default precision is used, a dot (
.
) is added after the single digit.The digits after the decimal mark are added after the dot. Exactly 'precision' digits will be added. If no precision is specified, it defaults to
6
digits after the dot. If not enough digits are available after the dot, additional0
characters are added after them, to reach the desired precision. If too many digits are available after the dot, digits are removed from the right until the desired precision is reached. Rounding using the 'half up' algorithm is used to ensure correct results in case digits are removed.If the
%e
specifier is used, ane
character is added to the end. If the%E
specifier is used, anE
character is added to the end.A sign character is added after that. That is, if the decimal mark was shifted a negative number of digits to the left, a

character is added, otherwise a+
character is added.The number of digits that was shifted is added as a decimal number, at the end. At least two decimal digits are added, so if the number of digits that was shifted can be represented using a single decimal digit, a
0
is added between thee
orE
character and the number of digits that was shifted.If the real number is negative, the text is prefixed with a

character.If the real number is nonnegative, and the space flag is given, a space is added before the text.
If the real number is nonnegative, and the
+
flag is given, a+
character is added before the text.If a width is given, the text so far is shorter than the width, and the
0
flag is given, then0
characters are added before the other digits, and after any nondigit characters, until the desired width is reached.If a width is given, the text so far is shorter than the width, and the

flag is given, then space characters are added before the result, until the desired width is reached.If a width is given, the text so far is shorter than the width, and neither the
0
flag nor the
flag is given, then space characters are added after the result, until the desired width is reached.
Here are some examples, assuming a
has value 12345.6789
and b
has value 0.00002345678
:
fmt("%e", a); // 1.234568e+04
fmt("%E", a); // 1.234568E+04
fmt("%.3e", a); // 1.235e+04
fmt("%.3e", b); // 2.346e05
fmt("_%20e_", a); // _ 1.234568e+04_
fmt("_%20e_", a); // _1.234568e+04 _
fmt("_%5e_", a); // _1.234568e+04_
fmt("_%020e_", a); // _000000001.234568e+04_
fmt("_%+20e_", a); // _+1.234568e+04 _
fmt("_%+20e_", b); // _2.345678e05 _
fmt("_% 20e_", a); // _ 1.234568e+04 _
fmt("_% 20e_", b); // _2.345678e05 _
%f
specifier
The %f
specifier converts real numbers to text, using a decimal number notation. The specifier only supports real values. The specifier supports explicit indices, widths, all flags, and precisions. That is, all features of format specifiers are supported.
Real numbers include a decimal mark, a symbol used to separate the integer part from the fractional part of number, when written in decimal form. This decimal mark is denoted by a dot (.
).
The resulting text is constructed as follows:
The decimal digits before the decimal mark are included in the result. If there are no digits before the decimal mark, a single
0
digit is included in the result.If the
,
flag is given, thousand separators (,
characters) are inserted as needed, for longer numbers.If the precision is specified and is not zero, or if the default precision is used, a dot (
.
) is added after the digits.The digits after the decimal mark are added after the dot. Exactly 'precision' digits will be added. If no precision is specified, it defaults to
6
digits after the dot. If not enough digits are available after the dot, additional0
characters are added after them, to reach the desired precision. If too many digits are available after the dot, digits are removed from the right until the desired precision is reached. Rounding using the 'half up' algorithm is used to ensure correct results in case digits are removed.If the real number is negative, the text is prefixed with a

character.If the real number is nonnegative, and the space flag is given, a space is added before the text.
If the real number is nonnegative, and the
+
flag is given, a+
character is added before the text.If a width is given, the text so far is shorter than the width, and the
0
flag is given, then0
characters are added before the other digits, and after any nondigit characters, until the desired width is reached.If a width is given, the text so far is shorter than the width, and the

flag is given, then space characters are added before the result, until the desired width is reached.If a width is given, the text so far is shorter than the width, and neither the
0
flag nor the
flag is given, then space characters are added after the result, until the desired width is reached.
Here are some examples, assuming a
has value 12345.6789
and b
has value 0.00002345678
:
fmt("%f", a); // 12345.678900
fmt("%f", b); // 0.000023
fmt("%.3f", a); // 12345.679
fmt("_%20f_", a); // _ 12345.678900_
fmt("_%20f_", a); // _12345.678900 _
fmt("_%,20f_", a); // _12,345.678900 _
fmt("_%5f_", a); // _12345.678900_
fmt("_%020f_", a); // _0000000012345.678900_
fmt("_%+20f_", a); // _+12345.678900 _
fmt("_%+20f_", b); // _0.000023 _
fmt("_% 20f_", a); // _ 12345.678900 _
fmt("_% 20f_", b); // _0.000023 _
%g
and %G
specifiers
The %g
and %G
specifiers convert real numbers to text, using general scientific notation. The specifiers only support real values. The specifiers supports explicit indices, widths, all flags, and precisions. That is, all features of format specifiers are supported.
Real numbers include a decimal mark, a symbol used to separate the integer part from the fractional part of number, when written in decimal form. This decimal mark is denoted by a dot (.
).
If the real number is greater than or equal to 10^{4} but less than 10^{precision}, the result is as %f
. Otherwise, the result is as %e
and %E
, for %g
and %G
respectively. However, the total number of significant digits of the result is equal to the precision of the %g
or %G
specifier, and defaults to 6
if not specified. If the specified precision is 0
, it is taken to be 1
instead.
Here are some examples, assuming a
has value 12345.6789
and b
has value 0.00002345678
:
fmt("%g", a); // 12345.7
fmt("%g", b); // 2.34568e05
fmt("%G", b); // 2.34568E05
fmt("%.3g", a); // 1.23e+04
fmt("_%20g_", a); // _ 12345.7_
fmt("_%20g_", a); // _12345.7 _
fmt("_%,20g_", a); // _12,345.7 _
fmt("_%5g_", a); // _12345.7_
fmt("_%020g_", a); // _000000000000012345.7_
fmt("_%+20g_", a); // _+12345.7 _
fmt("_%+20g_", b); // _2.34568e05 _
fmt("_% 20g_", a); // _ 12345.7 _
fmt("_% 20g_", b); // _2.34568e05 _
%s
and %S
specifiers
The %s
and %S
specifiers convert any value to text. The specifiers support values of any type. The specifiers supports explicit indices, widths, and the 
flag. They don’t supports any of the other flags, and precisions.
The resulting text is constructed as follows:
If the value has a
string
type, the value of that string is used as is, without escaping and double quoting. Otherwise, the value is converted to a textual representation closely resembling the CIF textual syntax (ASCII syntax), with string values surrounded by double quotes, and with special characters (tabs, new lines, double quotes, and backslashes) escaped.For the
%S
specifier, the text is converted to upper case, i.e. lettersa
throughz
are converted to lettersA
throughZ
.If a width is specified, and the resulting text so far is shorter than that width, spaces are added until the given width is reached. If the

flag is given, spaces are added to the right, otherwise spaces are added to the left.
Here are some examples, assuming x
has value "aBcD"
:
fmt("%s", x); // aBcD
fmt("%S", x); // ABCD
fmt("_%10s_", x); // _ aBcD_
fmt("_%10s_", x); // _aBcD _
As indicated above, string
typed values are of special interest. For instance, consider the following examples:
fmt("a %s b", ("some \\ text", 6)); // a ("some \\ text", 6) b
fmt("a %s b", "some \\ text"); // c some \ text d
The first example has a tuple as value, with a string and an integer number. The output of this example is a ("some \\ text", 6) b
. Note how the string in the tuple is included in the output with double quotes around it, and how the escaped backslash is also escaped in the resulting text.
The second example has a value that is a string directly (e.g. not contained in a tuple or some other container). This mapping results in c some \ text d
. Note how the string is included in the output 'as is', i.e. it is not surrounded by double quotes, and the backslash is not escaped.
In general, when using a %s
specifier, string values are double quoted and escaped. If however the entire value is a string, then that string is used 'as is' (without quoting, and without escaping).
Also of special interest are real values. The number of digits after the decimal point can vary. For instance, consider the following examples:
fmt("a %s b", 1 / 3); // a 0.3333333333333333 b
fmt("c %s d", 1 / 2); // c 0.5 d
Escaping and quoting
Double quote terminate string literals, and thus also a format pattern, as format patterns are string literals. It is therefore not possible to include a double quote in the text of a format pattern without escaping it. That is, use \"
inside a format pattern to include a single double quote. There are other escape sequences as well. Use \\
to include a single backslash (\
), \n
to include a single new line (to continue on a new line), and \t
to include a tab character (for alignment).
Format specifiers start with a percentage character (%
). If a percentage character is to be included as a percentage character instead of being interpreted as a format specifier, it needs to be escaped as well. That is, to include a percentage character as a percentage character, use %%
in the format pattern.
For instance, the format pattern "a\"b\nc\td\\e%%f"
results in the following text:
a"b
c d\e%f