A simple flag parser for Zig programs.
- No heap allocation
- Formatted printing
- Simple interface
- Returns argv list without flags
- allowDups: Don't error when duplicate flags are set. Default is false.
- verbose: Print out error messages when errors occur. Default is false.
- prefix: Print out a custom string for verbose messages. Default is null.
- writer: Required when using verbose option. Doesn't really do anything without it. Default is null.
- allowDashAsFirstCharInArgForArg: I admit this needs a better name. It allows argumentative type flags (meaning flags that hold a string/arg) to hold strings that begin with "-". Default is true.
- Fetch with zig and add as module in build.zig
zig fetch --save https://github.com/koeir/flagparse/releases/tag/v0.2.1 // build.zig
const flagparse = b.dependency("flagparse", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "example",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
})
});
exe.root_module.addImport("flagparse", flagparse.module("flagparse"));
b.installArtifact(exe);- Declare a list of flags with the built-in structs
const initflags: flagparse.Type.Flags = .{
.list = &[_] flagparse.Type.Flag
{
.{
.name = "recursive",
.long = "recursive",
.short = 'r',
.value = .{ .Switch = false },
.desc = "Recurse into directories",
},
.{
.name = "force",
.long = "force",
.short = 'f',
.value = .{ .Switch = false },
.desc = "Skip confirmation prompts",
},
.{
.name = "file",
.long = "path",
.short = 'p',
.value = .{ .Argumentative = .{0} ** 1024 },
.desc = "Path to file",
},
},
};
- Initialize posix argument iterator and buffers
const std = @import("std");
const flagparse = @import("flagparse");
pub fn main(init: std.process.Init) !void {
...
const io = init.io;
const min = init.minimal;
var flagarr: [initflags.list.len]flagparse.Type.Flag = undefined;
var argbuf: [20][:0]const u8 = undefined;
var errorbuf: [256]u8 = undefined;
...
- Parse
const std = @import("std");
const flagparse = @import("flagparse");
pub fn main() !void {
...
var args: std.process.ArgIteratorPosix = .init();
// buffers; must remain in scope for flags and argv
var flagarr: [initflags.list.len]flagparse.Type.Flag = undefined;
var argbuf: [20][:0]const u8 = undefined;
var errorbuf: [20]u8 = undefined;
const result = flagparse.parse(&min.args, argbuf[0..],
initflags, &flagarr, &errorbuf,
.{}) catch {
// handle err
};
// retrieve values from tuple
const flags = result.flags;
const argv = result.argv;
...
- Use
...
const recursive: bool = try flags.get_value("recursive", flagparse.Type.Switch);
const file = try flags.get_value("file", flagparse.Type.Argumentative);
...pub const FlagErrs = error {
NoArgs, // I don't think this error would be triggered under normal circumstances.
// It is only returned when skipping over argv[0] returns false.
NoSuchFlag, // unrecognized flag in arg list
FlagNotSwitch, // non-switch/non-bool Flag treated as a switch/bool
FlagNotArg, // non-argumentative flag treated as an argumentative
DuplicateFlag, // flag appears twice in arg list; can be ignored with config
ArgNoArg, // no argument given to argumentative flag
OutOfMemory, // something's size exceeds its buffers len
NoWriter, // no writer given when verbose is true
}