|
|
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
-
- namespace IPA
- {
- public class Arguments
- {
- public static readonly Arguments CmdLine = new(Environment.GetCommandLineArgs());
-
- private readonly List<string> positional = new();
- private readonly Dictionary<string, string?> longFlags = new();
- private readonly Dictionary<char, string?> flags = new();
- private readonly List<ArgumentFlag> flagObjects = new();
-
- private string[]? toParse;
-
- private Arguments(string[] args)
- {
- toParse = args.Skip(1).ToArray();
- }
-
- public Arguments Flags(params ArgumentFlag[] toAdd)
- {
- foreach (var f in toAdd) AddFlag(f);
- return this;
- }
-
- public void AddFlag(ArgumentFlag toAdd)
- {
- if (toParse == null) throw new InvalidOperationException();
- flagObjects.Add(toAdd);
- }
-
- public void Process()
- {
- if (toParse == null) throw new InvalidOperationException();
-
- foreach (var arg in toParse)
- {
- if (arg.StartsWith("--"))
- { // parse as a long flag
- var name = arg.Substring(2); // cut off first two chars
- string? value = null;
-
- if (name.Contains('='))
- {
- var spl = name.Split('=');
- name = spl[0];
- value = string.Join("=", spl, 1, spl.Length - 1);
- }
-
- longFlags.Add(name, value);
- }
- else if (arg.StartsWith("-"))
- { // parse as flags
- var argument = arg.Substring(1); // cut off first char
-
- var subBuildState = new StringBuilder();
- var parsingValue = false;
- var escaped = false;
- var mainChar = ' ';
- foreach (var chr in argument)
- {
- if (!parsingValue)
- {
- if (chr == '=')
- {
- parsingValue = true;
- }
- else
- {
- mainChar = chr;
- flags.Add(chr, null);
- }
- }
- else
- {
- if (!escaped)
- {
- if (chr == ',')
- {
- parsingValue = false;
- flags[mainChar] = subBuildState.ToString();
- subBuildState = new StringBuilder();
- continue;
- }
- else if (chr == '\\')
- {
- escaped = true;
- continue;
- }
- }
-
- _ = subBuildState.Append(chr);
- }
- }
-
- if (parsingValue)
- {
- flags[mainChar] = subBuildState.ToString();
- }
- }
- else
- { // parse as positional
- positional.Add(arg);
- }
- }
-
- toParse = null;
-
- foreach (var flag in flagObjects)
- {
- foreach (var charFlag in flag.ShortFlags)
- {
- if (!(flag.exists_ = HasFlag(charFlag))) continue;
-
- flag.value_ = GetFlagValue(charFlag);
- goto FoundValue; // continue to next flagObjects item
- }
-
- foreach (var longFlag in flag.LongFlags)
- {
- if (!(flag.exists_ = HasLongFlag(longFlag))) continue;
-
- flag.value_ = GetLongFlagValue(longFlag);
- goto FoundValue; // continue to next flagObjects item
- }
-
- FoundValue:;
- }
- }
-
- public bool HasLongFlag(string flag)
- {
- return longFlags.ContainsKey(flag);
- }
-
- public bool HasFlag(char flag)
- {
- return flags.ContainsKey(flag);
- }
-
- public string? GetLongFlagValue(string flag)
- {
- return longFlags[flag];
- }
-
- public string? GetFlagValue(char flag)
- {
- return flags[flag];
- }
-
- public void PrintHelp()
- {
- const string indent = " ";
- var filename = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
- const string format = @"usage:
- {2}{0} [FLAGS] [ARGUMENTS]
-
- flags:
- {1}";
- var flagsBuilder = new StringBuilder();
- foreach (var flag in flagObjects)
- {
- _ = flagsBuilder
- .AppendFormat("{2}{0}{3}{1}",
- string.Join(", ", flag.ShortFlags.Select(s => $"-{s}").Concat( flag.LongFlags.Select(s => $"--{s}")) ),
- Environment.NewLine, indent, flag.ValueString != null ? "=" + flag.ValueString : "")
- .AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent);
- }
-
- Console.Write(format, filename, flagsBuilder, indent);
- }
-
- public IReadOnlyList<string> PositionalArgs => positional;
- }
-
- public class ArgumentFlag
- {
- internal readonly List<char> ShortFlags = new();
- internal readonly List<string> LongFlags = new();
-
- internal string? value_;
- internal bool exists_;
-
- public ArgumentFlag(params string[] flags)
- {
- foreach (var part in flags)
- AddPart(part);
- }
-
- private void AddPart(string flagPart)
- {
- if (flagPart.StartsWith("--"))
- LongFlags.Add(flagPart.Substring(2));
- else if (flagPart.StartsWith("-"))
- ShortFlags.Add(flagPart[1]);
- }
-
- public bool Exists => exists_;
- public string? Value => value_;
-
- public bool HasValue => Exists && Value != null;
-
- public string DocString { get; set; } = "";
- public string? ValueString { get; set; }
-
- public static implicit operator bool(ArgumentFlag f) => f.Exists;
- }
- }
|