Zarg
The minimalistic, Zig command line argument parser. Following (or making it easier to follow) the CLIG guidelines

28 Replies
Here is the banner that will be going up on the repo

Here are the xcf files for these
Both of these can be cleaned up and @earth's penguin mentioned using something like inkscape to convert the logo into a vector. Which would clean up all the finer details. I also think the text could be cleaned up, maybe with a different font, or rounding the edges.
I have messed with this project quite a lot, about 8 different tests and such. I think this will be the last time I'll have to keep doing continued rewriting. I will be planning out things very extensively in this channel. If not here, then likely on a notion page (which I would send here for your viewing).
The goal is to follow (or making it easier to follow) the CLIG guidelines. I won't bend over back too far to make every single thing adhere. I plan on making a list of things that will be supported and (for the time being) what wont.
Command Line Interface Guidelines
An open-source guide to help you write better command-line programs, taking traditional UNIX principles and updating them for the modern day.
I plan on using this library for all argument parsing done with #Hexdump
This list is going to be quite verbose, listing out every single feature mentioned in CLIG. If you want more detail on a feature refer back to CLIG. I have marked some things with (optional), meaning they can be done but aren't required to be done. Anything marked as optional likely means it's something in the API that can be set, not something Zarg is expected to have or do.
This list is just stuff from CLIG, Zarg will have other features too that aren't mentioned in this message!
SUPPORTED
HELP
- Return zero exit code on success, non-zero on failure
- Send output to stdout.
- Send messaging to stderr.
- Display help text when passed no options.
- Display a concise help text by default.
- A description of what your program does. (optional)
- One or two example invocations. (optional)
- Show full help when -h and --help is passed.
- Provide a support path for feedback and issues. (optional)
- In help text, link to the web version of the documentation. (optional)
- Use formatting in your help text.
- If the user did something wrong and you can guess what they meant, suggest it.
- If your command is expecting to have something piped to it and stdin is an interactive terminal, display help immediately and quit.
DOCUMENTATION
- Consider auto-generating man pages.
This isn't something in CLIG, just rather my own idea. I'm on the fence about it just because of simplicity.
OUTPUT
This entire section for now will be skipped. Output is done the the developer, not Zarg. Do follow CLIG's guidelines for output though...
ERRORS
- Catch errors and rewrite them for humans.
- If there is an unexpected or unexplainable error, provide debug and traceback information, and instructions on how to submit a bug.
- Make it effortless to submit bug reports.
All of these are done for Zarg itself, but this is expected to be done by the developer themselves.
FLAGS AND ARGUMENTS
- If a flag can accept an optional value, allow a special word like “none.”
- If possible, make arguments, flags and subcommands order-independent.
Robustness
- Responsive is more important than fast.
- Do stuff in parallel where you can, but be thoughtful about it.
UNSUPPORTED
- Display the most common flags and commands at the start of the help text.
this should just be done by the developer, not zarg as to keep it minimal
What language are you going to write this in? I assume it's Zig judging by the name
That's correct
Yes, I will be using Zig
Unlike the SUPPORTED and UNSUPPORTED sections, here is a hard list of features Zarg plans to or has implemented. This list differs from the prior one mentioned as we're no longer in the realm of philosophy (which is up to different peoples interpretation) but now to cold hard facts of features.
This list will be pinned and updated as time goes on, (and at some point) tagging features with emojis for their status:
✅ : implemented & tested
☑️ : implemented but haven't been tested
⚠️ : implemented but failed testing
🧪 : working on implementation
❌ : not implemented
PLANNED FEATURES
not a complete list due to my laziness
- ❌ | Flags
- 🧪 | Short flags
-s
- 🧪 | Long flags --long
- ❌ | Chaining flags like -abc
(where a
and b
do not take values)
- ❌ | Passing values using spaces or =
(-a 100
, -a=100
)
You could also infer this from Zarg's logo and or banner, where the Ziglang logo is used
Created a Github repo, nothing on it yet. Just a novelty for right nowFor speed reasons I'll be dropping some features
Namely:
1. auto-generating help menu
2. Tab completion of flags (maybe?)
3. Validating flags at comptime or runtime (maybe?)
4. Abstracting the underlying cast, meaning the developer gets positions and flag values as
[]const u8
Why?
1. Although this could all be done at comptime, it would require a very verbose "magic" api. It wouldn't keep much of it's "low levelness"
2. Same reason as #1
3. Requires allocating space for all args, or searching for them at runtime
4. Makes Zarg seem more like magic, not a low level argument parser
TL;DR
Although this message was not long... like at all. Here are my final words and goal of Zarg as of now. Zarg shouldn't look like magic, following Zigs lead, nothing is magic, everything being written out. Explicitly, making the control flow of the code much more obvious.
Example API Going Forward
Here is the pseudo code idea for the API I strive for:
The Old API
Here is the old API just for fun, this was my original concept and testing API:
In my opinion the new API is just better. It also solves many issues and allows Zarg to parse arguments in just a few microseconds
While the old API takes around 5-7 milliseconds, and is just a bit messier in my opinion. Although not shown in the example it could also have a autogenerating help menu, along with flag autocomplete (thanks to having to explicitly define the flags taken)
I would like to hear what you think about this @earth's penguin, as you're the one who is going to be using it.
Zarg will be using a state machine to parse the command line arguments@earth's bird how would I get certain arguments later in the code. is it using the switch statement with just one case?
I'd say you'd just setup a switch like so
This would be a somewhat downside to this, as unlike the old API not everything is provided under one struct and accessible at any point.
is it using the switch statement with just one case?I'm pretty sure you meant something like this https://discord.com/channels/728958932210679869/1199401594630963221/1200888484949397684. If that was the case, then yeah Be sure to let me know how you feel about it, after all Zarg is really just designed for Hexdump Seeing as you wanted Zarg to be fast fast I've been messing around with the API to get it to be fast. This was my solution but I'm open to rethinking it Working just on Linux support for the time being Why is it not just cross platform already you say? Well Windows needs allocations, Linux doesn't. Allocating uses a (likely many) syscall, syscalls are slow. Hopefully you see my dilemma, so I must break Zarg into a Windows and then Unix section. Thankfully all that really changes is the
init
function, but now I must manage an allocator safely.
Here is the init function currently
As you can see I do a quick switch on the
os.tag
This makes Zarg very fast on Linux, but slower on Windows thanks to the pesky unavoidable allocations
I'm trying to think of how I could write my own allocator that would be smarter about allocating memory for command line arguments
Hence this is the reason I am "Working just on Linux support for the time being"
the other option is just to allocate on both platforms, but no, no. Not happening
I have created the tokenizer, which was the most annnoying task, jeez.
Here is the test I ran if anyone would like to know
I'll run a quick test on speed here
I'm a bit concerned as I want to majorly optimise every little thing, why? Just because
If the tokenizing takes over a milisecond I will be sad@earth's bird how long does it take

