Skip to content
/ cfmt Public

sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak

License

Notifications You must be signed in to change notification settings

IOKG04/cfmt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

"%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 lastly the specifier.
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.

By default, the formatted contents will be right alligned (space characters on the left), though this behavior can be changed with the - flag.

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 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

About

sprintf() like formatting entirely in zig - sometimes std.fmt is just too weak

Topics

Resources

License

Stars

Watchers

Forks

Languages