https://github.com/iokg04/cfmt
sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak
https://github.com/iokg04/cfmt
formatting sprintf-style zig
Last synced: 11 months ago
JSON representation
sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak
- Host: GitHub
- URL: https://github.com/iokg04/cfmt
- Owner: IOKG04
- License: 0bsd
- Created: 2025-01-26T18:53:16.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-27T09:20:36.000Z (over 1 year ago)
- Last Synced: 2025-03-24T04:21:27.076Z (over 1 year ago)
- Topics: formatting, sprintf-style, zig
- Language: Zig
- Homepage:
- Size: 14.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# cfmt
Zig's `@import("std").fmt` may be good, but in some cases you just need a little bit more functionality.
Now why not just link in `libc` and use `sprintf()` and such?
Either because you are on some device where there isn't (yet) a `libc` to link against,
because you just don't *want* to link against `libc`,
or lastly because you're using some types c doesn't understand (`u19`, `f128`, etc.) and want a native zig solution.
That being said, this is not a drop in replacement, the format specifiers are a little different from c's.
I did design them to be as close as possible though, requiring little rethinking if you're already used to c.
A lot of what's written here isn't implemented yet, I am working on it though.
Also any ideas are appreciated, making this more feature rich would be nice :3
Also also, I will add a `build.zig.zon` once this can be reasonably used as a library.
Might even make it so you can compile it to a static/dynamic library to use with other languages.
## Format specifier
Format specifiers in `cfmt` look something like this:
```zig
"%s" // a string
"%.4f" // a floating-point value rounded to 4 digits after the period
"%-4.8i" // a left alligned integer of at least 4 and at most 8 digits
```
They can be split into five parts in this exact order:
A `%` character,
[flags](#flags),
[minimum width](#minimum-width),
[precision](#precision) and lastly
the [specifier](#specifiers).
All besides the specifier are optional.
The only exception to this is the specifier for writing a `%` character, which is `%%`.
### Specifiers
Specifiers tell `cfmt` what kind of type you're formatting and how you want it formatted.
The following specifiers exist:
**Integers:**
- `i`: Decimal integer
- `b`: Binary integer
- `o`: Octal integer
- `x`: Hexadecimal integer (lowercase)
- `X`: Hexadecimal integer (uppercase)
**Floating-point:**
- `f`: Decimal floating-point
**Other:**
- `s`: String
- `c`: Character
- `p`: Pointer (hexadecimal lowercase)
- `P`: Pointer (hexadecimal uppercase)
**Special:**
\*cricket noises\*
For better compatibility with c's format specifiers, `d` and `u` work the same as `i`.
### Minimum width
If a minimum width is specified and the formatted string isn't that long, the string will be padded with space characters.
The minimum width can either be a decimal number, such as `4`, `9` or `142`,
or a `*`, in which case an `usize` is read from the arguments and its value is used as the minimum width.
If a `*` is used, the dynamic minimum width must be given before the value to be formatted (and the dynamic precision if used).
Please note that the decimal number may not have a leading zero as that could interfere with the [`0` flag](#flags).
By default, the formatted contents will be right alligned (space characters on the left),
though this behavior can be changed with the [`-` flag](#flags).
### Precision
What exactly *precision* means depends on the type to be formatted:
If it's a floating point value, precision is the amount of digits after the decimal separator.
If it's a string, precision defines the maximum amount of characters written.
When truncation happens, the last characters are cut off.
If it's a character, it will be repeated *precision* times.
Does it make sense to call that precision? No.
Could it still be a useful functionality? Yes.
For any other type, precision doesn't do anything.
To set the precision, a `.` followed by a number or a `*` is used, similar to [minimum width](#minimum-width) except with a `.` character.
Here however, the precision is put *between* the dynamic minimum width and value to be formatted.
If neither a `*` or a number follows the `.`, precision is set to `0`.
### Flags
Flags change some parts of formatting.
The following flags exist:
- `-`: Allign to the left instead of right (space characters on the right)
- `+`: Always write `+` and `-` sign for numeric types
- ` `: (space) Write a space character at start of positive numeric values
- `<`: Write sign before any padding
- `0`: Pad with `0` characters instead of space characters