Too long
:(
ouch
Way more then I want
Yeah well I ditched the system I told you last night
I keep changing everything because I find issues with it
Tokenizing like this fixes a lot, but as it's no longer abstract it still takes a hot minute. This is the longest task Zarg will have to do though.
Throwing my code onto my Linux machine to do some profiling
How would an auto generated help menu require a "magic API"
because auto generating the help menu requires it to now what options there are
if the options are handled by a switch statement as done without the magic api, the program doesnt know what arguments there are
thats a shitty way to explain it tho, @earth's bird can probably explain better
Magic just meaning you don't understand what it's doing, it seems like magic because you have no clue what is actually happening under the hood. Maybe for a high level language this isn't an issue, but for Zig it is. Regardless as @earth's penguin mentioned it would require me to know what arguments and flags the program wants to accept and their descriptions before hand
There is now tons of overhead that was never required before
Currently Zarg doesn't care what you want or what you don't want. What flags take values and what don't. It tokenizes the command line arguments and then gives a low level api for working with the tokens
That's what this is
Example API Going Forward Here is the pseudo code idea for the API I strive for:Wow, this is like my millionth time on this project 😅 However with some help from the Zig community I have gotten from my ideas to actual code Thanks to the help of one of my Zig heroes, I was pointed in a much better direction. Taking my hacky ideas and laying them out idiomatically has undoubtedly been a blessing. I'm here less to tell you about the progress of Zarg as, honestly, I'm just trying to code without losing motivation... however I am here to actually show you some cool "ziggy-ness" For those unaware, Zig has a cool feature called
comptime
. Compile-time means that:
- At the call site, the value must be known at compile-time, or it is a compile error.
- In the function definition, the value is known at compile-time.
This allows the compiler to take lines of code, or even entire functions, and do the work then, so it doesn't need to be when running your code.
This allows for crazy speedups in some places where you know the input and what the output should be. In my case, it's being used to make a very flexible API, so let me show you that:
Now this code is something to ignore
Although this is missing some required code to run it has all the information for me to show what comptime can do for us
The compiled executable is actually running code akin to:This is quite cool as it allows a developer to express what kinds of inputs they want their app to take intuitively without sacrificing performance. It's the opposite; doing this is relatively fast! Get more while doing less, that's something I can get behind.
Leveraging this compile-time duck typing allows for some crazy cool things. As a final message from me, try Zig.If that's what you're aiming to do it seems pretty straightforward
So basically it's precomputing everything it can to increase performance
pretty much, yes
Basic parsing is implemented. I'm working towards following CLIG guidelines as I have before. Along with my own strict rules on what will be parsed. The only reason these rules are enforced is to keep things simple. For example, duplicate flags are not allowed, period. There is no use case where a duplicate flag is practical.
Simple things like these conform to CLIG, along with my ideas of a command line parser.
As to what is currently supported, I'll quote a section from CLIG:
- Arguments, or args, are positional parameters to a command. For example, the file paths you provide toBoth of the featured outlined here are supported Due to this section, I'm hesitant to add support forcp
are args. The order of args is often important:cp foo bar
means something different fromcp bar foo
. - Flags are named parameters, denoted with either a hyphen and a single-letter name (-r
) or a double hyphen and a multiple-letter name (--recursive
). They may or may not also include a user-specified value (--file foo.txt
, or--file=foo.txt
). The order of flags, generally speaking, does not affect program semantics.
--file = foo.txt
As for the error, this would return? Who knows...make sure you actually implement the order not mattering because I know some libraries where it does
Arguments matter; flags won't. Well, actually, it's really due to the programmer
All the flags are parsed but you choose how and when to handle them