Adds support for value-passing via =.

This commit is contained in:
Felix (xq) Queißner 2020-03-04 22:58:12 +01:00
parent 8a505b6930
commit a5456dbf10
3 changed files with 41 additions and 13 deletions

View File

@ -7,6 +7,7 @@ Simple-to-use argument parser with struct-based config
- Everything after the first `--` is assumed to be a positional argument - 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 - 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` - 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: - Integrated support for primitive types:
- All integer types (signed & unsigned) - All integer types (signed & unsigned)
- Floating point types - Floating point types

View File

@ -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' // double hyphen is considered 'everything from here now is positional'
break; 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; var found = false;
inline for (std.meta.fields(Spec)) |fld| { inline for (std.meta.fields(Spec)) |fld| {
if (std.mem.eql(u8, item[2..], fld.name)) { if (std.mem.eql(u8, pair.name, fld.name)) {
try parseOption(Spec, &result, args, fld.field_type, fld.name); try parseOption(Spec, &result, args, fld.field_type, fld.name, pair.value);
found = true; found = true;
} }
} }
if (!found) { 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; return error.EncounteredUnknownArgument;
} }
} else if (std.mem.startsWith(u8, item, "-")) { } 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; 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; 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: { @field(_result.options, name) = if (requiresArg(field_type)) blk: {
const argval = try (_args.next(&_result.arena.allocator) orelse { const argval = if (value) |val|
try std.io.getStdErr().outStream().stream.print( val
"Missing argument for {}.\n", else
.{name}, try (_args.next(&_result.arena.allocator) orelse {
); try std.io.getStdErr().outStream().stream.print(
return error.MissingArgument; "Missing argument for {}.\n",
}); .{name},
);
return error.MissingArgument;
});
break :blk convertArgumentValue(field_type, argval) catch |err| { break :blk convertArgumentValue(field_type, argval) catch |err| {
try outputParseError(name, err); try outputParseError(name, err);

View File

@ -1,5 +1,5 @@
const std = @import("std"); const std = @import("std");
const argsParser = @import("args"); const argsParser = @import("args.zig");
pub fn main() !void { pub fn main() !void {
var args = std.process.args(); var args = std.process.args();