From a5456dbf10baab707dc76a397c1bb8272a7f8212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Wed, 4 Mar 2020 22:58:12 +0100 Subject: [PATCH] Adds support for value-passing via `=`. --- README.md | 1 + args.zig | 51 +++++++++++++++++++++++++++++++++++++++------------ demo.zig | 2 +- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index cf6a273..5ef31b7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Simple-to-use argument parser with struct-based config - Everything after the first `--` is assumed to be a positional argument - A single `-` is interpreted as a positional argument which can be used as the stdin/stdout file placeholder - Short options with no argument can be combined into a single argument: `-dfe` + - Long options can use either `--option=value` or `--option value` syntax - Integrated support for primitive types: - All integer types (signed & unsigned) - Floating point types diff --git a/args.zig b/args.zig index 475f339..c94e2a9 100644 --- a/args.zig +++ b/args.zig @@ -20,16 +20,33 @@ pub fn parse(comptime Spec: type, args: *std.process.ArgIterator, allocator: *st // double hyphen is considered 'everything from here now is positional' break; } + + const Pair = struct { + name: []const u8, + value: ?[]const u8, + }; + + const pair = if (std.mem.indexOf(u8, item, "=")) |index| + Pair{ + .name = item[2..index], + .value = item[index + 1 ..], + } + else + Pair{ + .name = item[2..], + .value = null, + }; + var found = false; inline for (std.meta.fields(Spec)) |fld| { - if (std.mem.eql(u8, item[2..], fld.name)) { - try parseOption(Spec, &result, args, fld.field_type, fld.name); + if (std.mem.eql(u8, pair.name, fld.name)) { + try parseOption(Spec, &result, args, fld.field_type, fld.name, pair.value); found = true; } } if (!found) { - try std.io.getStdErr().outStream().stream.print("Unknown command line option: {}\n", .{item}); + try std.io.getStdErr().outStream().stream.print("Unknown command line option: {}\n", .{pair.name}); return error.EncounteredUnknownArgument; } } else if (std.mem.startsWith(u8, item, "-")) { @@ -52,7 +69,7 @@ pub fn parse(comptime Spec: type, args: *std.process.ArgIterator, allocator: *st return error.EncounteredUnexpectedArgument; } - try parseOption(Spec, &result, args, real_fld.field_type, real_fld.name); + try parseOption(Spec, &result, args, real_fld.field_type, real_fld.name, null); found = true; } @@ -135,15 +152,25 @@ fn convertArgumentValue(comptime T: type, textInput: []const u8) !T { } } -fn parseOption(comptime Spec: type, _result: *ParseArgsResult(Spec), _args: *std.process.ArgIterator, comptime field_type: type, comptime name: []const u8) !void { +fn parseOption( + comptime Spec: type, + _result: *ParseArgsResult(Spec), + _args: *std.process.ArgIterator, + comptime field_type: type, + comptime name: []const u8, + value: ?[]const u8, +) !void { @field(_result.options, name) = if (requiresArg(field_type)) blk: { - const argval = try (_args.next(&_result.arena.allocator) orelse { - try std.io.getStdErr().outStream().stream.print( - "Missing argument for {}.\n", - .{name}, - ); - return error.MissingArgument; - }); + const argval = if (value) |val| + val + else + try (_args.next(&_result.arena.allocator) orelse { + try std.io.getStdErr().outStream().stream.print( + "Missing argument for {}.\n", + .{name}, + ); + return error.MissingArgument; + }); break :blk convertArgumentValue(field_type, argval) catch |err| { try outputParseError(name, err); diff --git a/demo.zig b/demo.zig index c516b98..5ae852d 100644 --- a/demo.zig +++ b/demo.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const argsParser = @import("args"); +const argsParser = @import("args.zig"); pub fn main() !void { var args = std.process.args();