CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
Formatting

Modules

 Formattable interface
 

Macros

#define strFormat(out, fmt, ...)    _strFormat(out, fmt, count_macro_args(__VA_ARGS__), (stvar[]) { __VA_ARGS__ })
 

Detailed Description

Type-safe string formatter with variable substitution and rich formatting options.

Though the function prototype itself is extremely simple, the usage is not. On a basic level, the formatter works similarly to printf, but is type safe and has many convenience features.

Format syntax

The format string is copied as-is unless the character sequence ${ is encountered. This sequence triggers a variable replacement, and everything until the next } is considered to be part of the variable. If a literal ${ is needed, it can be escaped with a backtick – i.e. `${

Variable substitution follows the following format, where N stands for a number and square brackets mark optional parts (the brackets around idx are literal):

${type} ${typeN} // e.g. ${type1} ${type:key} ${type#[idx](width,fmtopts);default} ${type:key[idx](width,fmtopts);default}

or, broken down: [prefix] type [N] [:key] [ [idx] ] [(width,fmtopts)] [;default]

The subscript precedes the formatting options because it binds tighter: it selects which value to render, and the options then apply to whatever came out. So ${int[2](6)} takes element 2 and pads it to a width of 6. The reverse order is rejected rather than silently accepted.

type is a type name (see below), and N indicates the n-th instance of that particular type in the format arguments. Both are OPTIONAL, but at least one of type or :key must be present. If N is omitted, an internal count is maintained, and each time that type name is used, the count is increased.

For example, ${string} indicates the next string in the argument sequence, and ${int3} uses the third integer.

Optional prefixes

An optional prefix may precede the type name. Supported prefixes are:

Format options

fmtopts is a comma-delimited list of formatting options, most of which are specific to particular types – see below for details. A formatting option that is just a number by itself is interpreted to be the field width.

Most types right-justify within the field width if it is present – this can be overridden with the formatting options of left, or center.

Supported types

Keyed arguments

An argument passed with stvark() carries a name, and :key selects it by that name instead of by type and position. Keyed lookup searches the whole argument list and is order-independent, so keyed and positional placeholders can be freely interleaved without disturbing each other.

The two addressing modes are disjoint: a keyed argument is never matched by an unkeyed placeholder, and a keyed placeholder never consults unkeyed arguments. This means adding a keyed argument to an existing call cannot renumber the placeholders already there, which is the whole point of naming one.

Keys compose with container subscripting (below), which is the only way to disambiguate two containers of the same element type in one call. A typeless keyed subscript takes its type from the container's element or value type, since that is what actually gets rendered.

strFormat(&s, _SL("${string:host} took ${int:ms}ms"),
stvark(host, string, hostname), stvark(ms, int32, elapsed));
#define strFormat(out, fmt,...)
Definition format.h:191
#define _SL(s)
Inline ASCII string literal with compile-time embedded length (STR_LEN8). Content must be < 200 bytes...
Definition strliteral.h:207
#define stvark(key, typen, val)
Definition stvar.h:204

The key sits in the type-name position, before any subscript or formatting options, so that the typed and typeless forms parse identically. Omitting the type is a convenience: the argument's own runtime type selects the formatter.

Container indexing

The 'idx' field subscripts a container argument and acts as a modifier on the type. Both forms use square brackets; which one applies is decided from the bracket contents, never from which arguments happen to be present:

Bracket contents that parse as a non-negative integer are always an array index; anything else is always a hashtable key. To force a hashtable key that looks like a number, escape it with a leading backtick – ${string[`0]} looks up the key "0".

Note
Hashtable lookup previously used type:key. That spelling now means a keyed argument (see above), which is by far the more common case, so hashtable lookups moved into the bracket syntax alongside array indexing.

Without a key the container is selected the usual way – the first matching argument of the right shape – so two same-typed containers in one call cannot be told apart. Adding a key does that: ${int:sizes[0]} and ${int:limits[0]} index two different arrays.

Remember that the subscript precedes (width,fmtopts): ${int[2](6)}, not ${int(6)[2]}.

Default values

If there is an error such as not being able to find an argument of the appropriate type, the normal behavior is for strFormat to return false and produce no output. However, if the variable contains a ;default section, instead of failing the entire format operation, the literal text of 'default' (anything after the semicolon) will be inserted in place of the variable instead. A } character may be escaped with `} in this section.

Macro Definition Documentation

◆ strFormat

#define strFormat (   out,
  fmt,
  ... 
)     _strFormat(out, fmt, count_macro_args(__VA_ARGS__), (stvar[]) { __VA_ARGS__ })

bool strFormat(string *out, strref fmt, ...)

Type-safe string formatter with variable substitution and rich formatting options

Copies the format string as-is, replacing ${...} sequences with formatted variables. See detailed documentation sections above for complete syntax and formatting options.

Parameters
outPointer to string to receive the formatted result
fmtFormat string with ${type} variable sequences
...Variable arguments, each wrapped with stvar(type, value)
Returns
true on success, false if a required variable is missing or type mismatch occurs

Example:

string s = 0;
strFormat(&s, _SL("Hello ${string}, you have ${int} messages"),
stvar(string, name), stvar(int32, count));
#define stvar(typen, val)
Definition stvar.h:162

Definition at line 191 of file format.h.