commandlineparser / commandlineparser/commandline

Parameter name is treated as parameter value

Open
#857 4 comments 1 reaction 0 assignees View on GitHub
bug help wanted
Dominant language
C#
Stars
4.8k
Forks
478
PR merge metrics
No merged PRs in 30d

Description

If I omit parameter value for one parameter name, next parametername is treated as value of the parameter.
Occurred at v2.9.1 from Nuget.

### What I observed
Code:
```
using System;
using CommandLine;

class Options
{
[Option('a', "option1", Required = true)]
public string Option1 { get; set; }

[Option('b', "option2", Required = false)]
public int option2 { get; set; }
}

class Program
{
static int Main(string[] args)
{
return Parser.Default.ParseArguments(args)
.MapResult(
options => RunAndReturnExitCode(options),
_ => -1);
}

static int RunAndReturnExitCode(Options options)
{
Console.WriteLine($"option1={options.Option1}, option2={options.option2}");
return 0;
}
}
```
Command line,
`$command --option1 --option2 5`
gives the result output,
`option1=option2, option2=0`

But expected result is to report error with lacking of required "option1".

### Suggested fix
In the method "CommandLine.Core.TokenPartitioner.PartitionTokensByType", scalarTokens.add(Scalar nem token) shall be occurred only when the following value is confirmed.

```
public static Tuple, IEnumerable, IEnumerable, IEnumerable> PartitionTokensByType(
IEnumerable tokens,
Func> typeLookup)
{
var switchTokens = new List();
var scalarTokens = new List();
var sequenceTokens = new List();
var nonOptionTokens = new List();
var sequences = new Dictionary>();
var count = new Dictionary();
var max = new Dictionary>();
var state = SequenceState.TokenSearch;
var separatorSeen = false;
Token nameToken = null;
foreach (var token in tokens)
{
if (token.IsValueForced())
{
separatorSeen = false;
nonOptionTokens.Add(token);
}
else if (token.IsName())
{
separatorSeen = false;
if (typeLookup(token.Text).MatchJust(out var info))
{
switch (info.TargetType)
{
case TargetType.Switch:
nameToken = null;
switchTokens.Add(token);
state = SequenceState.TokenSearch;
break;
case TargetType.Scalar:
nameToken = token;
// scalarTokens.Add(nameToken); <- don't add here
state = SequenceState.ScalarTokenFound;
break;
case TargetType.Sequence:
nameToken = token;
if (! sequences.ContainsKey(nameToken))
{
sequences[nameToken] = new List();
count[nameToken] = 0;
max[nameToken] = info.MaxItems;
}
state = SequenceState.SequenceTokenFound;
break;
}
}
else
{
nameToken = null;
nonOptionTokens.Add(token);
state = SequenceState.TokenSearch;
}
}
else
{
switch (state)
{
case SequenceState.TokenSearch:
case SequenceState.ScalarTokenFound when nameToken == null:
case SequenceState.SequenceTokenFound when nameToken == null:
separatorSeen = false;
nameToken = null;
nonOptionTokens.Add(token);
state = SequenceState.TokenSearch;
break;

case SequenceState.ScalarTokenFound:
separatorSeen = false;
scalarTokens.Add(nameToken); // add here instead so that scalar name token is valid only when a value is given
nameToken = null;
scalarTokens.Add(token);
state = SequenceState.TokenSearch;
break;

......
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in CommandLine.Core.TokenPartitioner.PartitionTokensByType and reproduce the issue with `--option1 --option2 5` using the provided C# example. Trace the ScalarTokenFound state and verify that a scalar option name is only retained when followed by a value. Done means the missing required option1 is reported as an error instead of treating option2 as its value.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.