Zig utility library
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add `flag` module

IamPyu b9d5fa75 4a550bb3

+192
+21
build.zig
··· 22 22 .install_subdir = "docs", 23 23 }); 24 24 25 + const examples: []const struct { 26 + name: []const u8, 27 + path: std.Build.LazyPath, 28 + } = &.{ 29 + .{ .name = "flag", .path = b.path("examples/flag.zig") }, 30 + }; 31 + for (examples) |e| { 32 + const t = b.addExecutable(.{ 33 + .name = e.name, 34 + .root_module = b.createModule( 35 + .{ .target = target, .optimize = optimize, .root_source_file = e.path, .imports = &.{ 36 + .{ 37 + .name = "mitochondria", 38 + .module = mod, 39 + }, 40 + } }, 41 + ), 42 + }); 43 + b.installArtifact(t); 44 + } 45 + 25 46 const docs_step = b.step("docs", "Install generated docs"); 26 47 docs_step.dependOn(&docs.step); 27 48
+26
examples/flag.zig
··· 1 + const std = @import("std"); 2 + const mito = @import("mitochondria"); 3 + 4 + pub fn main() !void { 5 + var gpa = std.heap.GeneralPurposeAllocator(.{}).init; 6 + 7 + const Parser = mito.flag.parser(&.{ 8 + .{ .name = "help", .kind = .boolean, .desc = "Print this help message" }, 9 + .{ .name = "name", .kind = .valued, .desc = "Name to greet" }, 10 + }); 11 + 12 + const args = try std.process.argsAlloc(gpa.allocator()); 13 + defer std.process.argsFree(gpa.allocator(), args); 14 + const out = try Parser.parse(args, .{}); 15 + 16 + if (out.flags.help) { 17 + const stdout = std.fs.File.stdout(); 18 + var buffer: [1024]u8 = undefined; 19 + var writer = stdout.writer(&buffer); 20 + try Parser.print_help(&writer.interface, args[0]); 21 + try writer.interface.flush(); 22 + return; 23 + } 24 + 25 + std.debug.print("Hello {s}!\n", .{out.flags.name orelse "unset"}); 26 + }
+142
src/flag.zig
··· 1 + //! Argument parser 2 + 3 + // taken from river with modifications 4 + 5 + const std = @import("std"); 6 + 7 + pub const FlagKind = enum { valued, boolean }; 8 + 9 + pub const Flag = struct { 10 + name: []const u8, 11 + kind: FlagKind, 12 + desc: ?[]const u8 = null, 13 + }; 14 + 15 + pub const ParseError = error{ 16 + MissingValue, 17 + UnknownFlag, 18 + }; 19 + 20 + pub fn parser(comptime flags: []const Flag) type { 21 + const flag_map = comptime map: { 22 + const N = flags.len; 23 + var flag_map: struct { 24 + names: [N][]const u8, 25 + kinds: [N]FlagKind, 26 + } = .{ 27 + .names = undefined, 28 + .kinds = undefined, 29 + }; 30 + 31 + for (flags, 0..) |flag, i| { 32 + flag_map.names[i] = flag.name; 33 + flag_map.kinds[i] = flag.kind; 34 + } 35 + 36 + break :map flag_map; 37 + }; 38 + 39 + const FlagsType = type: { 40 + var fields: []const std.builtin.Type.StructField = &.{}; 41 + for (flag_map.names, flag_map.kinds) |name, kind| { 42 + const field: std.builtin.Type.StructField = switch (kind) { 43 + .boolean => .{ 44 + .name = name[0..name.len :0], 45 + .type = bool, 46 + .default_value_ptr = &false, 47 + .is_comptime = false, 48 + .alignment = @alignOf(bool), 49 + }, 50 + .valued => .{ 51 + .name = name[0..name.len :0], 52 + .type = ?[]const u8, 53 + .default_value_ptr = &@as(?[]const u8, null), 54 + .is_comptime = false, 55 + .alignment = @alignOf(?[]const u8), 56 + }, 57 + }; 58 + fields = fields ++ [_]std.builtin.Type.StructField{field}; 59 + } 60 + const strukt = @Type(.{ .@"struct" = .{ 61 + .layout = .auto, 62 + .fields = fields, 63 + .decls = &.{}, 64 + .is_tuple = false, 65 + } }); 66 + 67 + break :type strukt; 68 + }; 69 + 70 + return struct { 71 + pub const Flags = FlagsType; 72 + pub const Result = struct { 73 + args: []const []const u8, 74 + flags: Flags, 75 + }; 76 + 77 + pub const Options = struct { 78 + log: bool = true, 79 + }; 80 + 81 + pub fn print_help(writer: *std.Io.Writer, program_name: []const u8) !void { 82 + try writer.print("help for {s}:\n\n", .{program_name}); 83 + 84 + for (flags) |f| { 85 + const desc = f.desc orelse "no description"; 86 + try switch (f.kind) { 87 + .boolean => writer.print("-{s} - {s}\n", .{ f.name, desc }), 88 + .valued => writer.print("-{s} VALUE - {s}\n", .{ f.name, desc }), 89 + }; 90 + } 91 + } 92 + 93 + pub fn parse(args: []const []const u8, options: Options) ParseError!Result { 94 + var out_flags: Flags = .{}; 95 + 96 + var i: usize = 0; 97 + outer: while (i < args.len) : (i += 1) { 98 + const a = args[i]; 99 + if (a[0] != '-') { 100 + continue; 101 + } 102 + 103 + var flag_found = false; 104 + inline for (flag_map.names, 0..) |flag_name, j| { 105 + if (std.mem.eql(u8, "-" ++ flag_name, a)) { 106 + flag_found = true; 107 + switch (flag_map.kinds[j]) { 108 + .boolean => @field(out_flags, flag_name) = !@field(out_flags, flag_name), 109 + .valued => { 110 + i += 1; 111 + if (i == args.len) { 112 + if (options.log) 113 + std.log.err("option '{s}' requires an argument but none was provided!", .{flag_name}); 114 + return error.MissingValue; 115 + } 116 + 117 + @field(out_flags, flag_name) = args[i]; 118 + }, 119 + } 120 + 121 + continue :outer; 122 + } 123 + } 124 + 125 + if (!flag_found) { 126 + if (options.log) 127 + std.log.err("option '{s}' is unknown", .{a}); 128 + return error.UnknownFlag; 129 + } 130 + break; 131 + } 132 + 133 + return Result{ .args = args[i..], .flags = out_flags }; 134 + } 135 + }; 136 + } 137 + 138 + test "a" { 139 + const Parser = parser(&.{.{ .name = "name", .kind = .valued }}); 140 + const out = try Parser.parse(&.{ "-name", "Dennis Ritchie" }, .{}); 141 + _ = out; 142 + }
+3
src/root.zig
··· 16 16 const result = @import("./result.zig"); 17 17 pub const Result = result.Result; 18 18 19 + pub const flag = @import("./flag.zig"); 20 + 19 21 test { 20 22 _ = math; 21 23 _ = mem; ··· 27 29 _ = gamedev; 28 30 29 31 _ = result; 32 + _ = flag; 30 33 }