Browse Source

Improved IPA argument parsing (again)

refactor
Anairkoen Schno 6 years ago
parent
commit
e2a2ae1a88
2 changed files with 134 additions and 17 deletions
  1. +105
    -4
      IPA/Arguments.cs
  2. +29
    -13
      IPA/Program.cs

+ 105
- 4
IPA/Arguments.cs View File

@ -1,22 +1,44 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IPA
namespace IPA.ArgParsing
{ {
public class Arguments public class Arguments
{ {
public static Arguments Process = new Arguments(Environment.GetCommandLineArgs());
public static Arguments CmdLine = new Arguments(Environment.GetCommandLineArgs());
private List<string> positional = new List<string>(); private List<string> positional = new List<string>();
private Dictionary<string, string> longFlags = new Dictionary<string, string>(); private Dictionary<string, string> longFlags = new Dictionary<string, string>();
private Dictionary<char, string> flags = new Dictionary<char, string>(); private Dictionary<char, string> flags = new Dictionary<char, string>();
private List<ArgumentFlag> flagObjects = new List<ArgumentFlag>();
private string[] toParse = null;
private Arguments(string[] args) private Arguments(string[] args)
{ {
foreach(var arg in args)
toParse = args;
}
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()
{
foreach (var arg in toParse)
{ {
if (arg.StartsWith("--")) if (arg.StartsWith("--"))
{ // parse as a long flag { // parse as a long flag
@ -27,7 +49,7 @@ namespace IPA
{ {
var spl = name.Split('='); var spl = name.Split('=');
name = spl[0]; name = spl[0];
value = string.Join("=", spl, 1, spl.Length-1);
value = string.Join("=", spl, 1, spl.Length - 1);
} }
longFlags.Add(name, value); longFlags.Add(name, value);
@ -73,6 +95,31 @@ namespace IPA
positional.Add(arg); positional.Add(arg);
} }
} }
toParse = null;
foreach (var flag in flagObjects)
{
foreach (var chflag in flag.shortFlags)
{
if (flag.exists = HasFlag(chflag))
{
flag.value = GetFlagValue(chflag);
goto FoundValue; // continue to next flagObjects item
}
}
foreach (var lflag in flag.longFlags)
{
if (flag.exists = HasLongFlag(lflag))
{
flag.value = GetLongFlagValue(lflag);
goto FoundValue; // continue to next flagObjects item
}
}
FoundValue:;
}
} }
public bool HasLongFlag(string flag) public bool HasLongFlag(string flag)
@ -95,6 +142,60 @@ namespace IPA
return flags[flag]; return flags[flag];
} }
public void PrintHelp()
{
const string indent = " ";
string filename = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
string format = @"help:
{2}{0} [FLAGS] [ARGUMENTS]
flags:
{1}";
var flagsBuilder = new StringBuilder();
foreach (var flag in flagObjects)
{
flagsBuilder.AppendFormat("{2}{0}{1}",
string.Join(", ", flag.shortFlags.Select(s => $"-{s}").Concat( flag.longFlags.Select(s => $"--{s}")) ),
Environment.NewLine, indent);
flagsBuilder.AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent);
}
Console.Write(string.Format(format, filename, flagsBuilder.ToString(), indent));
}
public IReadOnlyList<string> PositionalArgs => positional; public IReadOnlyList<string> PositionalArgs => positional;
} }
public class ArgumentFlag
{
internal List<char> shortFlags = new List<char>();
internal List<string> longFlags = new List<string>();
internal string value = null;
internal bool exists = false;
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 string DocString { get; set; } = "";
public static implicit operator bool(ArgumentFlag f)
{
return f.Exists;
}
}
} }

+ 29
- 13
IPA/Program.cs View File

@ -9,6 +9,7 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using IPA.ArgParsing;
namespace IPA { namespace IPA {
public class Program { public class Program {
@ -20,13 +21,29 @@ namespace IPA {
private static Version Version => Assembly.GetEntryAssembly().GetName().Version; private static Version Version => Assembly.GetEntryAssembly().GetName().Version;
public static ArgumentFlag ArgHelp = new ArgumentFlag("--help", "-h") { DocString = "prints this message" };
public static ArgumentFlag ArgWaitFor = new ArgumentFlag("--waitfor") { DocString = "waits for the specified PID to exit" };
public static ArgumentFlag ArgForce = new ArgumentFlag("--force", "-f") { DocString = "forces the operation to go through" };
public static ArgumentFlag ArgRevert = new ArgumentFlag("--revert") { DocString = "reverts the IPA installation" };
public static ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait") { DocString = "doesn't wait for user input after the operation" };
public static ArgumentFlag ArgStart = new ArgumentFlag("--start") { DocString = "uses value as arguments to start the game after the patch/unpatch" };
public static ArgumentFlag ArgLaunch = new ArgumentFlag("--launch") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
static void Main(string[] args) static void Main(string[] args)
{ {
Arguments.CmdLine.Flags(ArgHelp, ArgWaitFor, ArgForce, ArgRevert, ArgNoWait, ArgStart, ArgLaunch).Process();
if (ArgHelp)
{
Arguments.CmdLine.PrintHelp();
return;
}
try try
{ {
if (Arguments.Process.HasLongFlag("waitfor") && Arguments.Process.GetLongFlagValue("waitfor") != null)
if (ArgWaitFor && ArgWaitFor.Value != null)
{ {
int pid = int.Parse(Arguments.Process.GetLongFlagValue("waitfor"));
int pid = int.Parse(ArgWaitFor.Value);
try try
{ // wait for beat saber to exit (ensures we can modify the file) { // wait for beat saber to exit (ensures we can modify the file)
@ -41,7 +58,7 @@ namespace IPA {
PatchContext context; PatchContext context;
var argExeName = Arguments.Process.PositionalArgs.FirstOrDefault(s => s.EndsWith(".exe"));
var argExeName = Arguments.CmdLine.PositionalArgs.FirstOrDefault(s => s.EndsWith(".exe"));
if (argExeName == null) if (argExeName == null)
{ {
@ -55,7 +72,7 @@ namespace IPA {
context = PatchContext.Create(argExeName); context = PatchContext.Create(argExeName);
} }
bool isRevert = Arguments.Process.HasLongFlag("revert") || Keyboard.IsKeyDown(Keys.LMenu);
bool isRevert = ArgRevert || Keyboard.IsKeyDown(Keys.LMenu);
// Sanitizing // Sanitizing
Validate(context); Validate(context);
@ -107,8 +124,7 @@ namespace IPA {
var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins"); var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins");
bool isFlat = Directory.Exists(nativePluginFolder) && bool isFlat = Directory.Exists(nativePluginFolder) &&
Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll")); Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll"));
bool force = !BackupManager.HasBackup(context) || Arguments.Process.HasFlag('f') ||
Arguments.Process.HasLongFlag("force");
bool force = !BackupManager.HasBackup(context) || ArgForce;
var architecture = DetectArchitecture(context.Executable); var architecture = DetectArchitecture(context.Executable);
Console.WriteLine("Architecture: {0}", architecture); Console.WriteLine("Architecture: {0}", architecture);
@ -202,7 +218,7 @@ namespace IPA {
} }
if (!Arguments.Process.HasLongFlag("nowait"))
if (!ArgNoWait)
{ {
Console.ForegroundColor = ConsoleColor.Green; Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Finished!"); Console.WriteLine("Finished!");
@ -232,7 +248,7 @@ namespace IPA {
Console.WriteLine(""); Console.WriteLine("");
Console.WriteLine("--- Done reverting ---"); Console.WriteLine("--- Done reverting ---");
if (!Arguments.Process.HasLongFlag("nowait") && !isNewVersion) {
if (!ArgNoWait && !isNewVersion) {
Console.WriteLine("\n\n[Press any key to quit]"); Console.WriteLine("\n\n[Press any key to quit]");
Console.ReadKey(); Console.ReadKey();
} }
@ -241,17 +257,17 @@ namespace IPA {
} }
private static void StartIfNeedBe(PatchContext context) { private static void StartIfNeedBe(PatchContext context) {
if (Arguments.Process.HasLongFlag("start") && Arguments.Process.GetLongFlagValue("start") != null)
if (ArgStart && ArgStart.Value != null)
{ {
Process.Start(context.Executable, Arguments.Process.GetLongFlagValue("start"));
Process.Start(context.Executable, ArgStart.Value);
} }
else else
{ {
var argList = Arguments.Process.PositionalArgs.ToList();
var argList = Arguments.CmdLine.PositionalArgs.ToList();
argList.Remove(context.Executable); argList.Remove(context.Executable);
if (Arguments.Process.HasLongFlag("launch"))
if (ArgLaunch)
{ {
Process.Start(context.Executable, Args(argList.ToArray())); Process.Start(context.Executable, Args(argList.ToArray()));
} }
@ -332,7 +348,7 @@ namespace IPA {
static void Fail(string message) { static void Fail(string message) {
Console.Error.Write("ERROR: " + message); Console.Error.Write("ERROR: " + message);
if (!Arguments.Process.HasLongFlag("nowait")) {
if (!ArgNoWait) {
Console.WriteLine("\n\n[Press any key to quit]"); Console.WriteLine("\n\n[Press any key to quit]");
Console.ReadKey(); Console.ReadKey();
} }


Loading…
Cancel
Save