/// \brief Parse a single argument; returning the new argument and
        /// updating Index.
        ///
        /// \param [in,out] Index - The current parsing position in the argument
        /// string list; on return this will be the index of the next argument
        /// string to parse.
        /// \param [in] FlagsToInclude - Only parse options with any of these flags.
        /// Zero is the default which includes all flags.
        /// \param [in] FlagsToExclude - Don't parse options with this flag.  Zero
        /// is the default and means exclude nothing.
        ///
        /// <returns>The parsed argument, or 0 if the argument is missing values (in which case Index still points at the conceptual next argument string to parse).</returns>
        public Argument ParseOneArg(ArgumentList args,
                                    ref int index,
                                    int flagsToInclude = 0,
                                    int flagsToExclude = 0)
        {
            int    prev = index;
            string str  = args.GetArgString(index);

            // Anything that doesn't start with PrefixesUnion is an input, as is '-'
            // itself.
            if (IsInput(_prefixesUnion,
                        str))
            {
                return(new Argument(GetOption(_theInputOptionId),
                                    str,
                                    index++,
                                    str));
            }

            IEnumerable <OptionInfo> startEnd = _optionInfos.Skip(_firstSearchableIndex);

            string name = string.Concat(str.SkipWhile(item => _prefixChars.Any(chars => chars == item)));

            // Search for the first next option which could be a prefix.
            startEnd = startEnd.SkipWhile(item => !name.StartsWith(item.Name.ToString(),
                                                                   StringComparison.InvariantCultureIgnoreCase));

            // Options are stored in sorted order, with '\0' at the end of the
            // alphabet. Since the only options which can accept a string must
            // prefix it, we iteratively search for the next option which could
            // be a prefix.
            //
            // FIXME: This is searching much more than necessary, but I am
            // blanking on the simplest way to make it fast. We can solve this
            // problem when we move to TableGen.

            // Scan for first option which is a proper prefix.
            int i         = 0;
            var startList = startEnd.ToList();

            for (; i < startList.Count; i++)
            {
                int argSize = 0;

                // Scan for first option which is a proper prefix.
                for (; i < startList.Count; i++)
                {
                    argSize = MatchOption(startList[i],
                                          str,
                                          _ignoreCase);
                    if (argSize > 0)
                    {
                        break;
                    }
                }

                if (i == startList.Count)
                {
                    break;
                }

                Option opt = new Option(startList[i],
                                        this);

                if (flagsToInclude != 0 && !opt.HasFlag(flagsToInclude))
                {
                    continue;
                }

                if (opt.HasFlag(flagsToExclude))
                {
                    continue;
                }

                // See if this option matches.
                Argument a = opt.Accept(args,
                                        ref index,
                                        argSize);
                if (a != null)
                {
                    return(a);
                }

                // Otherwise, see if this argument was missing values.
                if (prev != index)
                {
                    return(null);
                }
            }

            // If we failed to find an option and this arg started with /, then it's
            // probably an input path.
            if (str[0] == '/')
            {
                return(new Argument(GetOption(_theInputOptionId),
                                    str,
                                    index++,
                                    str));
            }

            return(new Argument(GetOption(_theUnknownOptionId),
                                str,
                                index++,
                                str));
        }
