j-maly / CommandLineParser

Command line parser. Declarative arguments support. Rich set of argument types (switches, enums, files, etc...). Mutually exclusive arguments validations.
MIT License
137 stars 30 forks source link

.NET parsing issue #42

Open gt2847c opened 7 years ago

gt2847c commented 7 years ago

I ran into this problem with the .NET args parsing, so this isn't a problem in CommandLineParser, but I thought I'd mention as it can make using your package challenging where there are arguments that have quoted paths. When passing a path having spaces as an argument, you have to double quote the path to make sure it's consumed as a single argument. The problem is that when the path has a trailing backslash followed by the closing double quote, the .NET parser treats it as an escaped double quote and any trailing options following get munged into that argument. I am able to work around it by looking for a double quote in the argument and replacing it with a backslash so long as it's the last argument on the command line. MSDN's remarks on command line processing notes the behavior which is how it acts, even if it happens to cause difficulties working with quoted paths:

If a double quotation mark follows two or an even number of backslashes, each proceeding backslash pair is replaced with one backslash and the double quotation mark is removed. If a double quotation mark follows an odd number of backslashes, including just one, each preceding pair is replaced with one backslash and the remaining backslash is removed; however, in this case the double quotation mark is not removed.

Here's a couple of examples,

With path statement last:

C:\tmp>DirectorySearch.exe -f output.csv -d "C:\Program Files\"
Parsing results:
        Command line:
-f output.csv -d C:\Program Files"

        Parsed Arguments:
Argument: f(filename), type: String, value: output.csv (converted from: output.csv)
Argument: d(directory), type: String, value: C:\Program Files" (converted from: C:\Program Files")

        Arguments not specified:
Argument: h(help) value: 0

        Additional arguments:

It sees both arguments, but the path contains a double quote rather than the trailing backslash. This can be worked around by replacing the escaped quote, but it requires the path always be in last position as an argument.

With path statement first:

C:\tmp>DirectorySearch.exe -d "C:\Program Files\" -f output.csv

This triggers an exception because the -f argument is required:


Required arguments missing. Please see usage:

DirectorySearch

Usage:
        -f, --filename... Filename to receive catalog data

        -d, --directory... Directory root to catalog

        -h, --help[optional]... DirectorySearch command line arguments

Parsing results:
        Command line:
-d C:\Program Files" -d output.csv

        Parsed Arguments:
Argument: d(directory), type: String, value: C:\Program Files" -d output.csv (converted from: C:\Program Files" -d output.csv)

        Arguments not specified:
Argument: f(filename), type: String, value:  (converted from: )
Argument: h(help) value: 0

        Additional arguments:

In this case, the -f and filename are consumed by the -d. Again, this is a problem with the .NET parsing of the command line, here's the args variable from the second argument: `

`

Not sure if there's a good workaround that can be done in your package given you might actually want the escaped quotes in some cases (maybe a decorator denoting a path). I know that this particular argument is intended to be path, so I can make allowances for it, but it does make it more difficult as I have to require the user to order the arguments such that the path is last which allows me to use your package (much easier for me) or I have to directly work with the Environment.CommandLine to pick out the bits I need and essentially build my own parser specifically to handle this..

gt2847c commented 7 years ago

Just thought I'd mention that I did try the DirectoryArgument decorator, but got the same results when the -d argument is first.

j-maly commented 7 years ago

Thanks for the interesting post, maybe we could add some alternative parsing using Environment.CommandLine in the future.