From 7a7522f282cce8e511a80f38617a0561e2184b87 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Wed, 5 May 2021 06:08:47 +1000 Subject: [PATCH] Add path helpers, normalise rom path from CLI, update readme see #2077 --- README.md | 9 ++++-- src/BizHawk.Client.EmuHawk/MainForm.cs | 4 +-- .../Extensions/PathExtensions.cs | 29 +++++++++++++++++++ src/BizHawk.Common/IImportResolver.cs | 6 ++-- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index adc24288b9..a26386cf7d 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ On Windows 8.1/10, it's easiest to use PowerShell for this. For example, to pass ```pwsh (New-Object System.Diagnostics.Process -Property @{StartInfo=(New-Object System.Diagnostics.ProcessStartInfo -Property @{FileName="$PWD\EmuHawk.exe";Arguments='"--lua=C:\path\to\script.lua" "C:\path\to\rom.n64"'})}).Start() ``` +Note: PowerShell's `cd` doesn't seem to change the CWD of child processes. Just open a shell from the install folder. Don't @ me. For char escaping tips you're on your own. It might help to split up the command so you can identify syntax errors: ```pwsh @@ -205,8 +206,12 @@ $proc = New-Object System.Diagnostics.Process -Property @{StartInfo=$startInfo} $proc.Start() ``` -On Linux, you can pass arguments to `EmuHawkMono.sh` as expected and they will be forwarded to `mono`. (You can also `export` env. vars.) There is one exception: if you pass `--mono-no-redirect` as the *first argument* it will be eaten by the script itself, and stdout will *not* be redirected to a file. -The same example as above would be `./EmuHawkMono.sh --lua=/path/to/script.lua /path/to/rom.n64`. +On Linux, you can pass arguments to `EmuHawkMono.sh` as expected and they will be forwarded to `mono`. (You can also `export` env. vars.) All the arguments work as on Windows, with some caveats: +* Lua scripts are ignored; +* file paths must be absolute (or relative to the install dir, `EmuHawkMono.sh` changes the CWD to there); +* `--mono-no-redirect`: if you pass this flag *as the first argument*, it will be eaten by the script itself, and stdout will *not* be redirected to a file. (It's redirected by default.) + +The same example as above would be `./EmuHawkMono.sh --lua=/path/to/script.lua /path/to/rom.n64` (but Lua is no-op). For char escaping tips, see ~~Unix StackExchange~~ your shell's man/info page. BASH and Zsh have different rules! diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 6a847d4fcd..e5055cfde6 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -497,8 +497,8 @@ namespace BizHawk.Client.EmuHawk if (_argParser.cmdRom != null) { // Commandline should always override auto-load - var ioa = OpenAdvancedSerializer.ParseWithLegacy(_argParser.cmdRom); - LoadRom(_argParser.cmdRom, new LoadRomArgs { OpenAdvanced = ioa }); + var romPath = _argParser.cmdRom.MakeAbsolute(); + LoadRom(romPath, new LoadRomArgs { OpenAdvanced = OpenAdvancedSerializer.ParseWithLegacy(romPath) }); if (Game == null) { ShowMessageBox(owner: null, $"Failed to load {_argParser.cmdRom} specified on commandline"); diff --git a/src/BizHawk.Common/Extensions/PathExtensions.cs b/src/BizHawk.Common/Extensions/PathExtensions.cs index e03f11057e..0d09e49f94 100644 --- a/src/BizHawk.Common/Extensions/PathExtensions.cs +++ b/src/BizHawk.Common/Extensions/PathExtensions.cs @@ -48,6 +48,26 @@ namespace BizHawk.Common.PathExtensions return false; } + /// iff absolute (OS-dependent) + /// + public static bool IsAbsolute(this string path) + { + if (OSTailoredCode.IsUnixHost) return path.Length >= 1 && path[0] == '/'; + if (path.Contains('/')) return IsAbsolute(path.Replace('/', '\\')); + return path.Length >= 3 + && path[2] switch + { + '\\' => path[1] == '\\' && ('A'.RangeTo('Z').Contains(path[0]) || 'a'.RangeTo('z').Contains(path[0])), + '?' => path.StartsWith(@"\\?\"), + _ => false + }; + } + + /// iff absolute (OS-dependent) + /// that means it may return for invalid paths + /// + public static bool IsRelative(this string path) => !path.IsAbsolute(); + /// running on Windows host, and unmanaged call failed /// running on Windows host, and either path is not a regular file or directory /// @@ -87,6 +107,15 @@ namespace BizHawk.Common.PathExtensions : throw new ArgumentException("Paths must have a common prefix"); } + /// absolute path (OS-dependent) equivalent to + /// + /// unless is given, uses CWDHacks.Get/Environment.CurrentDirectory, + /// so take care when calling this after startup + /// + public static string MakeAbsolute(this string path, string? cwd = null) => path.IsAbsolute() + ? path + : new FileInfo($"{cwd ?? (OSTailoredCode.IsUnixHost ? Environment.CurrentDirectory : CWDHacks.Get())}/{path}").FullName; // FileInfo for normalisation ("C:\a\b\..\c" => "C:\a\c") + /// the absolute path equivalent to which contains %exe% (expanded) as a prefix /// /// returned string omits trailing slash
diff --git a/src/BizHawk.Common/IImportResolver.cs b/src/BizHawk.Common/IImportResolver.cs index 22d3265a1b..30797a3249 100644 --- a/src/BizHawk.Common/IImportResolver.cs +++ b/src/BizHawk.Common/IImportResolver.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using BizHawk.Common.PathExtensions; + namespace BizHawk.Common { /// Implementors are able to provide pointers to functions in dynamically-linked libraries, which are loaded through some undefined mechanism. @@ -32,7 +34,7 @@ namespace BizHawk.Common }; } - private static string UnixResolveFilePath(string orig) => orig[0] == '/' + private static string UnixResolveFilePath(string orig) => orig.IsAbsolute() ? orig : UnixSearchPaths.Select(dir => dir + orig) .FirstOrDefault(s => @@ -40,7 +42,7 @@ namespace BizHawk.Common var fi = new FileInfo(s); return fi.Exists && (fi.Attributes & FileAttributes.Directory) != FileAttributes.Directory; }) - ?? orig; + ?? orig; // don't MakeAbsolute, just pass through and hope something lower-level magically makes it work private IntPtr _p;