Exemple #2
0
        /// accept - Potentially accept the current argument, returning a
        /// new Argument instance, or 0 if the option does not accept this
        /// argument (or the argument is missing values).
        ///
        /// If the option accepts the current argument, accept() sets
        /// Index to the position where argument parsing should resume
        /// (even if the argument is missing values).
        ///
        /// \param ArgSize The number of bytes taken up by the matched Option prefix
        /// and name. This is used to determine where joined values
        /// start.
        public Argument Accept(ArgumentList args,
                               ref int index,
                               int argSize)
        {
            var    unaliasedOption = GetUnaliasedOption();
            string spelling;

            // If the option was an alias, get the spelling from the unaliased one.
            if (GetId() == unaliasedOption.GetId())
            {
                spelling = args.GetArgString(index).Substring(0,
                                                              argSize);
            }
            else
            {
                spelling = args.MakeArgString(unaliasedOption.GetPrefix() + unaliasedOption.GetName());
            }

            var kind = GetKind();

            if (kind == OptionKind.FlagClass)
            {
                if (argSize != args.GetArgString(index).Length)
                {
                    return(null);
                }

                var a = new Argument(unaliasedOption,
                                     spelling,
                                     index++);

                if (!string.IsNullOrEmpty(GetAliasArgs()))
                {
                    var vals = GetAliasArgs().Split(new[] { " " },
                                                    StringSplitOptions.RemoveEmptyEntries);

                    a.GetValues().AddRange(vals.Select(item => item));

                    //while (*Val != '\0')
                    //{
                    //    A.getValues().AddRange(Val);

                    //    // Move past the '\0' to the next argument.
                    //    Val += Val.Length + 1;
                    //}
                }

                if (unaliasedOption.GetKind() == OptionKind.JoinedClass &&
                    string.IsNullOrEmpty(GetAliasArgs()))
                {
                    a.GetValues().Add(string.Empty);
                }

                return(a);
            }
            else if (kind == OptionKind.JoinedClass)
            {
                string value = args.GetArgString(index).Substring(argSize);
                return(new Argument(unaliasedOption,
                                    spelling,
                                    index++,
                                    value));
            }
            else if (kind == OptionKind.CommaJoinedClass)
            {
                // Always matches.
                var str = args.GetArgString(index).Substring(argSize).
                          Split(new[] { ',' },
                                StringSplitOptions.RemoveEmptyEntries);      // + ArgSize;

                var a = new Argument(unaliasedOption,
                                     spelling,
                                     index++);

                a.GetValues().AddRange(str.Select(item => item));

                a.SetOwnsValues(true);

                return(a);
            }
            else if (kind == OptionKind.SeparateClass)
            {
                // Matches iff this is an exact match.
                // FIXME: Avoid strlen.
                if (argSize != args.GetArgString(index).Length)
                {
                    return(null);
                }

                index += 2;
                if (index > args.GetNumInputArgStrings() ||
                    args.GetArgString(index - 1) == null)
                {
                    return(null);
                }

                return(new Argument(unaliasedOption,
                                    spelling,
                                    index - 2,
                                    args.GetArgString(index - 1)));
            }
            else if (kind == OptionKind.MultiArgClass)
            {
                // Matches iff this is an exact match.
                // FIXME: Avoid strlen.
                if (argSize != args.GetArgString(index).Length)
                {
                    return(null);
                }

                index += 1 + GetNumArgs();
                if (index > args.GetNumInputArgStrings())
                {
                    return(null);
                }

                var a = new Argument(unaliasedOption,
                                     spelling,
                                     index - 1 - GetNumArgs(),
                                     args.GetArgString(index - GetNumArgs()));
                for (var i = 1; i != GetNumArgs(); ++i)
                {
                    a.GetValues().Add(args.GetArgString(index - GetNumArgs() + i));
                }

                return(a);
            }
            else if (kind == OptionKind.JoinedOrSeparateClass)
            {
                // If this is not an exact match, it is a joined arg.
                // FIXME: Avoid strlen.
                if (argSize != args.GetArgString(index).Length)
                {
                    var value = args.GetArgString(index).Substring(argSize);
                    return(new Argument(this,
                                        spelling,
                                        index++,
                                        value));
                }

                // Otherwise it must be separate.
                index += 2;
                if (index > args.GetNumInputArgStrings() ||
                    args.GetArgString(index - 1) == null)
                {
                    return(null);
                }

                return(new Argument(unaliasedOption,
                                    spelling,
                                    index - 2,
                                    args.GetArgString(index - 1)));
            }
            else if (kind == OptionKind.JoinedAndSeparateClass)
            {
                // Always matches.
                index += 2;
                if (index > args.GetNumInputArgStrings() ||
                    args.GetArgString(index - 1) == null)
                {
                    return(null);
                }

                return(new Argument(unaliasedOption,
                                    spelling,
                                    index - 2,
                                    args.GetArgString(index - 2).Substring(argSize),
                                    args.GetArgString(index - 1)));
            }
            else if (kind == OptionKind.RemainingArgsClass)
            {
                // Matches iff this is an exact match.
                // FIXME: Avoid strlen.
                if (argSize != args.GetArgString(index).Length)
                {
                    return(null);
                }

                var a = new Argument(unaliasedOption,
                                     spelling,
                                     index++);
                while (index < args.GetNumInputArgStrings() &&
                       args.GetArgString(index) != null)
                {
                    a.GetValues().Add(args.GetArgString(index++));
                }

                return(a);
            }
            else if (kind == OptionKind.RemainingArgsJoinedClass)
            {
                var a = new Argument(unaliasedOption,
                                     spelling,
                                     index);
                if (argSize != args.GetArgString(index).Length)
                {
                    a.GetValues().Add(args.GetArgString(index).Substring(argSize));
                }

                index++;
                while (index < args.GetNumInputArgStrings() &&
                       args.GetArgString(index) != null)
                {
                    a.GetValues().Add(args.GetArgString(index++));
                }

                return(a);
            }

            throw new Exception("Invalid option kind!");
        }