format.h#
Various function to print formatted strings to file objects.
Authors#
TheSilvered
Nst_fmt format rules#
General format syntax#
{Type[:[Flags][Width][.Precision][,SeparatorWidth][Alignment]]}
The things inside the square brackets are optional.
To write a curly brace {, write {{, and to write }, write }} instead.
Type#
The type determines how the argument passed is read. The following types are allowed:
sforchar *(string)Bforu8(takes auintbut expects values in the range[0, 255])iforintoruint(unsigned int)lfori32oru32Lfori64oru64zforisizeorusizebforbool(takes anintbut writestrueorfalseinstead of1and0)fforf32orf64cforcharpforvoid *
Flags#
The available flags are:
g,G: general representation forRealsf,F: decimal representation forRealse,E: standard (or scientific) notation forRealsb: binary integer representationo: octal integer representationx: hexadecimal integer representationX: uppercase hexadecimal integer representationu: treat the integer as unsigned0: fill with zeroes(space): add a space in front of positive numbers+: add a plus sign in front of positive numbersr: Nest literal string representationR: escape special charactersa: ASCII Nest literal string representationA: escape special and non-ASCII charactersp: lowercase affixes/general lowercaseP: uppercase affixes/general uppercase': thousand separator_: padding characterc: cut to width
Note
If a flag is not supported by the type it is used with it is ignored. If
incompatible flags are used in the same format, such as {i:bo}, only the
latter will be used.
The g and G flags#
These flags are only supported by the f type. They set the general
representation mode to be used though mode g is the default.
In general representation the number is represented with precision
significant digits and will alternate between the f or F mode and the e
or E modes depending on its magnitude.
The f or F mode is used when -4 <= exp < precision where exp is the
exponent in standard notation of the number. When the exponent falls outside
of this range the e or E representation is used.
The difference between g and G is that the latter will always contain a
decimal point where the former may strip it away.
For example:
Nst_fmt("{f:g.3}", 0, NULL, 100.0); // results in "100"
Nst_fmt("{f:G.3}", 0, NULL, 100.0); // results in "100.0"
Note
The g in the first line can be omitted since it is the default mode.
When using the G mode significant digits are automatically increased to
properly display the digit after the decimal point, for example:
Nst_fmt("{f:G.3}", 0, NULL, 123.4); // results in "123.4" even with
// a precision of 3
The f and F flags#
These flags are only supported by the f type. They set the decimal
representation mode to be used.
In this representation the number is printed with precision digits after the
decimal point though trailing zeroes are removed.
For example:
Nst_fmt("{f:f}", 0, NULL, 13.5871558); // results in "13.587156"
Nst_fmt("{f:f}", 0, NULL, 13.5); // results in "13.5"
Nst_fmt("{f:f}", 0, NULL, 10.0); // results in "10"
Nst_fmt("{f:f}", 0, NULL, 0.0248); // results in "0.0248"
Similarly to G and E, the F flag will always include a decimal point,
for example:
Nst_fmt("{f:F}", 0, NULL, 10.0); // results in "10.0"
The e and E flags#
These flags are only supported by the f type. They set the standard notation
mode to be used.
In this representation the number is printed with one non-zero digit before
the dot (unless the number itself is zero) followed by at most precision
digits after the dot, any trailing zeroes are removed by default.
For example:
Nst_fmt("{f:e}", 0, NULL, 13.5871558); // results in "1.358716e+01"
Nst_fmt("{f:e}", 0, NULL, 13.5); // results in "1.35e+01"
Nst_fmt("{f:e}", 0, NULL, 10.0); // results in "1e+01"
Nst_fmt("{f:e}", 0, NULL, 0.0248); // results in "2.48e-02"
Similarly to G and F, the E flag will always include a decimal point,
for example:
Nst_fmt("{f:e}", 0, NULL, 10.0); // results in "1.0e+01"
The b, o, x and X flags#
These flags are supported by B, i, l, L and z and determine the base
used to represent them. Additionally the X flag is supported by the p type.
The b flag will use binary, the o flag will use octal, the x flag will
use hexadecimal with lower-case a-f digits and X will used hexadecimal with
upper-case A-F digits. For example:
Nst_fmt("{i:b}", 0, NULL, 28); // results in "11100"
Nst_fmt("{i:o}", 0, NULL, 28); // results in "34"
Nst_fmt("{i}", 0, NULL, 28); // results in "28"
Nst_fmt("{i:x}", 0, NULL, 28); // results in "1c"
Nst_fmt("{i:X}", 0, NULL, 28); // results in "1C"
By default no prefixes are added to the numbers.
On the p type by default the 0x prefix is added, using the X flag you
can add the 0X prefix instead.
Nst_fmt("{p}", 0, NULL, (void *)0x325c4e4); // results in "0x325c4e4"
Nst_fmt("{p:X}", 0, NULL, (void *)0x325c4e4); // results in "0X325c4e4"
The u flag#
This flag is supported by i, l, L and z and indicates to use the
unsigned variant of the types. For i this flag will read a uint instead of
an int, for l it will read a u32 instead of a i32 and so on.
The 0 flag#
This flag will have a different behaviour depending on the type.
For B, i, l, L and z it will add zeroes between the number and the
sign until the number of digits matches the precision. When using this flag the
thousand separator is put between the zeroes. For example:
Nst_fmt("{i:0.4}", 0, NULL, 16); // results in "0016"
Nst_fmt("{i:0',.4}", 0, NULL, 16); // results in "0,016"
For the p type this flag will add zeroes before the 0x or 0X prefix to
reach 16 characters on 64-bit machines and 8 characters on 32-bit ones. For
example:
// on x64
Nst_fmt("{p:0}", 0, NULL, (void *)0x325c4e4); // results in "0x000000000325c4e4"
// on x86
Nst_fmt("{p:0}", 0, NULL, (void *)0x325c4e4); // results in "0x0325c4e4"
For the f type this flag will stop any trailing zeroes from being removed.
for example:
Nst_fmt("{f:g0}", 0, NULL, 10.0); // results in "10.0000"
Nst_fmt("{f:f0}", 0, NULL, 10.0); // results in "10.000000"
Nst_fmt("{f:e0}", 0, NULL, 10.0); // results in "1.000000e+01"
The (space) and + flags#
These flags are supported by B, i, l, L, z and f and add either a
space or a plus sign before positive numbers. For example:
Nst_fmt("{i}", 0, NULL, 10); // results in "10"
Nst_fmt("{i:+}", 0, NULL, 10); // results in "+10"
Nst_fmt("{i: }", 0, NULL, 10); // results in " 10"
If the number is unsigned it is treated as positive and thus a space or a plus is added in front.
Nst_fmt("{i:u+}", 0, NULL, 10); // results in "+10"
The r, R, a and A flags#
These flags are supported by the s type and specify a representation mode
for the string.
The r flag will make the string into a valid Nest literal, adding either
single or double quotes around it and escaping non-printable or special
characters.
Nst_fmt("{s:r}", 0, NULL, "hello😊\n"); // results in "'hello😊\\n'"
The R flag will instead only escape special characters (including the
backslash \ but not quotes) and leaving everything else untouched.
Nst_fmt("{s:R}", 0, NULL, "hello😊\n"); // results in "hello😊\\n"
The a flag is similar to the r flag but the string will be translated into
printable ASCII using unicode escapes for non-ASCII characters.
Nst_fmt("{s:R}", 0, NULL, "hello😊\n"); // results in "'hello\\U01f60a\\n'"
The A flag is similar to the R flag but it will also escape any non-ASCII
character.
Nst_fmt("{s:R}", 0, NULL, "hello😊\n"); // results in "hello\\U01f60a\\n"
The p flag#
This flag is supported by B, i, l, L, z and f.
For the B type it will add the 0b prefix and the b suffix in binary mode,
the 0o prefix and the b suffix in octal mode, the b suffix in decimal
mode and the 0h prefix in hexadecimal mode (both upper and lower-case). For
example:
Nst_fmt("{B:bp}", 0, NULL, 28); // results in "0b11100b"
Nst_fmt("{B:op}", 0, NULL, 28); // results in "0o34b"
Nst_fmt("{B:p}", 0, NULL, 28); // results in "28b"
Nst_fmt("{B:xp}", 0, NULL, 28); // results in "0h1c"
Nst_fmt("{B:Xp}", 0, NULL, 28); // results in "0h1C"
For i, l, L and z it will add the 0b prefix in binary mode, the 0o
prefix in octal mode and the 0x prefix in hexadecimal mode (both upper and
lower-case). For example:
Nst_fmt("{i:bp}", 0, NULL, 28); // results in "0b11100"
Nst_fmt("{i:op}", 0, NULL, 28); // results in "0o34"
Nst_fmt("{i:p}", 0, NULL, 28); // results in "28"
Nst_fmt("{i:xp}", 0, NULL, 28); // results in "0x1c"
Nst_fmt("{i:Xp}", 0, NULL, 28); // results in "0x1C"
For the f type it will format NaN and Inf as nan and inf.
Nst_fmt("{f}" , 0, NULL, INFINITY); // results in "Inf"
Nst_fmt("{f:p}", 0, NULL, INFINITY); // results in "inf"
Nst_fmt("{f}", 0, NULL, NAN); // results in "NaN"
Nst_fmt("{f:p}", 0, NULL, NAN); // results in "nan"
The P flag#
This flag is supported by B, i, l, L, z, f, b and p
For the B type it will add the 0B prefix and the B suffix in binary mode,
the 0O prefix and the B suffix in octal mode, the B suffix in decimal
mode and the 0H prefix in hexadecimal mode (both upper and lower-case). For
example:
Nst_fmt("{B:bP}", 0, NULL, 28); // results in "0B11100b"
Nst_fmt("{B:oP}", 0, NULL, 28); // results in "0O34b"
Nst_fmt("{B:P}", 0, NULL, 28); // results in "28B"
Nst_fmt("{B:xP}", 0, NULL, 28); // results in "0H1c"
Nst_fmt("{B:XP}", 0, NULL, 28); // results in "0H1C"
For i, l, L and z it will add the 0B prefix in binary mode, the 0O
prefix in octal mode and the 0X prefix in hexadecimal mode (both upper and
lower-case). For example:
Nst_fmt("{i:bp}", 0, NULL, 28); // results in "0B11100"
Nst_fmt("{i:op}", 0, NULL, 28); // results in "0O34"
Nst_fmt("{i:p}", 0, NULL, 28); // results in "28"
Nst_fmt("{i:xp}", 0, NULL, 28); // results in "0X1c"
Nst_fmt("{i:Xp}", 0, NULL, 28); // results in "0X1C"
For the f type it will format NaN and Inf as NAN and INF and the e
in standard notation will be an upper-case E.
Nst_fmt("{f}" , 0, NULL, INFINITY); // results in "Inf"
Nst_fmt("{f:P}", 0, NULL, INFINITY); // results in "INF"
Nst_fmt("{f}", 0, NULL, NAN); // results in "NaN"
Nst_fmt("{f:P}", 0, NULL, NAN); // results in "NAN"
Nst_fmt("{f:eP}", 0, NULL, 10.0); // results in "1E+01"
For the b type it will format true and false as TRUE and FALSE.
Nst_fmt("{b}" , 0, NULL, true); // results in "true"
Nst_fmt("{b:P}", 0, NULL, true); // results in "TRUE"
For the p type it will make the prefix be 0X instead of 0x.
Nst_fmt("{p}", 0, NULL, (void *)0x325c4e4); // results in "0x325c4e4"
Nst_fmt("{p:P}", 0, NULL, (void *)0x325c4e4); // results in "0X325c4e4"
The ' flag#
This flag is supported by B, i, l, L and f, it specifies the
character to be used as the thousand separator.
It is not a standalone flag as it needs to be followed by another character that will be the actual character used.
For example:
Nst_fmt("{i}", 0, NULL, 1000000); // results in "1000000"
Nst_fmt("{i:''}", 0, NULL, 1000000); // results in "1'000'000"
Nst_fmt("{i:',}", 0, NULL, 1000000); // results in "1,000,000"
Nst_fmt("{i:' }", 0, NULL, 1000000); // results in "1 000 000"
The _ flag#
This flag is supported by all types and specifies the character used to fill
the extra space to reach width characters on the formatted value. If the
width is not specified this flag has no meaning.
Just like the ' flag it is not a standalone flag as it needs to be followed
by another character that will be the actual character used.
By default the padding character is a space.
For example:
Nst_fmt("{s}", 0, NULL, "hi"); // results in "hi"
Nst_fmt("{s:5}", 0, NULL, "hi"); // results in "hi "
Nst_fmt("{s:_.5}", 0, NULL, "hi"); // results in "hi..."
Nst_fmt("{s:__5}", 0, NULL, "hi"); // results in "hi___"
The c flag#
This flag is supported by all types and will make the formatted value exactly
width characters long. If the string is shorter than width it will be
padded normally but if it is longer it will be trimmed.
Nst_fmt("{s:4}", 0, NULL, "hi"); // results in "hi "
Nst_fmt("{s:4}", 0, NULL, "hello"); // results in "hello"
Nst_fmt("{s:c4}", 0, NULL, "hi"); // results in "hi "
Nst_fmt("{s:c4}", 0, NULL, "hello"); // results in "hell"
This flag will cut the value according to the alignment: values aligned to the left will be cut from the right, values aligned to the right will be cut to the left and values aligned in the middle will be cut from both sides.
Width#
This field specifies the minimum width of the formatted value, if the string is
shorter than the specified width it is padded by default with spaces. The _
flag is used to specify what character to use instead of the space.
When the c flag is used this field specifies the exact width of the resulting
string, shorter strings will still be padded but strings that are too long will
be cut to size regardless of the value, this means that digits and signs can
be cut off numbers.
The width can be specified directly with a number after the flags or by writing
an asterisk and passing an int value in the arguments after the value to be
formatted. For example:
Nst_fmt("{i:5}", 0, NULL, 123); // results in " 123"
Nst_fmt("{i:*}", 0, NULL, 123, 4); // results in " 123"
A negative width is ignored and a width of zero is useless without the c
flag.
Precision#
This field has different interpretations depending on the type being formatted:
For the f type in decimal and standard notation (with the f and e flags)
it specifies the number of digits after the dot. By default the precision is
6.
Nst_fmt("{f:f.3}", 0, NULL, 1.234567); // results in "1.235"
Nst_fmt("{f:e.3}", 0, NULL, 1.234567); // results in "1.235e+00"
Nst_fmt("{f:f}", 0, NULL, 1.234567); // results in "1.234567"
Nst_fmt("{f:e}", 0, NULL, 1.234567); // results in "1.234567e+00"
For the f type in general notation the precision specifies the number of
significant digits to show. By default the precision is 6.
Nst_fmt("{f:.3}", 0, NULL, 1.234567); // results in "1.23"
Nst_fmt("{f}", 0, NULL, 1.234567); // results in "1.23457"
For B, i, l and L it specifies the minimum number of characters before
the sign, by default the extra characters are spaces but using the 0 flag
they become zeroes.
Nst_fmt("{i}", 0, NULL, 123); // results in "123"
Nst_fmt("{i:.5}", 0, NULL, 123); // results in " 123"
Nst_fmt("{i:0.5}", 0, NULL, 123); // results in "00123"
When using a thousand separator it is displayed when using the 0 flag and is
otherwise accounted for with extra spaces in order to reach the same number of
characters in the final output.
Nst_fmt("{i:0',.5}", 0, NULL, 123); // results in "00,123"
Nst_fmt("{i:',.5}", 0, NULL, 123); // results in " 123"
Nst_fmt("{i:.5}", 0, NULL, 123); // results in " 123"
For the s type it specifies the maximum amount of characters to write, if a
string is longer than specified it is shortened to size removing characters
from the right and adding an ellipsis (...) at the end.
Nst_fmt("{s:.5}", 0, NULL, "short"); // results in "short"
Nst_fmt("{s:.5}", 0, NULL, "somewhat long"); // results in "somew..."
The precision can be specified directly with a number after the dot (.) or by
writing an asterisk and passing an int value in the arguments after the value
to be formatted and, if specified, the width. For example:
Nst_fmt("{i:.5}", 0, NULL, 123); // results in " 123"
Nst_fmt("{i:.*}", 0, NULL, 123, 4); // results in " 123"
Nst_fmt("{i:0*.*}", 0, NULL, 123, 6, 4); // results in " 0123"
A negative precision is ignored.
Separator width#
This field applies to the types that support the ' flag and changes the
amount of digits between separators from the default.
The default values for the separator width is as follows:
8for numbers in binary3for numbers in octal or decimal (including all floats)4for numbers in hexadecimal
Like the precision, the separator width can be specified directly with a number
after the comma (,) or by writing an asterisk and passing an int value in
the arguments after the value to be formatted and, if specified, the width and
the precision. For example:
Nst_fmt("{i:''}", 0, NULL, 12345); // results in "12'345"
Nst_fmt("{i:'',4}", 0, NULL, 12345); // results in "1'2345"
Nst_fmt("{i:''.*}", 0, NULL, 12345, 2); // results in "1'23'45"
Nst_fmt("{i:''0*.*,*}", 0, NULL, 123, 6, 4, 2); // results in " 01'23"
A separator width smaller than one ignored.
Alignment#
This field specifies the alignment of the formatted string. It is meaningful
only when used along side the width because otherwise the formatted values
will only ever be as bit as necessary.
The alignment can be one of three values:
<: left align (default behaviour for most types)>: right align (default behaviour forB,i,l,Landf)^: center align
A left alignment will cause the value to be placed on the left and the padding on the right and will cause the string to be cut from the right.
A right alignment will cause the value to be placed on the right and the padding on the left and will cause the string to be cut from the left.
A center alignment will cause the value to be placed in the middle with the padding on both sides and will cause the string to be cut from both the left and the right.
Functions#
Nst_print#
Synopsis:
isize Nst_print(const char *buf)
Description:
Print a string to the Nest standard output.
Warning
Do not use this function to print Str objects, use
Nst_fwrite instead.
Parameters:
buf: the NUL-terminated string to print
Returns:
The number of bytes written. If the file is closed -1 is returned. No error is
set.
Nst_fprint#
Synopsis:
isize Nst_fprint(Nst_Obj *f, const char *buf)
Description:
Print a string to a Nest file object.
Warning
Do not use this function to print Str objects, use
Nst_fwrite instead.
Parameters:
f: the file to print the string tobuf: the NUL-terminated string to print
Returns:
The number of bytes written. If the file is closed -1 is returned. No error is
set.
Nst_println#
Synopsis:
isize Nst_println(const char *buf)
Description:
Print a string to the Nest standard output appending a newline character.
Warning
Do not use this function to print Str objects, use
Nst_fwrite instead.
On all platforms only a newline (U+000A) is appended, NOT a carriage return.
Parameters:
buf: the NUL-terminated string to print
Returns:
The number of bytes written, including the newline character. If the file is
closed -1 is returned. No error is set.
Nst_fprintln#
Synopsis:
isize Nst_fprintln(Nst_Obj *f, const char *buf)
Description:
Print a string to a Nest file object appending a newline character.
On all platforms only a newline (U+000A) is appended, NOT a carriage return.
Warning
Do not use this function to print Str objects, use
Nst_fwrite instead.
Parameters:
f: the file to print the string tobuf: the NUL-terminated string to print
Returns:
The number of bytes written, including the newline character. If the file is
closed -1 is returned. No error is set.
Nst_printf#
Synopsis:
isize Nst_printf(const char *fmt, ...)
Description:
Print a formatted string to the Nest standard output. The format specifier works
like that of C's
printf.
Parameters:
fmt: the format placeholder...: the arguments to be formatted
Returns:
The number of characters written. On failure a negative value is returned and no error is set. The negative value returned depends on the type of the error:
-1signals a failure of vsprintf,-2that the output file is closed,-3an error in the format string and-4a memory allocation error.
Nst_fprintf#
Synopsis:
isize Nst_fprintf(Nst_Obj *f, const char *fmt, ...)
Description:
Print a formatted string to a Nest file object. The format specifier works like
that of C's printf.
Parameters:
f: the file to print the string tofmt: the format placeholder...: the arguments to be formatted
Returns:
The number of characters written. On failure a negative value is returned and no error is set. The negative value returned depends on the type of the error:
-1signals a failure of vsprintf,-2that the output file is closed,-3an error in the format string and-4a memory allocation error.
Nst_vfprintf#
Synopsis:
isize Nst_vfprintf(Nst_Obj *f, const char *fmt, va_list args)
Description:
va_list variant of Nst_fprintf.
Nst_sprintf#
Synopsis:
Nst_ObjRef *Nst_sprintf(const char *fmt, ...)
Description:
Create a Nest string object from a format placeholder. The format specifier
works like that of C's
printf.
Check the full printf format rules.
Parameters:
fmt: the format placeholder...: the arguments to be formatted
Returns:
The function returns the newly created string object.
Nst_vsprintf#
Synopsis:
Nst_ObjRef *Nst_vsprintf(const char *fmt, va_list args)
Description:
va_list variant of Nst_sprintf.
Nst_fmt#
Synopsis:
u8 *Nst_fmt(const char *fmt, usize fmt_len, usize *out_len, ...)
Description:
Create a heap-allocated string formatted with a more customizable format placeholder.
Check the full format rules for this function.
Parameters:
fmt: the format placeholderfmt_len: the length offmt, if set to0is it determined usingstrlenout_len: pointer to a value filled with the final length of the formatted string, it can beNULL...: the values to format
Returns:
The newly created string or NULL on failure, the error is set. When the
function fails and out_len is not NULL it is set to 0.
Nst_vfmt#
Synopsis:
u8 *Nst_vfmt(const char *fmt, usize fmt_len, usize *out_len, va_list args)
Description:
va_list variant of Nst_fmt.
Nst_fmt_objs#
Synopsis:
Nst_ObjRef *Nst_fmt_objs(Nst_Obj *fmt, Nst_Obj **values, usize value_count)
Description:
Create a string object formatted using Nest objects.
The format is similar to the
full format rules of
Nst_fmt except that the type of the value to format
is taken from the object and the general syntax for a format placeholder becomes
{[Flags][Width][.Precision][,SeparatorWidth][Alignment]} (the Type and the
: have been removed).
Parameters:
fmt: the format placeholdervalues: the objects to use when formattingvalue_count: the number of objects given
Returns:
A new object of type Str or NULL on failure. The error is set.
Nst_repr#
Synopsis:
u8 *Nst_repr(u8 *str, usize str_len, usize *out_len, bool shallow, bool ascii)
Description:
Make a string into its representation, like using the r, R, a and A
flags in Nst_fmt.
Parameters:
str: the initial stringstr_len: the length in bytes of the string, if set to zero it will be calculated withstrlenout_len: pointer to be set with the length of the output string, if set toNULLit will be ignoredshallow: if set to true it will only escape special characters, like theRandAflagsascii: if set to true it will produce an output that uses only printable ASCII characters
Returns:
A pointer to the string representation or NULL on failure. The error is set.