- Notifications
You must be signed in to change notification settings - Fork0
sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak
License
IOKG04/cfmt
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
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 inlibc
and usesprintf()
and such?
Either because you are on some device where there isn't (yet) alibc
to link against,because you just don'twant to link againstlibc
,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 abuild.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 specifiers incfmt
look something like this:
"%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,minimum width,precision and lastlythespecifier.
All besides the specifier are optional.
The only exception to this is the specifier for writing a%
character, which is%%
.
Specifiers tellcfmt
what kind of type you're formatting and how you want it formatted.
The following specifiers exist:
Integers:
i
: Decimal integerb
: Binary integero
: Octal integerx
: Hexadecimal integer (lowercase)X
: Hexadecimal integer (uppercase)
Floating-point:
f
: Decimal floating-point
Other:
s
: Stringc
: Characterp
: Pointer (hexadecimal lowercase)P
: Pointer (hexadecimal uppercase)
Special:
*cricket noises*
For better compatibility with c's format specifiers,d
andu
work the same asi
.
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 as4
,9
or142
,or a*
, in which case anusize
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 the0
flag.
By default, the formatted contents will be right alligned (space characters on the left),though this behavior can be changed with the-
flag.
What exactlyprecision 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 repeatedprecision 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 tominimum width except with a.
character.
Here however, the precision is putbetween the dynamic minimum width and value to be formatted.
If neither a*
or a number follows the.
, precision is set to0
.
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 padding0
: Pad with0
characters instead of space characters
About
sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak