summaryrefslogtreecommitdiff
path: root/src/args.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/args.zig')
-rw-r--r--src/args.zig90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/args.zig b/src/args.zig
new file mode 100644
index 0000000..304596c
--- /dev/null
+++ b/src/args.zig
@@ -0,0 +1,90 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const debug = std.debug;
5const heap = std.heap;
6const mem = std.mem;
7const os = std.os;
8
9/// A interface for iterating over command line arguments
10pub fn Iterator(comptime E: type) type {
11 return struct {
12 const Self = @This();
13 const Error = E;
14
15 nextFn: fn (iter: *Self) Error!?[]const u8,
16
17 pub fn next(iter: *Self) Error!?[]const u8 {
18 return iter.nextFn(iter);
19 }
20 };
21}
22
23/// An ::ArgIterator, which iterates over a slice of arguments.
24/// This implementation does not allocate.
25pub const SliceIterator = struct {
26 const Error = error{};
27
28 args: []const []const u8,
29 index: usize,
30 iter: Iterator(Error),
31
32 pub fn init(args: []const []const u8) SliceIterator {
33 return SliceIterator{
34 .args = args,
35 .index = 0,
36 .iter = Iterator(Error){ .nextFn = nextFn },
37 };
38 }
39
40 fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 {
41 const self = @fieldParentPtr(SliceIterator, "iter", iter);
42 if (self.args.len <= self.index)
43 return null;
44
45 defer self.index += 1;
46 return self.args[self.index];
47 }
48};
49
50test "clap.args.SliceIterator" {
51 const args = [][]const u8{ "A", "BB", "CCC" };
52 var slice_iter = SliceIterator.init(args);
53 const iter = &slice_iter.iter;
54
55 for (args) |a| {
56 const b = try iter.next();
57 debug.assert(mem.eql(u8, a, b.?));
58 }
59}
60
61/// An ::ArgIterator, which wraps the ArgIterator in ::std.
62/// On windows, this iterator allocates.
63pub const OsIterator = struct {
64 const Error = os.ArgIterator.NextError;
65
66 arena: heap.ArenaAllocator,
67 args: os.ArgIterator,
68 iter: Iterator(Error),
69
70 pub fn init(allocator: *mem.Allocator) OsIterator {
71 return OsIterator{
72 .arena = heap.ArenaAllocator.init(allocator),
73 .args = os.args(),
74 .iter = Iterator(Error){ .nextFn = nextFn },
75 };
76 }
77
78 pub fn deinit(iter: *OsIterator) void {
79 iter.arena.deinit();
80 }
81
82 fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 {
83 const self = @fieldParentPtr(OsIterator, "iter", iter);
84 if (builtin.os == builtin.Os.windows) {
85 return try self.args.next(&self.arena.allocator) orelse return null;
86 } else {
87 return self.args.nextPosix();
88 }
89 }
90};