Closed ptr727 closed 6 months ago
Does it work like you expect if you escape the backslash?
This is a 'bug' with any .Net app that accepts command line arguments. If the string ends in \" then everything after it is merged (not just the next item). You can see this if you look at the args array in Main.. You'll have a much smaller array than expected. I noticed this with Ndesk.options a few months ago and traced the behavior to a NET/windows issue. GetCommandLineArgsNative is an internal call which obviously calls some native code to parses the command line arguments ( CommandLineToArgvW) which has special rules for quotes and slashes. These misparsed arguments are what get passed into the arguments array. Read here for more info on the particular issue. https://weblogs.asp.net/jongalloway/Command-Line-Confusion Check the Comments for a link to another blog post which in turn has a lot of details in ITS comments (not so much the blog itself)
The fix should be pretty simple to include in the mainline code:
// TODO : Quoted paths ending in a \ fail to parse properly, use our own parser for now
// https://github.com/gsscoder/commandline/issues/473
ParserResult<Options> result = parser.ParseArguments<Options>(Tools.GetCommandlineArgs());
if (result.Tag == ParserResultType.NotParsed)
{
Tools.WriteLineError("Failed to parse commandline.");
return -1;
}
Options options = (((Parsed<Options>)result).Value);
// https://stackoverflow.com/questions/298830/split-string-containing-command-line-parameters-into-string-in-c-sharp
public static string[] ParseArguments(string commandLine)
{
char[] parmChars = commandLine.ToCharArray();
bool inQuote = false;
for (int index = 0; index < parmChars.Length; index++)
{
if (parmChars[index] == '"')
inQuote = !inQuote;
if (!inQuote && parmChars[index] == ' ')
parmChars[index] = '\n';
}
return (new string(parmChars)).Split('\n');
}
public static string[] GetCommandlineArgs()
{
// Split the arguments
string[] args = ParseArguments(Environment.CommandLine);
// Strip the process path from the lsit of arguments
string[] argsex = new string[args.Length - 1];
Array.Copy(args, 1, argsex, 0, argsex.Length);
return argsex;
}
This looks like a common mistake I've made dozens of times with Command Prompt. Windows itself does the argument splitting, and it is interpreting \"
to mean "oh, you wanted to escape the backslash. If I remember right, you can get around this with either of these invocations:
foo.exe "W:\\" "X:\\"
foo.exe "W:^\" "X:^\"
Update was wrong about the second one. Just the first one works. See also https://github.com/natemcmaster/CommandLineUtils/issues/220#issuecomment-482453664
Abandon
If a commandline includes a quoted path ending in a \, the arguments are incorrectly merged.
E.g.
This seems to be a general problem with C# console commandline parsing, and the docs for Environment.GetCommandLineArgs() say we need to use "c:\" to avoid this, which is unnatural.
In other commandline parsing classes this is not an issue for commandline args are treated as literal input, and split by space and by quoted strings.
Can you please create a constructor that does its own string parsing, i.e. instead of using the flawed console args, take the raw Environment.CommandLine value and split it, or take a default constructor that internally calls Environment.CommandLine?