Skip to content

Parameter name is treated as parameter value #857

Open
@HidetoshiMiyao

Description

@HidetoshiMiyao

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<Options>(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<Token>, IEnumerable<Token>, IEnumerable<Token>, IEnumerable<Token>> PartitionTokensByType(
            IEnumerable<Token> tokens,
            Func<string, Maybe<TypeDescriptor>> typeLookup)
        {
            var switchTokens = new List<Token>();
            var scalarTokens = new List<Token>();
            var sequenceTokens = new List<Token>();
            var nonOptionTokens = new List<Token>();
            var sequences = new Dictionary<Token, IList<Token>>();
            var count = new Dictionary<Token, int>();
            var max = new Dictionary<Token, Maybe<int>>();
            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<Token>();
                                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;

                        ......

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions