109467b48Spatrick //===- OptTable.cpp - Option Table Implementation -------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
973471bf0Spatrick #include "llvm/Option/OptTable.h"
1009467b48Spatrick #include "llvm/ADT/STLExtras.h"
1109467b48Spatrick #include "llvm/ADT/StringRef.h"
1209467b48Spatrick #include "llvm/Option/Arg.h"
1309467b48Spatrick #include "llvm/Option/ArgList.h"
1409467b48Spatrick #include "llvm/Option/OptSpecifier.h"
1573471bf0Spatrick #include "llvm/Option/Option.h"
1673471bf0Spatrick #include "llvm/Support/CommandLine.h" // for expandResponseFiles
1709467b48Spatrick #include "llvm/Support/Compiler.h"
1809467b48Spatrick #include "llvm/Support/ErrorHandling.h"
1909467b48Spatrick #include "llvm/Support/raw_ostream.h"
2009467b48Spatrick #include <algorithm>
2109467b48Spatrick #include <cassert>
2209467b48Spatrick #include <cctype>
2309467b48Spatrick #include <cstring>
2409467b48Spatrick #include <map>
25*d415bd75Srobert #include <set>
2609467b48Spatrick #include <string>
2709467b48Spatrick #include <utility>
2809467b48Spatrick #include <vector>
2909467b48Spatrick
3009467b48Spatrick using namespace llvm;
3109467b48Spatrick using namespace llvm::opt;
3209467b48Spatrick
3309467b48Spatrick namespace llvm {
3409467b48Spatrick namespace opt {
3509467b48Spatrick
3609467b48Spatrick // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
3709467b48Spatrick // with an exception. '\0' comes at the end of the alphabet instead of the
3809467b48Spatrick // beginning (thus options precede any other options which prefix them).
StrCmpOptionNameIgnoreCase(StringRef A,StringRef B)39*d415bd75Srobert static int StrCmpOptionNameIgnoreCase(StringRef A, StringRef B) {
40*d415bd75Srobert size_t MinSize = std::min(A.size(), B.size());
41*d415bd75Srobert if (int Res = A.substr(0, MinSize).compare_insensitive(B.substr(0, MinSize)))
42*d415bd75Srobert return Res;
43*d415bd75Srobert
44*d415bd75Srobert if (A.size() == B.size())
4509467b48Spatrick return 0;
4609467b48Spatrick
47*d415bd75Srobert return (A.size() == MinSize) ? 1 /* A is a prefix of B. */
48*d415bd75Srobert : -1 /* B is a prefix of A */;
4909467b48Spatrick }
5009467b48Spatrick
5109467b48Spatrick #ifndef NDEBUG
StrCmpOptionName(StringRef A,StringRef B)52*d415bd75Srobert static int StrCmpOptionName(StringRef A, StringRef B) {
5309467b48Spatrick if (int N = StrCmpOptionNameIgnoreCase(A, B))
5409467b48Spatrick return N;
55*d415bd75Srobert return A.compare(B);
5609467b48Spatrick }
5709467b48Spatrick
operator <(const OptTable::Info & A,const OptTable::Info & B)5809467b48Spatrick static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
5909467b48Spatrick if (&A == &B)
6009467b48Spatrick return false;
6109467b48Spatrick
6209467b48Spatrick if (int N = StrCmpOptionName(A.Name, B.Name))
6309467b48Spatrick return N < 0;
6409467b48Spatrick
65*d415bd75Srobert for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size()); I != K;
66*d415bd75Srobert ++I)
67*d415bd75Srobert if (int N = StrCmpOptionName(A.Prefixes[I], B.Prefixes[I]))
6809467b48Spatrick return N < 0;
6909467b48Spatrick
7009467b48Spatrick // Names are the same, check that classes are in order; exactly one
7109467b48Spatrick // should be joined, and it should succeed the other.
7209467b48Spatrick assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
7309467b48Spatrick "Unexpected classes for options with same name.");
7409467b48Spatrick return B.Kind == Option::JoinedClass;
7509467b48Spatrick }
7609467b48Spatrick #endif
7709467b48Spatrick
7809467b48Spatrick // Support lower_bound between info and an option name.
operator <(const OptTable::Info & I,StringRef Name)79*d415bd75Srobert static inline bool operator<(const OptTable::Info &I, StringRef Name) {
8009467b48Spatrick return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0;
8109467b48Spatrick }
8209467b48Spatrick
8309467b48Spatrick } // end namespace opt
8409467b48Spatrick } // end namespace llvm
8509467b48Spatrick
OptSpecifier(const Option * Opt)8609467b48Spatrick OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
8709467b48Spatrick
OptTable(ArrayRef<Info> OptionInfos,bool IgnoreCase)8809467b48Spatrick OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
8909467b48Spatrick : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
9009467b48Spatrick // Explicitly zero initialize the error to work around a bug in array
9109467b48Spatrick // value-initialization on MinGW with gcc 4.3.5.
9209467b48Spatrick
9309467b48Spatrick // Find start of normal options.
9409467b48Spatrick for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
9509467b48Spatrick unsigned Kind = getInfo(i + 1).Kind;
9609467b48Spatrick if (Kind == Option::InputClass) {
97*d415bd75Srobert assert(!InputOptionID && "Cannot have multiple input options!");
98*d415bd75Srobert InputOptionID = getInfo(i + 1).ID;
9909467b48Spatrick } else if (Kind == Option::UnknownClass) {
100*d415bd75Srobert assert(!UnknownOptionID && "Cannot have multiple unknown options!");
101*d415bd75Srobert UnknownOptionID = getInfo(i + 1).ID;
10209467b48Spatrick } else if (Kind != Option::GroupClass) {
10309467b48Spatrick FirstSearchableIndex = i;
10409467b48Spatrick break;
10509467b48Spatrick }
10609467b48Spatrick }
10709467b48Spatrick assert(FirstSearchableIndex != 0 && "No searchable options?");
10809467b48Spatrick
10909467b48Spatrick #ifndef NDEBUG
11009467b48Spatrick // Check that everything after the first searchable option is a
11109467b48Spatrick // regular option class.
11209467b48Spatrick for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
11309467b48Spatrick Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
11409467b48Spatrick assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
11509467b48Spatrick Kind != Option::GroupClass) &&
11609467b48Spatrick "Special options should be defined first!");
11709467b48Spatrick }
11809467b48Spatrick
11909467b48Spatrick // Check that options are in order.
12009467b48Spatrick for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
12109467b48Spatrick if (!(getInfo(i) < getInfo(i + 1))) {
12209467b48Spatrick getOption(i).dump();
12309467b48Spatrick getOption(i + 1).dump();
12409467b48Spatrick llvm_unreachable("Options are not in order!");
12509467b48Spatrick }
12609467b48Spatrick }
12709467b48Spatrick #endif
128*d415bd75Srobert }
12909467b48Spatrick
buildPrefixChars()130*d415bd75Srobert void OptTable::buildPrefixChars() {
131*d415bd75Srobert assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
13209467b48Spatrick
13309467b48Spatrick // Build prefix chars.
134*d415bd75Srobert for (const StringLiteral &Prefix : getPrefixesUnion()) {
135*d415bd75Srobert for (char C : Prefix)
136*d415bd75Srobert if (!is_contained(PrefixChars, C))
137*d415bd75Srobert PrefixChars.push_back(C);
13809467b48Spatrick }
13909467b48Spatrick }
14009467b48Spatrick
14109467b48Spatrick OptTable::~OptTable() = default;
14209467b48Spatrick
getOption(OptSpecifier Opt) const14309467b48Spatrick const Option OptTable::getOption(OptSpecifier Opt) const {
14409467b48Spatrick unsigned id = Opt.getID();
14509467b48Spatrick if (id == 0)
14609467b48Spatrick return Option(nullptr, nullptr);
14709467b48Spatrick assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
14809467b48Spatrick return Option(&getInfo(id), this);
14909467b48Spatrick }
15009467b48Spatrick
isInput(const ArrayRef<StringLiteral> & Prefixes,StringRef Arg)151*d415bd75Srobert static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
15209467b48Spatrick if (Arg == "-")
15309467b48Spatrick return true;
154*d415bd75Srobert for (const StringRef &Prefix : Prefixes)
155*d415bd75Srobert if (Arg.startswith(Prefix))
15609467b48Spatrick return false;
15709467b48Spatrick return true;
15809467b48Spatrick }
15909467b48Spatrick
16009467b48Spatrick /// \returns Matched size. 0 means no match.
matchOption(const OptTable::Info * I,StringRef Str,bool IgnoreCase)16109467b48Spatrick static unsigned matchOption(const OptTable::Info *I, StringRef Str,
16209467b48Spatrick bool IgnoreCase) {
163*d415bd75Srobert for (auto Prefix : I->Prefixes) {
16409467b48Spatrick if (Str.startswith(Prefix)) {
16509467b48Spatrick StringRef Rest = Str.substr(Prefix.size());
16673471bf0Spatrick bool Matched = IgnoreCase ? Rest.startswith_insensitive(I->Name)
16709467b48Spatrick : Rest.startswith(I->Name);
16809467b48Spatrick if (Matched)
16909467b48Spatrick return Prefix.size() + StringRef(I->Name).size();
17009467b48Spatrick }
17109467b48Spatrick }
17209467b48Spatrick return 0;
17309467b48Spatrick }
17409467b48Spatrick
17509467b48Spatrick // Returns true if one of the Prefixes + In.Names matches Option
optionMatches(const OptTable::Info & In,StringRef Option)17609467b48Spatrick static bool optionMatches(const OptTable::Info &In, StringRef Option) {
177*d415bd75Srobert for (auto Prefix : In.Prefixes)
178*d415bd75Srobert if (Option.endswith(In.Name))
179*d415bd75Srobert if (Option.slice(0, Option.size() - In.Name.size()) == Prefix)
18009467b48Spatrick return true;
18109467b48Spatrick return false;
18209467b48Spatrick }
18309467b48Spatrick
18409467b48Spatrick // This function is for flag value completion.
18509467b48Spatrick // Eg. When "-stdlib=" and "l" was passed to this function, it will return
18609467b48Spatrick // appropiriate values for stdlib, which starts with l.
18709467b48Spatrick std::vector<std::string>
suggestValueCompletions(StringRef Option,StringRef Arg) const18809467b48Spatrick OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
18909467b48Spatrick // Search all options and return possible values.
19009467b48Spatrick for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
19109467b48Spatrick const Info &In = OptionInfos[I];
19209467b48Spatrick if (!In.Values || !optionMatches(In, Option))
19309467b48Spatrick continue;
19409467b48Spatrick
19509467b48Spatrick SmallVector<StringRef, 8> Candidates;
19609467b48Spatrick StringRef(In.Values).split(Candidates, ",", -1, false);
19709467b48Spatrick
19809467b48Spatrick std::vector<std::string> Result;
19909467b48Spatrick for (StringRef Val : Candidates)
20009467b48Spatrick if (Val.startswith(Arg) && Arg.compare(Val))
201097a140dSpatrick Result.push_back(std::string(Val));
20209467b48Spatrick return Result;
20309467b48Spatrick }
20409467b48Spatrick return {};
20509467b48Spatrick }
20609467b48Spatrick
20709467b48Spatrick std::vector<std::string>
findByPrefix(StringRef Cur,unsigned int DisableFlags) const20873471bf0Spatrick OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const {
20909467b48Spatrick std::vector<std::string> Ret;
21009467b48Spatrick for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
21109467b48Spatrick const Info &In = OptionInfos[I];
212*d415bd75Srobert if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID))
21309467b48Spatrick continue;
21409467b48Spatrick if (In.Flags & DisableFlags)
21509467b48Spatrick continue;
21609467b48Spatrick
217*d415bd75Srobert for (auto Prefix : In.Prefixes) {
218*d415bd75Srobert std::string S = (Prefix + In.Name + "\t").str();
21909467b48Spatrick if (In.HelpText)
22009467b48Spatrick S += In.HelpText;
22173471bf0Spatrick if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
22209467b48Spatrick Ret.push_back(S);
22309467b48Spatrick }
22409467b48Spatrick }
22509467b48Spatrick return Ret;
22609467b48Spatrick }
22709467b48Spatrick
findNearest(StringRef Option,std::string & NearestString,unsigned FlagsToInclude,unsigned FlagsToExclude,unsigned MinimumLength,unsigned MaximumDistance) const22809467b48Spatrick unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
22909467b48Spatrick unsigned FlagsToInclude, unsigned FlagsToExclude,
230*d415bd75Srobert unsigned MinimumLength,
231*d415bd75Srobert unsigned MaximumDistance) const {
23209467b48Spatrick assert(!Option.empty());
23309467b48Spatrick
23409467b48Spatrick // Consider each [option prefix + option name] pair as a candidate, finding
23509467b48Spatrick // the closest match.
236*d415bd75Srobert unsigned BestDistance =
237*d415bd75Srobert MaximumDistance == UINT_MAX ? UINT_MAX : MaximumDistance + 1;
238*d415bd75Srobert SmallString<16> Candidate;
239*d415bd75Srobert SmallString<16> NormalizedName;
240*d415bd75Srobert
24109467b48Spatrick for (const Info &CandidateInfo :
24209467b48Spatrick ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
24309467b48Spatrick StringRef CandidateName = CandidateInfo.Name;
24409467b48Spatrick
24509467b48Spatrick // We can eliminate some option prefix/name pairs as candidates right away:
24609467b48Spatrick // * Ignore option candidates with empty names, such as "--", or names
24709467b48Spatrick // that do not meet the minimum length.
248*d415bd75Srobert if (CandidateName.size() < MinimumLength)
24909467b48Spatrick continue;
25009467b48Spatrick
25109467b48Spatrick // * If FlagsToInclude were specified, ignore options that don't include
25209467b48Spatrick // those flags.
25309467b48Spatrick if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
25409467b48Spatrick continue;
25509467b48Spatrick // * Ignore options that contain the FlagsToExclude.
25609467b48Spatrick if (CandidateInfo.Flags & FlagsToExclude)
25709467b48Spatrick continue;
25809467b48Spatrick
25909467b48Spatrick // * Ignore positional argument option candidates (which do not
26009467b48Spatrick // have prefixes).
261*d415bd75Srobert if (CandidateInfo.Prefixes.empty())
26209467b48Spatrick continue;
26309467b48Spatrick
26409467b48Spatrick // Now check if the candidate ends with a character commonly used when
26509467b48Spatrick // delimiting an option from its value, such as '=' or ':'. If it does,
26609467b48Spatrick // attempt to split the given option based on that delimiter.
26709467b48Spatrick char Last = CandidateName.back();
26809467b48Spatrick bool CandidateHasDelimiter = Last == '=' || Last == ':';
269*d415bd75Srobert StringRef RHS;
27009467b48Spatrick if (CandidateHasDelimiter) {
271*d415bd75Srobert std::tie(NormalizedName, RHS) = Option.split(Last);
272*d415bd75Srobert if (Option.find(Last) == NormalizedName.size())
27309467b48Spatrick NormalizedName += Last;
274*d415bd75Srobert } else
275*d415bd75Srobert NormalizedName = Option;
27609467b48Spatrick
27709467b48Spatrick // Consider each possible prefix for each candidate to find the most
27809467b48Spatrick // appropriate one. For example, if a user asks for "--helm", suggest
27909467b48Spatrick // "--help" over "-help".
280*d415bd75Srobert for (auto CandidatePrefix : CandidateInfo.Prefixes) {
281*d415bd75Srobert // If Candidate and NormalizedName have more than 'BestDistance'
282*d415bd75Srobert // characters of difference, no need to compute the edit distance, it's
283*d415bd75Srobert // going to be greater than BestDistance. Don't bother computing Candidate
284*d415bd75Srobert // at all.
285*d415bd75Srobert size_t CandidateSize = CandidatePrefix.size() + CandidateName.size(),
286*d415bd75Srobert NormalizedSize = NormalizedName.size();
287*d415bd75Srobert size_t AbsDiff = CandidateSize > NormalizedSize
288*d415bd75Srobert ? CandidateSize - NormalizedSize
289*d415bd75Srobert : NormalizedSize - CandidateSize;
290*d415bd75Srobert if (AbsDiff > BestDistance) {
291*d415bd75Srobert continue;
292*d415bd75Srobert }
293*d415bd75Srobert Candidate = CandidatePrefix;
294*d415bd75Srobert Candidate += CandidateName;
295*d415bd75Srobert unsigned Distance = StringRef(Candidate).edit_distance(
296*d415bd75Srobert NormalizedName, /*AllowReplacements=*/true,
29709467b48Spatrick /*MaxEditDistance=*/BestDistance);
29809467b48Spatrick if (RHS.empty() && CandidateHasDelimiter) {
29909467b48Spatrick // The Candidate ends with a = or : delimiter, but the option passed in
30009467b48Spatrick // didn't contain the delimiter (or doesn't have anything after it).
30109467b48Spatrick // In that case, penalize the correction: `-nodefaultlibs` is more
30209467b48Spatrick // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
30309467b48Spatrick // though both have an unmodified editing distance of 1, since the
30409467b48Spatrick // latter would need an argument.
30509467b48Spatrick ++Distance;
30609467b48Spatrick }
30709467b48Spatrick if (Distance < BestDistance) {
30809467b48Spatrick BestDistance = Distance;
30909467b48Spatrick NearestString = (Candidate + RHS).str();
31009467b48Spatrick }
31109467b48Spatrick }
31209467b48Spatrick }
31309467b48Spatrick return BestDistance;
31409467b48Spatrick }
31509467b48Spatrick
31673471bf0Spatrick // Parse a single argument, return the new argument, and update Index. If
31773471bf0Spatrick // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
31873471bf0Spatrick // be updated to "-bc". This overload does not support
31973471bf0Spatrick // FlagsToInclude/FlagsToExclude or case insensitive options.
parseOneArgGrouped(InputArgList & Args,unsigned & Index) const320*d415bd75Srobert std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
321*d415bd75Srobert unsigned &Index) const {
32273471bf0Spatrick // Anything that doesn't start with PrefixesUnion is an input, as is '-'
32373471bf0Spatrick // itself.
32473471bf0Spatrick const char *CStr = Args.getArgString(Index);
32573471bf0Spatrick StringRef Str(CStr);
326*d415bd75Srobert if (isInput(getPrefixesUnion(), Str))
327*d415bd75Srobert return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
32873471bf0Spatrick
32973471bf0Spatrick const Info *End = OptionInfos.data() + OptionInfos.size();
33073471bf0Spatrick StringRef Name = Str.ltrim(PrefixChars);
331*d415bd75Srobert const Info *Start =
332*d415bd75Srobert std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name);
33373471bf0Spatrick const Info *Fallback = nullptr;
33473471bf0Spatrick unsigned Prev = Index;
33573471bf0Spatrick
33673471bf0Spatrick // Search for the option which matches Str.
33773471bf0Spatrick for (; Start != End; ++Start) {
33873471bf0Spatrick unsigned ArgSize = matchOption(Start, Str, IgnoreCase);
33973471bf0Spatrick if (!ArgSize)
34073471bf0Spatrick continue;
34173471bf0Spatrick
34273471bf0Spatrick Option Opt(Start, this);
343*d415bd75Srobert if (std::unique_ptr<Arg> A =
344*d415bd75Srobert Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
345*d415bd75Srobert /*GroupedShortOption=*/false, Index))
34673471bf0Spatrick return A;
34773471bf0Spatrick
34873471bf0Spatrick // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
34973471bf0Spatrick // the current argument (e.g. "-abc"). Match it as a fallback if no longer
35073471bf0Spatrick // option (e.g. "-ab") exists.
35173471bf0Spatrick if (ArgSize == 2 && Opt.getKind() == Option::FlagClass)
35273471bf0Spatrick Fallback = Start;
35373471bf0Spatrick
35473471bf0Spatrick // Otherwise, see if the argument is missing.
35573471bf0Spatrick if (Prev != Index)
35673471bf0Spatrick return nullptr;
35773471bf0Spatrick }
35873471bf0Spatrick if (Fallback) {
35973471bf0Spatrick Option Opt(Fallback, this);
360*d415bd75Srobert // Check that the last option isn't a flag wrongly given an argument.
361*d415bd75Srobert if (Str[2] == '=')
362*d415bd75Srobert return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
363*d415bd75Srobert CStr);
364*d415bd75Srobert
365*d415bd75Srobert if (std::unique_ptr<Arg> A = Opt.accept(
366*d415bd75Srobert Args, Str.substr(0, 2), /*GroupedShortOption=*/true, Index)) {
36773471bf0Spatrick Args.replaceArgString(Index, Twine('-') + Str.substr(2));
36873471bf0Spatrick return A;
36973471bf0Spatrick }
37073471bf0Spatrick }
37173471bf0Spatrick
372*d415bd75Srobert // In the case of an incorrect short option extract the character and move to
373*d415bd75Srobert // the next one.
374*d415bd75Srobert if (Str[1] != '-') {
375*d415bd75Srobert CStr = Args.MakeArgString(Str.substr(0, 2));
376*d415bd75Srobert Args.replaceArgString(Index, Twine('-') + Str.substr(2));
377*d415bd75Srobert return std::make_unique<Arg>(getOption(UnknownOptionID), CStr, Index, CStr);
37873471bf0Spatrick }
37973471bf0Spatrick
380*d415bd75Srobert return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, CStr);
381*d415bd75Srobert }
382*d415bd75Srobert
ParseOneArg(const ArgList & Args,unsigned & Index,unsigned FlagsToInclude,unsigned FlagsToExclude) const383*d415bd75Srobert std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
38409467b48Spatrick unsigned FlagsToInclude,
38509467b48Spatrick unsigned FlagsToExclude) const {
38609467b48Spatrick unsigned Prev = Index;
387*d415bd75Srobert StringRef Str = Args.getArgString(Index);
38809467b48Spatrick
38909467b48Spatrick // Anything that doesn't start with PrefixesUnion is an input, as is '-'
39009467b48Spatrick // itself.
391*d415bd75Srobert if (isInput(getPrefixesUnion(), Str))
392*d415bd75Srobert return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
393*d415bd75Srobert Str.data());
39409467b48Spatrick
39509467b48Spatrick const Info *Start = OptionInfos.data() + FirstSearchableIndex;
39609467b48Spatrick const Info *End = OptionInfos.data() + OptionInfos.size();
397*d415bd75Srobert StringRef Name = Str.ltrim(PrefixChars);
39809467b48Spatrick
39909467b48Spatrick // Search for the first next option which could be a prefix.
400*d415bd75Srobert Start = std::lower_bound(Start, End, Name);
40109467b48Spatrick
40209467b48Spatrick // Options are stored in sorted order, with '\0' at the end of the
40309467b48Spatrick // alphabet. Since the only options which can accept a string must
40409467b48Spatrick // prefix it, we iteratively search for the next option which could
40509467b48Spatrick // be a prefix.
40609467b48Spatrick //
40709467b48Spatrick // FIXME: This is searching much more than necessary, but I am
40809467b48Spatrick // blanking on the simplest way to make it fast. We can solve this
40909467b48Spatrick // problem when we move to TableGen.
41009467b48Spatrick for (; Start != End; ++Start) {
41109467b48Spatrick unsigned ArgSize = 0;
41209467b48Spatrick // Scan for first option which is a proper prefix.
41309467b48Spatrick for (; Start != End; ++Start)
41409467b48Spatrick if ((ArgSize = matchOption(Start, Str, IgnoreCase)))
41509467b48Spatrick break;
41609467b48Spatrick if (Start == End)
41709467b48Spatrick break;
41809467b48Spatrick
41909467b48Spatrick Option Opt(Start, this);
42009467b48Spatrick
42109467b48Spatrick if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude))
42209467b48Spatrick continue;
42309467b48Spatrick if (Opt.hasFlag(FlagsToExclude))
42409467b48Spatrick continue;
42509467b48Spatrick
42609467b48Spatrick // See if this option matches.
427*d415bd75Srobert if (std::unique_ptr<Arg> A =
428*d415bd75Srobert Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
429*d415bd75Srobert /*GroupedShortOption=*/false, Index))
43009467b48Spatrick return A;
43109467b48Spatrick
43209467b48Spatrick // Otherwise, see if this argument was missing values.
43309467b48Spatrick if (Prev != Index)
43409467b48Spatrick return nullptr;
43509467b48Spatrick }
43609467b48Spatrick
43709467b48Spatrick // If we failed to find an option and this arg started with /, then it's
43809467b48Spatrick // probably an input path.
43909467b48Spatrick if (Str[0] == '/')
440*d415bd75Srobert return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
441*d415bd75Srobert Str.data());
44209467b48Spatrick
443*d415bd75Srobert return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
444*d415bd75Srobert Str.data());
44509467b48Spatrick }
44609467b48Spatrick
ParseArgs(ArrayRef<const char * > ArgArr,unsigned & MissingArgIndex,unsigned & MissingArgCount,unsigned FlagsToInclude,unsigned FlagsToExclude) const44709467b48Spatrick InputArgList OptTable::ParseArgs(ArrayRef<const char *> ArgArr,
44809467b48Spatrick unsigned &MissingArgIndex,
44909467b48Spatrick unsigned &MissingArgCount,
45009467b48Spatrick unsigned FlagsToInclude,
45109467b48Spatrick unsigned FlagsToExclude) const {
45209467b48Spatrick InputArgList Args(ArgArr.begin(), ArgArr.end());
45309467b48Spatrick
45409467b48Spatrick // FIXME: Handle '@' args (or at least error on them).
45509467b48Spatrick
45609467b48Spatrick MissingArgIndex = MissingArgCount = 0;
45709467b48Spatrick unsigned Index = 0, End = ArgArr.size();
45809467b48Spatrick while (Index < End) {
45909467b48Spatrick // Ingore nullptrs, they are response file's EOL markers
46009467b48Spatrick if (Args.getArgString(Index) == nullptr) {
46109467b48Spatrick ++Index;
46209467b48Spatrick continue;
46309467b48Spatrick }
46409467b48Spatrick // Ignore empty arguments (other things may still take them as arguments).
46509467b48Spatrick StringRef Str = Args.getArgString(Index);
46609467b48Spatrick if (Str == "") {
46709467b48Spatrick ++Index;
46809467b48Spatrick continue;
46909467b48Spatrick }
47009467b48Spatrick
47109467b48Spatrick unsigned Prev = Index;
472*d415bd75Srobert std::unique_ptr<Arg> A = GroupedShortOptions
47373471bf0Spatrick ? parseOneArgGrouped(Args, Index)
47473471bf0Spatrick : ParseOneArg(Args, Index, FlagsToInclude, FlagsToExclude);
47573471bf0Spatrick assert((Index > Prev || GroupedShortOptions) &&
47673471bf0Spatrick "Parser failed to consume argument.");
47709467b48Spatrick
47809467b48Spatrick // Check for missing argument error.
47909467b48Spatrick if (!A) {
48009467b48Spatrick assert(Index >= End && "Unexpected parser error.");
48109467b48Spatrick assert(Index - Prev - 1 && "No missing arguments!");
48209467b48Spatrick MissingArgIndex = Prev;
48309467b48Spatrick MissingArgCount = Index - Prev - 1;
48409467b48Spatrick break;
48509467b48Spatrick }
48609467b48Spatrick
487*d415bd75Srobert Args.append(A.release());
48809467b48Spatrick }
48909467b48Spatrick
49009467b48Spatrick return Args;
49109467b48Spatrick }
49209467b48Spatrick
parseArgs(int Argc,char * const * Argv,OptSpecifier Unknown,StringSaver & Saver,function_ref<void (StringRef)> ErrorFn) const49373471bf0Spatrick InputArgList OptTable::parseArgs(int Argc, char *const *Argv,
49473471bf0Spatrick OptSpecifier Unknown, StringSaver &Saver,
49573471bf0Spatrick function_ref<void(StringRef)> ErrorFn) const {
49673471bf0Spatrick SmallVector<const char *, 0> NewArgv;
49773471bf0Spatrick // The environment variable specifies initial options which can be overridden
49873471bf0Spatrick // by commnad line options.
49973471bf0Spatrick cl::expandResponseFiles(Argc, Argv, EnvVar, Saver, NewArgv);
50073471bf0Spatrick
50173471bf0Spatrick unsigned MAI, MAC;
502*d415bd75Srobert opt::InputArgList Args = ParseArgs(ArrayRef(NewArgv), MAI, MAC);
50373471bf0Spatrick if (MAC)
50473471bf0Spatrick ErrorFn((Twine(Args.getArgString(MAI)) + ": missing argument").str());
50573471bf0Spatrick
50673471bf0Spatrick // For each unknwon option, call ErrorFn with a formatted error message. The
50773471bf0Spatrick // message includes a suggested alternative option spelling if available.
50873471bf0Spatrick std::string Nearest;
50973471bf0Spatrick for (const opt::Arg *A : Args.filtered(Unknown)) {
51073471bf0Spatrick std::string Spelling = A->getAsString(Args);
51173471bf0Spatrick if (findNearest(Spelling, Nearest) > 1)
512*d415bd75Srobert ErrorFn("unknown argument '" + Spelling + "'");
51373471bf0Spatrick else
514*d415bd75Srobert ErrorFn("unknown argument '" + Spelling + "', did you mean '" + Nearest +
515*d415bd75Srobert "'?");
51673471bf0Spatrick }
51773471bf0Spatrick return Args;
51873471bf0Spatrick }
51973471bf0Spatrick
getOptionHelpName(const OptTable & Opts,OptSpecifier Id)52009467b48Spatrick static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
52109467b48Spatrick const Option O = Opts.getOption(Id);
52209467b48Spatrick std::string Name = O.getPrefixedName();
52309467b48Spatrick
52409467b48Spatrick // Add metavar, if used.
52509467b48Spatrick switch (O.getKind()) {
52609467b48Spatrick case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
52709467b48Spatrick llvm_unreachable("Invalid option with help text.");
52809467b48Spatrick
52909467b48Spatrick case Option::MultiArgClass:
53009467b48Spatrick if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) {
53109467b48Spatrick // For MultiArgs, metavar is full list of all argument names.
53209467b48Spatrick Name += ' ';
53309467b48Spatrick Name += MetaVarName;
53409467b48Spatrick }
53509467b48Spatrick else {
53609467b48Spatrick // For MultiArgs<N>, if metavar not supplied, print <value> N times.
53709467b48Spatrick for (unsigned i=0, e=O.getNumArgs(); i< e; ++i) {
53809467b48Spatrick Name += " <value>";
53909467b48Spatrick }
54009467b48Spatrick }
54109467b48Spatrick break;
54209467b48Spatrick
54309467b48Spatrick case Option::FlagClass:
54409467b48Spatrick break;
54509467b48Spatrick
54609467b48Spatrick case Option::ValuesClass:
54709467b48Spatrick break;
54809467b48Spatrick
54909467b48Spatrick case Option::SeparateClass: case Option::JoinedOrSeparateClass:
55009467b48Spatrick case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass:
55109467b48Spatrick Name += ' ';
552*d415bd75Srobert [[fallthrough]];
55309467b48Spatrick case Option::JoinedClass: case Option::CommaJoinedClass:
55409467b48Spatrick case Option::JoinedAndSeparateClass:
55509467b48Spatrick if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
55609467b48Spatrick Name += MetaVarName;
55709467b48Spatrick else
55809467b48Spatrick Name += "<value>";
55909467b48Spatrick break;
56009467b48Spatrick }
56109467b48Spatrick
56209467b48Spatrick return Name;
56309467b48Spatrick }
56409467b48Spatrick
56509467b48Spatrick namespace {
56609467b48Spatrick struct OptionInfo {
56709467b48Spatrick std::string Name;
56809467b48Spatrick StringRef HelpText;
56909467b48Spatrick };
57009467b48Spatrick } // namespace
57109467b48Spatrick
PrintHelpOptionList(raw_ostream & OS,StringRef Title,std::vector<OptionInfo> & OptionHelp)57209467b48Spatrick static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
57309467b48Spatrick std::vector<OptionInfo> &OptionHelp) {
57409467b48Spatrick OS << Title << ":\n";
57509467b48Spatrick
57609467b48Spatrick // Find the maximum option length.
57709467b48Spatrick unsigned OptionFieldWidth = 0;
578*d415bd75Srobert for (const OptionInfo &Opt : OptionHelp) {
57909467b48Spatrick // Limit the amount of padding we are willing to give up for alignment.
580*d415bd75Srobert unsigned Length = Opt.Name.size();
58109467b48Spatrick if (Length <= 23)
58209467b48Spatrick OptionFieldWidth = std::max(OptionFieldWidth, Length);
58309467b48Spatrick }
58409467b48Spatrick
58509467b48Spatrick const unsigned InitialPad = 2;
586*d415bd75Srobert for (const OptionInfo &Opt : OptionHelp) {
587*d415bd75Srobert const std::string &Option = Opt.Name;
58809467b48Spatrick int Pad = OptionFieldWidth - int(Option.size());
58909467b48Spatrick OS.indent(InitialPad) << Option;
59009467b48Spatrick
59109467b48Spatrick // Break on long option names.
59209467b48Spatrick if (Pad < 0) {
59309467b48Spatrick OS << "\n";
59409467b48Spatrick Pad = OptionFieldWidth + InitialPad;
59509467b48Spatrick }
596*d415bd75Srobert OS.indent(Pad + 1) << Opt.HelpText << '\n';
59709467b48Spatrick }
59809467b48Spatrick }
59909467b48Spatrick
getOptionHelpGroup(const OptTable & Opts,OptSpecifier Id)60009467b48Spatrick static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
60109467b48Spatrick unsigned GroupID = Opts.getOptionGroupID(Id);
60209467b48Spatrick
60309467b48Spatrick // If not in a group, return the default help group.
60409467b48Spatrick if (!GroupID)
60509467b48Spatrick return "OPTIONS";
60609467b48Spatrick
60709467b48Spatrick // Abuse the help text of the option groups to store the "help group"
60809467b48Spatrick // name.
60909467b48Spatrick //
61009467b48Spatrick // FIXME: Split out option groups.
61109467b48Spatrick if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
61209467b48Spatrick return GroupHelp;
61309467b48Spatrick
61409467b48Spatrick // Otherwise keep looking.
61509467b48Spatrick return getOptionHelpGroup(Opts, GroupID);
61609467b48Spatrick }
61709467b48Spatrick
printHelp(raw_ostream & OS,const char * Usage,const char * Title,bool ShowHidden,bool ShowAllAliases) const61873471bf0Spatrick void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
61909467b48Spatrick bool ShowHidden, bool ShowAllAliases) const {
62073471bf0Spatrick printHelp(OS, Usage, Title, /*Include*/ 0, /*Exclude*/
62109467b48Spatrick (ShowHidden ? 0 : HelpHidden), ShowAllAliases);
62209467b48Spatrick }
62309467b48Spatrick
printHelp(raw_ostream & OS,const char * Usage,const char * Title,unsigned FlagsToInclude,unsigned FlagsToExclude,bool ShowAllAliases) const62473471bf0Spatrick void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
62509467b48Spatrick unsigned FlagsToInclude, unsigned FlagsToExclude,
62609467b48Spatrick bool ShowAllAliases) const {
62709467b48Spatrick OS << "OVERVIEW: " << Title << "\n\n";
62809467b48Spatrick OS << "USAGE: " << Usage << "\n\n";
62909467b48Spatrick
63009467b48Spatrick // Render help text into a map of group-name to a list of (option, help)
63109467b48Spatrick // pairs.
63209467b48Spatrick std::map<std::string, std::vector<OptionInfo>> GroupedOptionHelp;
63309467b48Spatrick
63409467b48Spatrick for (unsigned Id = 1, e = getNumOptions() + 1; Id != e; ++Id) {
63509467b48Spatrick // FIXME: Split out option groups.
63609467b48Spatrick if (getOptionKind(Id) == Option::GroupClass)
63709467b48Spatrick continue;
63809467b48Spatrick
63909467b48Spatrick unsigned Flags = getInfo(Id).Flags;
64009467b48Spatrick if (FlagsToInclude && !(Flags & FlagsToInclude))
64109467b48Spatrick continue;
64209467b48Spatrick if (Flags & FlagsToExclude)
64309467b48Spatrick continue;
64409467b48Spatrick
64509467b48Spatrick // If an alias doesn't have a help text, show a help text for the aliased
64609467b48Spatrick // option instead.
64709467b48Spatrick const char *HelpText = getOptionHelpText(Id);
64809467b48Spatrick if (!HelpText && ShowAllAliases) {
64909467b48Spatrick const Option Alias = getOption(Id).getAlias();
65009467b48Spatrick if (Alias.isValid())
65109467b48Spatrick HelpText = getOptionHelpText(Alias.getID());
65209467b48Spatrick }
65309467b48Spatrick
654*d415bd75Srobert if (HelpText && (strlen(HelpText) != 0)) {
65509467b48Spatrick const char *HelpGroup = getOptionHelpGroup(*this, Id);
65609467b48Spatrick const std::string &OptName = getOptionHelpName(*this, Id);
65709467b48Spatrick GroupedOptionHelp[HelpGroup].push_back({OptName, HelpText});
65809467b48Spatrick }
65909467b48Spatrick }
66009467b48Spatrick
66109467b48Spatrick for (auto& OptionGroup : GroupedOptionHelp) {
66209467b48Spatrick if (OptionGroup.first != GroupedOptionHelp.begin()->first)
66309467b48Spatrick OS << "\n";
66409467b48Spatrick PrintHelpOptionList(OS, OptionGroup.first, OptionGroup.second);
66509467b48Spatrick }
66609467b48Spatrick
66709467b48Spatrick OS.flush();
66809467b48Spatrick }
669*d415bd75Srobert
GenericOptTable(ArrayRef<Info> OptionInfos,bool IgnoreCase)670*d415bd75Srobert GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
671*d415bd75Srobert : OptTable(OptionInfos, IgnoreCase) {
672*d415bd75Srobert
673*d415bd75Srobert std::set<StringLiteral> TmpPrefixesUnion;
674*d415bd75Srobert for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
675*d415bd75Srobert TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end());
676*d415bd75Srobert PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
677*d415bd75Srobert buildPrefixChars();
678*d415bd75Srobert }
679