# sprintf.h ## Overview
The Sprintf API provides a replacement for the system `sprintf()` function based on Sean Barret's [stb_sprintf.h](https://github.com/nothings/stb/blob/master/stb_sprintf.h) and extended with support for printing custom types. The stb implementation is generally faster and smaller than libc implementations and comes with the following additions: * 64-bit integers can be printed with either `%I64d` or `%lld` (no need to use the `PRId64` macro). * `%'d` prints integers with commas for thousand separators. * For integers and floats, use `$` to print with a kilo, mega, giga or tera suffix. * Use `$$` for kibibyte, mebibyte, etc. * Use `$$$` for kibibyte but with JEDEC suffixes rather than SI ones. * Use `_$` to skip the space between the number and the suffix. * `%b` prints integers in binary format. * `tm_snprintf()` and `tm_vsnprintf()` always produce zero-terminated strings. In addition, The Machinery implementation has the following additions (which are not in the standard stb implementation): * `tm_snprintf()` and `tm_vsnprintf()` use UTF-8 safe truncation, i.e. the truncated string is guaranteed to still be valid UTF-8. * Custom types are printed with a format specifier of the form `%p{type:args}`. `args` are arguments to the printer and can be omitted: `%p{type}`. The type name `type` in the custom specifier is used to to look up a `tm_sprintf_printer` callback function, registered with `add_printer()`. This callback function is called to print the custom type into a temporary buffer which is then composed into the main output buffer as if it was a string argument (`%s`). Note that this means that the regular formatting flags that you can use with `%s` also work for custom structs, i.e. `%-20p{tm_vec3_t}`. Custom types should always be passed as pointers to `print()`, passing actual values will yield an error. | Fmt | Value | Result | | ----------------------- | ----------------------------------- | ------------------------------------------ | | `%I64d` | `(uint64_t)100` | `100` | | `%'d` | `12345` | `12,345` | | `%$d` | `12345` | `12.3 k` | | `%$d` | `1000` | `1.0 k` | | `%$.2d` | `2536000` | `2.53 M` | | `%$$d` | `2536000` | `2.42 Mi` | | `%$$$d` | `2536000` | `2.42 M` | | `%_$d` | `2536000` | `2.53M` | | `%b` | `36` | `100100` | | `%p{bool}` | `&(bool){true}` | `true` | | `%p{tm_vec3_t}` | `&(tm_vec3_t){ 1, 2, 3 }` | `{ 1, 2, 3 }` | | `%p{tm_vec3_t}` | `0` | `(null)` | | `%p{unknown_type}` | `&(tm_vec3_t){ 1, 2, 3 }` | `%p{unknown_type}` | | `%p{unknown_type:args}` | `&(tm_vec3_t){ 1, 2, 3 }` | `%p{unknown_type:args}` | | `%p{tm_vec3_t` | `&(tm_vec3_t){ 1, 2, 3 }` | `(error)` | | `%p{tm_rect_t}` | `&(tm_rect_t){ 10, 20, 100, 200 })` | `{ 10, 20, 100, 200 }` | | `%p{tm_color_srgb_t}` | `&TM_RGB(0xff7f00)` | `{ .r = 255, .g = 127, .b = 0, .a = 255 }` |
## Index
`tm_sprintf_printer`

`struct tm_sprintf_api`
`print_unsafe()`
`print()`
`vprint_unsafe()`
`vprint()`
`add_printer()`

`tm_sprintf_api_version`
`tm_sprintf()`
`tm_snprintf()`
`tm_vsprintf()`
`tm_vsnprintf()`
## API
### `tm_sprintf_printer`
~~~c typedef int tm_sprintf_printer(char *buf, int count, tm_str_t type, tm_str_t args, const void *data); ~~~ Callback used for custom printing of a struct that has been registered with `add_printer()`. `buf` is the temporary buffer to print to and `count` it's size. The callback function should behave as `print()` (typically, the implementation will just call `print()`). `type` is the type name from the format specifier. I.e. for `%p{tm_vec3_t}`, `type` is `"tm_vec3_t"`. `args` the argument from the format specifier. I.e., for `%p{my_type_t:long}`, `args` will be `"long"`. If there is no argument string, `args` is `{0}`. `args` can be used to customize the printing. It is up to each printer to decide how `args` should be interpreted. `data` is a pointer to the struct that should be printed. !!! TIP: Tip If you are unsure how to format the output of a certain type, a good first choice is to use the format you would use to write a literal of the same type in the code, but without the type specifier. Use the same spacing as you get from auto-formatting the literal in the code. For example, a `tm_vec3_t` literal would be written as `(tm_vec3_t){ 1, 2, 3 }`, so a good default for the string representation is `{ 1, 2, 3 }`.
### `struct tm_sprintf_api`
#### `print_unsafe()` ~~~c int (*print_unsafe)(char *buf, const char *fmt, ...); ~~~ Replacement for C `sprintf()`. #### `print()` ~~~c int (*print)(char *buf, int count, const char *fmt, ...); ~~~ Replacement for C `snprintf()`. `print()` truncates strings in a UTF-8 safe way -- i.e. it doesn't leave any split codepoints at the end of the string. If there are any split codepoints at the end, they will be replaced by `\0`. #### `vprint_unsafe()` ~~~c int (*vprint_unsafe)(char *buf, const char *fmt, va_list va); ~~~ Replacement for C `vsprintf()`. #### `vprint()` ~~~c int (*vprint)(char *buf, int count, const char *fmt, va_list va); ~~~ Replacement for C `vsnprintf()`. `vprint()` truncates strings in a UTF-8 safe way -- i.e. it doesn't leave any split codepoints at the end of the string. If there are any split codepoints at the end, they will be replaced by `\0`. #### `add_printer()` ~~~c void (*add_printer)(const char *name, tm_sprintf_printer *printer); ~~~ Adds a custom printer callback function for the type `name`.
### `tm_sprintf_api_version`
~~~c #define tm_sprintf_api_version ~~~
### `tm_sprintf()`
~~~c #define tm_sprintf(buf, fmt, ...) ~~~ Convenience macro for `tm_sprintf_api->print_unsafe()`.
### `tm_snprintf()`
~~~c #define tm_snprintf(buf, count, fmt, ...) ~~~ Convenience macro for `tm_sprintf_api->print()`.
### `tm_vsprintf()`
~~~c #define tm_vsprintf(buf, fmt, va) ~~~ Convenience macro for `tm_sprintf_api->vprint()`.
### `tm_vsnprintf()`
~~~c #define tm_vsnprintf(buf, count, fmt, va) ~~~ Convenience macro for `tm_sprintf_api->vprint()`.