1
3
Fork
You've already forked argz
0
Command Line Parser for Zig
  • Zig 100%
2026年02月27日 11:12:20 +01:00
examples Enum example 2026年02月27日 10:48:52 +01:00
src switch *Arena parameters to Allocator 2026年02月27日 10:12:14 +01:00
.gitignore Initial commit 2026年02月15日 21:05:23 +01:00
build.zig Enum example 2026年02月27日 10:48:52 +01:00
build.zig.zon Big refactor 2026年02月26日 13:28:56 +01:00
LICENSE Initial commit 2026年02月15日 21:05:23 +01:00
README.md Update README.md 2026年02月27日 10:48:30 +01:00

argz

Command Line Parser for Zig 0.16.

How it works

It parses a given help text to produce a struct type with the appropriate fields. This struct is then populated during the parsing of init.minimal.args. Command line arguments that weren't used are copied as-is in the _argv field.

The first character of each line indicates its meaning:

  • a . signify an flag, positional argument, or sub-command
  • a ! signify a required flag or positional argument
  • any other character is ignored.

The automatic help text printer will discard the first character of every line.

The following flag syntax is recognized by the parser:

  • -a, --alice: simple flags
  • -b=42, --bob=42, -b 42, --bob 42: flags with parameter.
  • -abcde, multiple short form flags. Note that if -c takes a parameter then -abcde is parsed as -a -b -c=de.

An empty argument, or an argument equal to -, or any argument that doesn't start with - is treated as a sub-command if one matches or a positional argument.

In addition, a -- appearing anywhere will force subsequent arguments to be parsed as positional arguments.

Getting started

Make sure you have zig 0.16. Fetch argz and store it in your project:

zig fetch --save https://codeberg.org/chocapix/argz/archive/0.16.x.tar.gz

Then make argz available as a module for your executable, in build.zig, do:

 const exe = b.addExecutable(...);
 const argz = b.dependency("argz", .{});
 exe.root_module.addImport("argz", argz.module("argz"));

Examples

The simplest way to use argz is via the parse function. It takes an std.process.Init argument and parses the command line arguments. In case of error, it will print a diagnostic on stderr and returns an error. If the help text defines a --help flag and it is present, it will print the help text to stdout and call exit(0).

Simple Flags

const std = @import("std");
pub fn main(init: std.process.Init) !void {
 const argv = try @import("argz").parse(
 \\ usage simple [options...]
 \\ 
 \\ options:
 \\. -h, --help print this help and exit
 \\. -f simple short flag
 \\. --long simple long flag
 , .{}, init);
 std.debug.print("{any}\n", .{argv});
}

Here argv will have the following fields:

  • help: usize: the number of times the -h or --help flag is present.
  • f: usize: the number of times the -f flag is present.
  • long: usize: the number of times the --long flag is present.
  • _argv: []const [:0]const u8: the unused command line arguments.

Flags with parameters, required flags, positional arguments

A ! denotes a required flag or positional argument. =<type> after a flag or positinal indicate how parameters will be parsed. =<type> is required for positional arguments.

Builtin argz types and their zig counter parts are as follows.

argz <type> zig type
<str> [:0]const u8
<int> isize
<uint> usize
<float> f64
<iXX> iXX
<uXX> uXX
<fXX> fXX
const std = @import("std");
pub fn main(init: std.process.Init) !void {
 const argv = try @import("argz").parse(
 \\ usage simple [options...]
 \\ 
 \\ options:
 \\. -h, --help print this help and exit
 \\! --foo=<int> an integer required flag
 \\. -g, --gaa=<float> an float optional flag
 \\. bar=<str> an string optional positional argument
 , .{}, init);
 std.debug.print("{any}\n", .{argv});
}

Here argv will have the following fields:

  • help: usize: the number of times the -h or --help flag is present
  • foo: isize: the number passed to the --foo=XXX flag
  • gaa: ?f64: the number passed to the --gaa=XXX flag, or null if --gaa is not present
  • bar: ?[:0]const u8: the first positional argument if any, null otherwise
  • _argv: []const [:0]const u8: the unused command line arguments

Note that a optional positional argument cannot appear before a required one. The help text printer removes the name= part of positional argument definitions.

Sub-commands

A . line with a name and no =<type> defines a sub-command. They define an optional enum _command field that one can switch on. Then, the _argv field can be passed to the parseArgv function. Sub-command definitions cannot start with a !.

const std = @import("std");
pub fn main(init: std.process.Init) !void {
 const argv = try @import("argz").parse(
 \\ usage subcmd [options...] command [command options...]
 \\ 
 \\ options:
 \\. -h, --help print this help and exit
 \\ 
 \\ commands:
 \\. zero zeroth commmand
 \\. one oneth commmand
 , .{}, init);
 return if (argv._command) |cmd| switch (cmd) {
 .zero => zeroCmd(init, argv._argv),
 .one => std.debug.print("cmd one not implemented\n", .{}),
 } else error.MissingCommand;
}
fn zeroCmd(init: std.process.Init, argv: []const [:0]const u8) !void {
 const args = try @import("argz").parseArgv(
 \\ usage subcmd zero [options...] posi
 \\. -f, --foo=<uint> foo
 , .{}, init.arena.allocator(), init.io, argv);
 std.debug.print("{any}\n", .{args});
}

Custom types

The second argument to parse() is expected to be a struct literal that defines parsers for custom types:

pub fn main(init: std.process.Init) !void {
 const argv = try @import("argz").parse(
 \\! foo=<footype>
 , .{
 .footype = parseFoo,
 }, init);
}
fn parseFoo(str: [:0]const u8) !Foo { ... }

The type Foo of argv.foo is extracted from the result type of parseFoo. Custom parsers must be callable with a [:0]const u8 and return a E!T for some error union E and some type T.

For convenience, argz provides an enum parser, parseEnum:

const std = @import("std");
pub fn main(init: std.process.Init) !void {
 const argz = @import("argz");
 const argv = try argz.parse(
 \\ usage customtypes [options...]
 \\. -h, --help print this help and exit
 \\. --maybe=<yesno> sets maybe to yes or no
 , .{
 .yesno = argz.parseEnum(YesNo),
 }, init);
 std.debug.print("{any}\n", .{argv});
}
const YesNo = enum { yes, no };

Advanced API

argz needs an arena and an io, parse() gets them from the std.process.Init parameter. If your program defines its own io and allocator, use the parseMinimal() function.

If you want full control, define an Argz variable and call parse() on it.