/// <summary>
        /// Adds the specified CommandLineOption object to the list of supported command-line options.
        /// </summary>
        /// <param name="option">The option to add.</param>
        public void AddOption(CommandLineOption option)
        {
            CheckNameAvailable(option.Name);

            Options.Add(option);
            option.Parser = this;
        }
 private string FormatOption(string format, CommandLineOption option)
 {
     return(String.Format(
                format,
                option.ShortSymbol,
                option.LongSymbol,
                option.IsRequired ? "required" : "optional",
                option.Description,
                option.DefaultValue != null ? " (\"" + option.DefaultValue + "\")" : ""
                ));
 }
 /**
  * Accepts command line args in the form of a string array, and assigns the
  * given values to the object properties annotated by CommandLineOption attributes.
  * Any text output (e.g. usage, errors) is written to the given TextWriter.
  */
 protected AbstractCommandLine(String[] args, TextWriter writer)
 {
     this.allOptions                        = new List <CommandLineOption>();
     this.requiredOptions                   = new List <CommandLineOption>();
     this.optionalOptions                   = new List <CommandLineOption>();
     this.optionPropertyDict                = new Dictionary <CommandLineOption, PropertyInfo>();
     this.argValDict                        = new Dictionary <string, string>();
     this.targetCommandLineOption           = null;
     this.targetValue                       = null;
     this.lastArgKey                        = null;
     this.lastArgValue                      = null;
     this.missingRequiredCommandLineOptions = new List <CommandLineOption>();
     this.ProcessOptions(args, writer);
 }
        /**
         * Finds a CommandLineOption on this class that matches the given symbol (short or long).
         * Returns null if no such CommandLineOption exists.
         */
        protected CommandLineOption FindCommandLineOption(string symbol)
        {
            CommandLineOption commandLineOption = null;

            foreach (CommandLineOption o in this.allOptions)
            {
                if (lastArgKey.Equals("" + o.ShortSymbol) || lastArgKey.Equals(o.LongSymbol))
                {
                    commandLineOption = o;
                    break;
                }
            }
            return(commandLineOption);
        }
        /**
         * As part of processing a command line, this method scans the (derived) class for all
         * CommandLineOption propertiess.
         */
        protected void InitializeCommandLineOptions()
        {
            PropertyInfo[] properties = this.GetAllProperties(this.GetType());
            foreach (PropertyInfo property in properties)
            {
                CommandLineOption commandLineOption = (CommandLineOption)this.GetPropertyAttribute(property, typeof(CommandLineOption));
                if (commandLineOption != null)
                {
                    // Remember the property so we can assign the value later.
                    this.optionPropertyDict[commandLineOption] = property;

                    // Capture the option
                    this.allOptions.Add(commandLineOption);

                    // Is it optional?
                    if (!commandLineOption.IsTargetOption)
                    {
                        if (commandLineOption.IsRequired)
                        {
                            this.requiredOptions.Add(commandLineOption);
                        }
                        else
                        {
                            this.optionalOptions.Add(commandLineOption);
                        }
                    }

                    // Make special note of the target option, if any
                    if (commandLineOption.IsTargetOption)
                    {
                        if (this.targetCommandLineOption != null)
                        {
                            throw new CommandLineException("Too many target command line options. One is maximum.");
                        }
                        else
                        {
                            this.targetCommandLineOption = commandLineOption;
                        }
                    }
                }
            }

            // Move the target command line option to the end so it's considered last
            if (this.targetCommandLineOption != null)
            {
                this.allOptions.Remove(this.targetCommandLineOption);
                this.allOptions.Add(this.targetCommandLineOption);
            }
        }
        /**
         * Checks the provided command line values for both long and short symbol versions
         * of the given CommandLineOption.
         */
        protected string GetCommandLineOptionValue(CommandLineOption commandLineOption)
        {
            string value = null;

            if (commandLineOption.IsTargetOption)
            {
                value = this.targetValue;
            }
            else if (this.argValDict.ContainsKey(commandLineOption.ShortSymbol.ToString()))
            {
                value = this.argValDict[commandLineOption.ShortSymbol.ToString()];
            }
            else if (this.argValDict.ContainsKey(commandLineOption.LongSymbol))
            {
                value = this.argValDict[commandLineOption.LongSymbol];
            }
            return(value);
        }
        /**
         * Returns true if the given CommandLineOption was present on the actual command line.
         * We need this in addition to GetCommandLineOptionValue() because it returns null
         * for bool values, which is correct; this method, on the other hand, just checks for
         * keys.
         */
        protected bool IsCommandLineOptionPresent(CommandLineOption commandLineOption)
        {
            bool present = false;

            // Is it the target?
            if (commandLineOption.IsTargetOption)
            {
                present = this.targetValue != null;
            }
            // If not the target, then it may have been provided as a keyed argument.
            // Check for both long and short symbols.
            else
            {
                present =
                    this.argValDict.ContainsKey(commandLineOption.ShortSymbol.ToString())
                    ||
                    this.argValDict.ContainsKey(commandLineOption.LongSymbol);
            }
            return(present);
        }
        /**
         * The final step in command line processing, this method will assign the incoming, indexed string arg
         * values to the CommandLineOption properties. A few notes:
         *
         * Boolean flags are either present or not. If present, they are assigned true. If missing, they are assigned false.
         *
         * Keyed values expect a value to follow immediately.
         *
         * Target values always appear last in the command line. There may be only one.
         *
         * There is a case handled here where a command line contains a target value with a boolean flag
         * immediately preceding it. In this case, the regex accepts the target as the value of the boolean
         * flag, which is incorrect. So, there's logic here to tease out the value from the boolean keyed
         * value and treat it as the target. Whew.
         */
        protected void AssignCommandLineOptionValues()
        {
            foreach (CommandLineOption commandLineOption in this.allOptions)
            {
                PropertyInfo property = this.optionPropertyDict[commandLineOption];

                // Is this a bool property? If so, its value is true if the arg is present, false if not.
                if (property.PropertyType == typeof(bool))
                {
                    property.SetValue(this, this.IsCommandLineOptionPresent(commandLineOption), null);
                }

                // Otherwise it's a target or keyed value.
                else
                {
                    bool valueAssigned = false;

                    // Is this the target option?
                    if (commandLineOption.IsTargetOption)
                    {
                        // Assign the target value if we have one
                        if (this.targetValue != null)
                        {
                            this.AssignPropertyValue(property, this.targetValue);
                            valueAssigned = true;
                        }
                        // Target value not set; check the last keyed arg. If bool, the option's value is actually the target.
                        // If the last arg is NOT a bool, then it's a legit keyed argument and the target is just missing.
                        else if (this.lastArgKey != null)
                        {
                            CommandLineOption lastCommandLineOption = this.FindCommandLineOption(lastArgKey);
                            if (
                                lastCommandLineOption != null &&
                                this.optionPropertyDict[lastCommandLineOption].PropertyType == typeof(bool) &&
                                lastArgValue != null
                                )
                            {
                                this.AssignPropertyValue(property, lastArgValue);
                                valueAssigned = true;
                            }
                        }
                    }

                    // If it's a keyed option and it's present, assign it.
                    else if (this.IsCommandLineOptionPresent(commandLineOption))
                    {
                        string value = this.GetCommandLineOptionValue(commandLineOption);
                        this.AssignPropertyValue(property, value);
                        valueAssigned = true;
                    }

                    // A value wasn't assigned (either target or keyed). Deal with required/default values.
                    if (!valueAssigned)
                    {
                        // Gather missing required args
                        if (commandLineOption.IsRequired)
                        {
                            this.missingRequiredCommandLineOptions.Add(commandLineOption);
                        }

                        // Otherwise it's optional, so set the default value
                        else
                        {
                            this.AssignPropertyValue(property, commandLineOption.DefaultValue);
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the ParsingException class with the specified message and
 /// an instance of CommandLineOption that is invalid.
 /// </summary>
 /// <param name="message">The message of this exception.</param>
 /// <param name="option">The option that caused this exception.</param>
 public ParsingException(string message, CommandLineOption option)
     : base(message)
 {
     this.Option = option;
 }