Example #1
0
        private string Usage(Type type)
        {
            VerbAttribute verbAttr    = type.GetCustomAttributes <VerbAttribute>().FirstOrDefault();
            var           options     = OptionsClassProcessor.GetOptions(type);
            var           values      = OptionsClassProcessor.GetValues(type);
            var           restOfInput = OptionsClassProcessor.GetRestOfInputProperty(type);

            StringBuilder result = new StringBuilder();

            if (verbAttr != null)
            {
                result.AppendLine(verbAttr.HelpText.SplitToLines(LineWidth + 20, 0) + Environment.NewLine);
            }
            foreach (var option in options.Values)
            {
                result.AppendFormat("{0,-20} {1}" + Environment.NewLine,
                                    (option.IsShortOption ? "-" : "--") + option.Option,
                                    option.Description.SplitToLines(LineWidth, PrepadSpaces));
            }
            foreach (var value in values.Values.OrderBy(v => v.Index))
            {
                result.AppendFormat("#{0,-19} {1}" + Environment.NewLine,
                                    value.Index,
                                    value.Description.SplitToLines(LineWidth, PrepadSpaces));
            }
            if (restOfInput != null)
            {
                result.AppendFormat("{0,-20} {1}" + Environment.NewLine,
                                    "rest of input",
                                    restOfInput.Item2.Description.SplitToLines(LineWidth, PrepadSpaces));
            }
            return(result.ToString());
        }
Example #2
0
        private ParseResult <object> Parse(Type type, string input)
        {
            // TODO Refactor this whole thing to use exception handling and store common objects in a class

            object instance = Activator.CreateInstance(type);

            Dictionary <string, OptionAttribute> options = OptionsClassProcessor.GetOptions(type);
            Dictionary <int, ValueAttribute>     values  = OptionsClassProcessor.GetValues(type);
            int             unsatisfiedCount             = options.Count + values.Count;
            int             nextValueToFill      = 0;
            OptionAttribute optionExpectingValue = null;
            Tokenizer       tokenizer            = new Tokenizer(input);

            while (!tokenizer.AtEnd && unsatisfiedCount > 0)
            {
                Token token = tokenizer.NextToken;
                switch (token.Kind)
                {
                case TokenKind.LongOption:
                case TokenKind.ShortOption:
                    if (optionExpectingValue != null)
                    {
                        return(ParseResult <object> .WithError("No value provided for option '" + optionExpectingValue.Option + "'"));
                    }
                    OptionAttribute optionAttr;
                    if (!options.TryGetValue(token.Value, out optionAttr))
                    {
                        return(ParseResult <object> .WithError("Unexpected option '" + token.Value + "'"));
                    }
                    if (optionAttr.Satisfied)
                    {
                        return(ParseResult <object> .WithError("Multiple values for option '" + token.Value + "' are not allowed"));
                    }

                    var alreadySatisfiedExclusiveOption = FirstAlreadySatisfiedMutuallyExclusiveOption(options, optionAttr);
                    if (alreadySatisfiedExclusiveOption != null)
                    {
                        return(ParseResult <object> .WithError("The option '" + token.Value + "' is mutually exclusive with the option '" + alreadySatisfiedExclusiveOption.Option + "' that was already satisfied"));
                    }

                    if (optionAttr.TargetProperty.PropertyType == typeof(bool))
                    {
                        optionAttr.TargetProperty.SetValue(instance, true);
                        optionAttr.Satisfied = true;
                        --unsatisfiedCount;
                    }
                    else
                    {
                        optionExpectingValue = optionAttr;
                    }
                    break;

                case TokenKind.Value:
                    if (optionExpectingValue != null)
                    {
                        string error = SetPropertyValue(optionExpectingValue, instance, token.Value);
                        if (error != null)
                        {
                            return(ParseResult <object> .WithError("Error setting option '" + optionExpectingValue.Option + "': " + error));
                        }
                        optionExpectingValue.Satisfied = true;
                        optionExpectingValue           = null;
                        --unsatisfiedCount;
                    }
                    else
                    {
                        if (nextValueToFill >= values.Count)
                        {
                            // There are no more values to fill, just options
                            return(ParseResult <object> .WithError("Unexpected plain value '" + token.Value + "'"));
                        }

                        ValueAttribute valueAttr = values[nextValueToFill];
                        string         error     = SetPropertyValue(valueAttr, instance, token.Value);
                        if (error != null)
                        {
                            return(ParseResult <object> .WithError("Error setting value #" + nextValueToFill + ": " + error));
                        }
                        valueAttr.Satisfied = true;
                        --unsatisfiedCount;
                        ++nextValueToFill;
                    }
                    break;

                case TokenKind.Error:
                    return(ParseResult <object> .WithError("Error parsing options: " + token.Value));
                }
            }

            SetDefaultValues(instance, options, values);

            var errorResult = FindUnsatisfiedOptionsAndValues(options, values);

            if (errorResult != null)
            {
                return(errorResult);
            }

            errorResult = SetRestOfInputPropertyIfAvailable(type, instance, tokenizer);
            if (errorResult != null)
            {
                return(errorResult);
            }

            return(ParseResult <object> .WithValue(instance));
        }