I wanted to check if there is anything after the first arg, to avoid doing all initing after, and continued parsing of the args. My code currently looks like this:
pub fn main(init: std.process.Init.Minimal) !void {
// Mem allocator init
var arena = std.heap.ArenaAllocator.init(std.heap.smp_allocator);
defer arena.deinit();
const alloc = arena.allocator();
// stdin
var args = try init.args.iterateAllocator(alloc);
defer args.deinit();
// Handle in main, avoids unnecessary inits
const name = args.next().?;
// Handle empty args case early
if (args.inner.remaining.len == 0) {
std.log.err("Usage: {s} [options] <src...> <dst>", .{name});
return error.InvalidArgs;
}
// Io init
var io_init = std.Io.Threaded.init(
alloc,
.{ .environ = init.environ },
);
const io = io_init.io();
// sdout
var stdout_init = std.Io.File.stdout().writer(io, &.{});
const stdout = &stdout_init.interface;
var cfg = try Config.parse(alloc, &args, stdout, name);
defer cfg.deinit(alloc);
...
// config.zig:
const std = @import("std");
const Allocator = std.mem.Allocator;
const Iterator = std.process.Args.Iterator;
const Sort = @import("root.zig").Sort;
const help_msg =
\\Usage: {s} [options] <src...> <dest>
\\
\\Options:
\\ -a, --acl Copy ACLs/xattrs
\\ -b, --binary Use binary, lexicographic sorting
\\ -p, --path Copy path passed as argument (no flatten)
\\ -v, --verbose Sets logging level to debug
\\ -h, --help Show this help message
\\
;
pub const Config = struct {
const Self = @This();
acls: bool = false,
flatten: bool = true,
mkdir: bool = false,
falloc_switch: bool = true,
sort: Sort = .natural,
log_level: std.log.Level = std.log.default_level,
src_list: std.ArrayList([]const u8) = .empty,
dest: []const u8 = "",
pub fn parse(alloc: Allocator, args: *Iterator, writer: *std.Io.Writer, name: []const u8) !Self {
var self = Self{};
// Only on error
errdefer self.deinit(alloc);
while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
try writer.print(help_msg, .{name});
try writer.flush();
self.deinit(alloc);
std.process.exit(0);
} else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--acl")) {
self.acls = true;
} else if (std.mem.eql(u8, arg, "-v") or std.mem.eql(u8, arg, "--verbose")) {
self.log_level = .debug;
} else if (std.mem.eql(u8, arg, "-p") or std.mem.eql(u8, arg, "--path")) {
self.flatten = false;
} else if (std.mem.eql(u8, arg, "-b") or std.mem.eql(u8, arg, "--binary")) {
self.sort = .binary;
} else {
try self.src_list.append(alloc, arg);
}
}
if (self.src_list.items.len < 2) {
std.log.err("Usage: {s} [options] <src...> <dst>", .{name});
return error.InvalidArgs;
}
self.dest = self.src_list.pop().?;
return self;
}
pub fn deinit(self: *Self, alloc: Allocator) void {
self.src_list.deinit(alloc);
self.* = undefined;
}
};
I had in mind “Exit early as possible if arg count is not valid”. I’ll try doing something with toSlice()