Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Needs to handle free arguments. #1

Open
pragmatrix opened this issue Feb 24, 2013 · 11 comments
Open

Needs to handle free arguments. #1

pragmatrix opened this issue Feb 24, 2013 · 11 comments
Milestone

Comments

@pragmatrix
Copy link
Contributor

I'd like to extract free arguments from the command line, e.g. arguments without an option like MyConsoleApp.exe --opt1 opt1value Filename.txt. Right now it seems that Filename.txt is ignored and can not be extracted from CommandLineParserResult.

Is this planned?

@siywilliams
Copy link
Member

Interesting, I've not used free arguments before.

May I ask what purpose do they serve, and how would you expect to consume them through the api? What if the same free argument was specified twice?

@pragmatrix
Copy link
Contributor Author

Often a command has some primary function that is associated with one or more file-names or a host name, for example. In such cases it makes sense to pass them without an option. Prominent examples are echo, cat, or ssh.

I would prefer to retrieve the free arguments via callbacks in the DSL instead of going through a list of free arguments in the result interface, simply because free arguments may need to take part in the error checking. Right now free arguments are ignored and commands could run without being sure that all the user input was handled properly.

What should happen when the same free argument is passed twice to a command is up to the command's semantic. So either the DSL supports some additional parameterization or - if a callback is used - it just calls it for each in the order supplied.

I guess it could also happen that a free argument is just a shortcut that provides a value for one of the options, so there could also be a method that marks an option as the one that receives the free arguments by default.

@siywilliams
Copy link
Member

I'm going to spend some time soon working towards other features to include so I will see about how free arguments could fit into it. If you have any other suggestions I will be interested to hear them.

@pragmatrix
Copy link
Contributor Author

One related thing I can remember is that some Linux commands support this -- marker. From the bash man page:

A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.

This seems to be very useful for commands that wish to forward options and arguments to other commands. The API could look something like:

.PassThroughAfter("--")
  .Callback(remainingOptionOrArg => stuffIWantToForward.Add(remainingOptionOrArg))

@siywilliams
Copy link
Member

Work almost complete towards support for -- which disables further option parsing and treats all remaining arguments as additional for the current option.

Using your initial example:

MyConsoleApp.exe --opt1 opt1value Filename.txt Filename2.txt

CaptionAdditionalArguments(Action<IEnumerable<string>>) is used to now capture the free arguments Filename.txt and Filename2.txt

The setup looks like this

string value;
var freeArgs = new List<string>();

parser.Setup<string>("opt1")
      .Callback(str => value = str)
      .CaptureAdditionalArguments(freeArgs.AddRange);

// after parsing
// value is "opt1value"
// freeArgs contains "Filename.txt", "Filename2.txt"

It can also be used to safely handle negative integer and doubles

MyConsoleApp.exe --numbers -- -123 123 -789 789

can be safely parsed to a list of integers using

var numbers = new List<int>();

parser.Setup<int>("numbers")
      .Callback(numbers.AddRange);

// after parsing numbers contains
// -123
// 123
// -789
// 789

@pragmatrix
Copy link
Contributor Author

Great work! But I'm not sure if your interpretation of the -- semantics is correct.

I don't think that arguments after -- should be linked to any option that comes before. From my experience, -- is used to capture a trailing set of free arguments, which may include unescaped options. These strings may then passed to subsequent shells / command line processors.

In bash for example, you can clearly separate the arguments that are given to the shell and the script it executes: bash --login -- test.sh --option_for_test_sh. Here, everything before the -- goes to bash, everything after the -- goes to test.sh.

@do0om
Copy link
Contributor

do0om commented Jul 3, 2013

I agree with pragmatrix. It's like in git commit command (https://www.kernel.org/pub/software/scm/git/docs/git-commit.html) , the free arguments at the end represent a list of files, which are not linked to any of the previous options.
In my latest pull request, I didn't link arguments after "--" to any option.
I think this is why 6 tests are failing, our expectations are different.

@mbrenn
Copy link

mbrenn commented Jan 25, 2015

I also agree. Being able to parse something like

  • "a.exe input output -o options"

is a mandatory requirement for such a library, which is not satisfied here.

@graniv
Copy link

graniv commented Jun 24, 2015

UP

I also agree with @pragmatrix and @do0om. Could you add a semantics like this ?

In bash for example, you can clearly separate the arguments that are given to the shell and the script it executes: bash --login -- test.sh --option_for_test_sh. Here, everything before the -- goes to bash, everything after the -- goes to test.sh.

@ruslanfedoseenko
Copy link

ruslanfedoseenko commented Sep 24, 2016

You may look how other do that case. For example boost::program_options call this type of parameters Positional Options. Here is a small description. Hope it can help you to understed what they are.

@sgillbee
Copy link

sgillbee commented Mar 27, 2017

How about allowing certain arguments to be definable as positional to allow mapping of positional arguments to strongly-typed arguments.

For example:

p.Setup(arg => arg.InputFile)
  .As('i', "input")
  .OrAsPositional();

p.Setup(arg => arg.OutputFile)
  .As('o', "output")
  .OrAsPositional();

This would parse "app.exe -i filename.txt -o outfile.txt" and also "app.exe filename.exe outfile.txt" and also "app.exe outfile.txt -i filename.txt. You could mix named and positional arguments in any order. Basically, the parser would split the command line into parsable segments. It would first assign all the named argumented. Then it would take all the positional arguments in order and map the to the list of unassigned arguments in the order they were defined in the code.

Examples:
app.exe -i filename.txt -o outfile.txt
This would parse into two named blocked and no positional blocks: "-i filename.txt" and "-o outfile.txt".
settings.InputFile == "filename.txt"
settings.OutputFile == "outfile.txt"
Nothing new here. Move along.

app.exe filename.txt outfile.txt
This would parse into two positional blocks: "filename.txt" and "outfile.txt". The would be assigned in order to properties tagged as OrAsPositional in the order they were defined (InputFile and then OutputFile)
settings.InputFile == "filename.txt"
settings.OutputFile == "outfile.txt"
Fairly straightforward since there is no mix of param types

app.exe outfile.txt -i filename.txt
This would parse into one positional block ("outfile.txt") and one named block ("-i filename.txt"). First the named block would be assigned so that:
settings.InputFile == "filename.txt"
Then the positional block would be assigned based on the order that properties have been assigned. First defined is InputFile, but it's already assigned. So next up is OutputFile. That's unassigned to assign "outfile.txt" to OutputFile.
settings.OutputFile == "outfile.txt"
Now you can mix and match positional and named arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants