From 7a768f09217a278103fc4cf7999a68691c577e0b Mon Sep 17 00:00:00 2001 From: lookbusy1344 <3680611+lookbusy1344@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:42:31 +0100 Subject: [PATCH] Updating PicoArgs to v1.6.0 --- PicoArgs.cs | 80 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/PicoArgs.cs b/PicoArgs.cs index 2cff843..a60955b 100644 --- a/PicoArgs.cs +++ b/PicoArgs.cs @@ -3,18 +3,19 @@ namespace PicoArgs_dotnet; /* PICOARGS_DOTNET - a tiny command line argument parser for .NET https://github.com/lookbusy1344/PicoArgs-dotnet - Version 1.5.1 - 09 Jul 2024 + Version 1.6.0 - 17 Jul 2024 Example usage: var pico = new PicoArgs(args); bool verbose = pico.Contains("-v", "--verbose"); // true if any of these switches are present - string? pattern = pico.GetParamOpt("-t", "--pattern") ?? "*.txt"; // optional parameter - string requiredpath = pico.GetParam("-p", "--path"); // mandatory parameter, throws if not present + string? patternOpt = pico.GetParamOpt("-t", "--pattern"); // optional parameter + string pattern = pico.GetParamOpt("-t", "--pattern") ?? "*.txt"; // optional parameter with default + string requirePath = pico.GetParam("-p", "--path"); // mandatory parameter, throws if not present string[] files = pico.GetMultipleParams("-f", "--file"); // multiple parameters returned in string[] string command = pico.GetCommand(); // first parameter, throws if not present - string? commandopt = pico.GetCommandOpt(); // first parameter, null if not present + string? commandOpt = pico.GetCommandOpt(); // first parameter, null if not present pico.Finished(); // We are done. Throw if there are any unused parameters @@ -39,10 +40,8 @@ public class PicoArgs(IEnumerable args, bool recogniseEquals = true) /// public bool Contains(params string[] options) { + ValidateParams(options); CheckFinished(); - if (options == null || options.Length == 0) { - throw new ArgumentException("Must specify at least one option", nameof(options)); - } // no args left if (args.Count == 0) { @@ -50,10 +49,6 @@ public bool Contains(params string[] options) } foreach (var o in options) { - if (!o.StartsWith('-')) { - throw new ArgumentException("Must start with -", nameof(options)); - } - var index = args.FindIndex(a => a.Key == o); if (index >= 0) { // if this argument has a value, throw eg "--verbose=true" when we just expected "--verbose" @@ -77,10 +72,12 @@ public bool Contains(params string[] options) /// public string[] GetMultipleParams(params string[] options) { + ValidateParams(options); CheckFinished(); + var result = new List(); while (true) { - var s = GetParamOpt(options); + var s = GetParamInternal(options); // Internal call, because we have already validated the options if (s == null) { break; // nothing else found, break out of loop } @@ -93,32 +90,31 @@ public string[] GetMultipleParams(params string[] options) /// /// Get a string value from the command line, throws is not present - /// eg -a "value" or --foldera "value" + /// eg -a "value" or --folder "value" /// public string GetParam(params string[] options) => GetParamOpt(options) ?? throw new PicoArgsException(10, $"Expected value for \"{string.Join(", ", options)}\""); /// /// Get a string value from the command line, or null if not present - /// eg -a "value" or --foldera "value" + /// eg -a "value" or --folder "value" /// public string? GetParamOpt(params string[] options) { + ValidateParams(options); CheckFinished(); - if (options == null || options.Length == 0) { - throw new ArgumentException("Must specify at least one option", nameof(options)); - } + return GetParamInternal(options); + } + + /// + /// Internal version of GetParamOpt, which does not check for valid options + /// + private string? GetParamInternal(string[] options) + { if (args.Count == 0) { return null; } - // check all options are switches - foreach (var o in options) { - if (!o.StartsWith('-')) { - throw new ArgumentException("Must start with -", nameof(options)); - } - } - // do we have this switch on command line? var index = args.FindIndex(a => options.Contains(a.Key)); if (index == -1) { @@ -140,16 +136,16 @@ public string[] GetMultipleParams(params string[] options) } // grab and check the next parameter - var seconditem = args[index + 1]; - if (seconditem.Value != null) { - throw new PicoArgsException(30, $"Cannot identify value for param \"{item.Key}\", followed by \"{seconditem.Key}\" and \"{seconditem.Value}\""); + var secondItem = args[index + 1]; + if (secondItem.Value != null) { + throw new PicoArgsException(30, $"Cannot identify value for param \"{item.Key}\", followed by \"{secondItem.Key}\" and \"{secondItem.Value}\""); } // consume the switch and the separate value args.RemoveRange(index, 2); // return the value - return seconditem.Key; + return secondItem.Key; } /// @@ -210,6 +206,34 @@ private void CheckFinished() } } + /// + /// Check options are valid, eg -a or --action, but not -aa (already expanded) or ---action or --a + /// + private static void ValidateParams(string[] options) + { + if (options == null || options.Length == 0) { + throw new ArgumentException("Must specify at least one option", nameof(options)); + } + + foreach (var o in options) { + if (o.Length == 1 || !o.StartsWith('-')) { + throw new ArgumentException($"Options must start with a dash and be longer than 1 character: {o}", nameof(options)); + } + if (o.Length > 2) { + if (o[1] != '-') { + // if it is longer than 2 characters, the second character must be a dash. eg -ab is invalid here (its already been expanded to -a -b) + throw new ArgumentException($"Long options must start with 2 dashes: {o}", nameof(options)); + } else if (o[2] == '-') { + // if it is longer than 2 characters, the third character must not be a dash. eg ---a is not valid + throw new ArgumentException($"Options should not start with 3 dashes: {o}", nameof(options)); + } + if (o.Length == 3) { + throw new ArgumentException($"Long options must be 2 characters or more: {o}", nameof(options)); + } + } + } + } + /// /// Helper function to process the command line arguments. Splits multiple switches into individual switches /// eg -abc becomes -a -b -c