124d58133SDimitry Andric //===- Option.cpp - Abstract Driver Options -------------------------------===// 2139f7f9bSDimitry Andric // 3139f7f9bSDimitry Andric // The LLVM Compiler Infrastructure 4139f7f9bSDimitry Andric // 5139f7f9bSDimitry Andric // This file is distributed under the University of Illinois Open Source 6139f7f9bSDimitry Andric // License. See LICENSE.TXT for details. 7139f7f9bSDimitry Andric // 8139f7f9bSDimitry Andric //===----------------------------------------------------------------------===// 9139f7f9bSDimitry Andric 1024d58133SDimitry Andric #include "llvm/ADT/StringRef.h" 11139f7f9bSDimitry Andric #include "llvm/ADT/Twine.h" 12139f7f9bSDimitry Andric #include "llvm/Option/Arg.h" 13139f7f9bSDimitry Andric #include "llvm/Option/ArgList.h" 1424d58133SDimitry Andric #include "llvm/Option/Option.h" 1524d58133SDimitry Andric #include "llvm/Option/OptTable.h" 1624d58133SDimitry Andric #include "llvm/Support/Compiler.h" 177d523365SDimitry Andric #include "llvm/Support/Debug.h" 18139f7f9bSDimitry Andric #include "llvm/Support/ErrorHandling.h" 19139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h" 20139f7f9bSDimitry Andric #include <cassert> 2124d58133SDimitry Andric #include <cstring> 22139f7f9bSDimitry Andric 23139f7f9bSDimitry Andric using namespace llvm; 24139f7f9bSDimitry Andric using namespace llvm::opt; 25139f7f9bSDimitry Andric 26139f7f9bSDimitry Andric Option::Option(const OptTable::Info *info, const OptTable *owner) 27139f7f9bSDimitry Andric : Info(info), Owner(owner) { 28f785676fSDimitry Andric // Multi-level aliases are not supported. This just simplifies option 29f785676fSDimitry Andric // tracking, it is not an inherent limitation. 30f785676fSDimitry Andric assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && 31f785676fSDimitry Andric "Multi-level aliases are not supported."); 32f785676fSDimitry Andric 33f785676fSDimitry Andric if (Info && getAliasArgs()) { 34f785676fSDimitry Andric assert(getAlias().isValid() && "Only alias options can have alias args."); 35f785676fSDimitry Andric assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); 36f785676fSDimitry Andric assert(getAlias().getKind() != FlagClass && 37f785676fSDimitry Andric "Cannot provide alias args to a flag option."); 38f785676fSDimitry Andric } 39139f7f9bSDimitry Andric } 40139f7f9bSDimitry Andric 417d523365SDimitry Andric void Option::print(raw_ostream &O) const { 427d523365SDimitry Andric O << "<"; 43139f7f9bSDimitry Andric switch (getKind()) { 447d523365SDimitry Andric #define P(N) case N: O << #N; break 45139f7f9bSDimitry Andric P(GroupClass); 46139f7f9bSDimitry Andric P(InputClass); 47139f7f9bSDimitry Andric P(UnknownClass); 48139f7f9bSDimitry Andric P(FlagClass); 49139f7f9bSDimitry Andric P(JoinedClass); 50edd7eaddSDimitry Andric P(ValuesClass); 51139f7f9bSDimitry Andric P(SeparateClass); 52139f7f9bSDimitry Andric P(CommaJoinedClass); 53139f7f9bSDimitry Andric P(MultiArgClass); 54139f7f9bSDimitry Andric P(JoinedOrSeparateClass); 55139f7f9bSDimitry Andric P(JoinedAndSeparateClass); 56f785676fSDimitry Andric P(RemainingArgsClass); 573ca95b02SDimitry Andric P(RemainingArgsJoinedClass); 58139f7f9bSDimitry Andric #undef P 59139f7f9bSDimitry Andric } 60139f7f9bSDimitry Andric 61f785676fSDimitry Andric if (Info->Prefixes) { 627d523365SDimitry Andric O << " Prefixes:["; 6391bc56edSDimitry Andric for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 647d523365SDimitry Andric O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 65139f7f9bSDimitry Andric } 667d523365SDimitry Andric O << ']'; 67f785676fSDimitry Andric } 68139f7f9bSDimitry Andric 697d523365SDimitry Andric O << " Name:\"" << getName() << '"'; 70139f7f9bSDimitry Andric 71139f7f9bSDimitry Andric const Option Group = getGroup(); 72139f7f9bSDimitry Andric if (Group.isValid()) { 737d523365SDimitry Andric O << " Group:"; 747d523365SDimitry Andric Group.print(O); 75139f7f9bSDimitry Andric } 76139f7f9bSDimitry Andric 77139f7f9bSDimitry Andric const Option Alias = getAlias(); 78139f7f9bSDimitry Andric if (Alias.isValid()) { 797d523365SDimitry Andric O << " Alias:"; 807d523365SDimitry Andric Alias.print(O); 81139f7f9bSDimitry Andric } 82139f7f9bSDimitry Andric 83139f7f9bSDimitry Andric if (getKind() == MultiArgClass) 847d523365SDimitry Andric O << " NumArgs:" << getNumArgs(); 85139f7f9bSDimitry Andric 867d523365SDimitry Andric O << ">\n"; 87139f7f9bSDimitry Andric } 88139f7f9bSDimitry Andric 897a7e6055SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 903ca95b02SDimitry Andric LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); } 917a7e6055SDimitry Andric #endif 927d523365SDimitry Andric 93139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const { 94139f7f9bSDimitry Andric // Aliases are never considered in matching, look through them. 95139f7f9bSDimitry Andric const Option Alias = getAlias(); 96139f7f9bSDimitry Andric if (Alias.isValid()) 97139f7f9bSDimitry Andric return Alias.matches(Opt); 98139f7f9bSDimitry Andric 99139f7f9bSDimitry Andric // Check exact match. 100139f7f9bSDimitry Andric if (getID() == Opt.getID()) 101139f7f9bSDimitry Andric return true; 102139f7f9bSDimitry Andric 103139f7f9bSDimitry Andric const Option Group = getGroup(); 104139f7f9bSDimitry Andric if (Group.isValid()) 105139f7f9bSDimitry Andric return Group.matches(Opt); 106139f7f9bSDimitry Andric return false; 107139f7f9bSDimitry Andric } 108139f7f9bSDimitry Andric 109139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args, 110139f7f9bSDimitry Andric unsigned &Index, 111139f7f9bSDimitry Andric unsigned ArgSize) const { 112139f7f9bSDimitry Andric const Option &UnaliasedOption = getUnaliasedOption(); 113139f7f9bSDimitry Andric StringRef Spelling; 114139f7f9bSDimitry Andric // If the option was an alias, get the spelling from the unaliased one. 115139f7f9bSDimitry Andric if (getID() == UnaliasedOption.getID()) { 116139f7f9bSDimitry Andric Spelling = StringRef(Args.getArgString(Index), ArgSize); 117139f7f9bSDimitry Andric } else { 118139f7f9bSDimitry Andric Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + 119139f7f9bSDimitry Andric Twine(UnaliasedOption.getName())); 120139f7f9bSDimitry Andric } 121139f7f9bSDimitry Andric 122139f7f9bSDimitry Andric switch (getKind()) { 123f785676fSDimitry Andric case FlagClass: { 124139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 12591bc56edSDimitry Andric return nullptr; 126139f7f9bSDimitry Andric 127f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 128f785676fSDimitry Andric if (getAliasArgs()) { 129f785676fSDimitry Andric const char *Val = getAliasArgs(); 130f785676fSDimitry Andric while (*Val != '\0') { 131f785676fSDimitry Andric A->getValues().push_back(Val); 132f785676fSDimitry Andric 133f785676fSDimitry Andric // Move past the '\0' to the next argument. 134f785676fSDimitry Andric Val += strlen(Val) + 1; 135f785676fSDimitry Andric } 136f785676fSDimitry Andric } 137ff0cc061SDimitry Andric 138ff0cc061SDimitry Andric if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) 139ff0cc061SDimitry Andric // A Flag alias for a Joined option must provide an argument. 140ff0cc061SDimitry Andric A->getValues().push_back(""); 141ff0cc061SDimitry Andric 142f785676fSDimitry Andric return A; 143f785676fSDimitry Andric } 144139f7f9bSDimitry Andric case JoinedClass: { 145139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 146139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index++, Value); 147139f7f9bSDimitry Andric } 148139f7f9bSDimitry Andric case CommaJoinedClass: { 149139f7f9bSDimitry Andric // Always matches. 150139f7f9bSDimitry Andric const char *Str = Args.getArgString(Index) + ArgSize; 151139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 152139f7f9bSDimitry Andric 153139f7f9bSDimitry Andric // Parse out the comma separated values. 154139f7f9bSDimitry Andric const char *Prev = Str; 155139f7f9bSDimitry Andric for (;; ++Str) { 156139f7f9bSDimitry Andric char c = *Str; 157139f7f9bSDimitry Andric 158139f7f9bSDimitry Andric if (!c || c == ',') { 159139f7f9bSDimitry Andric if (Prev != Str) { 160139f7f9bSDimitry Andric char *Value = new char[Str - Prev + 1]; 161139f7f9bSDimitry Andric memcpy(Value, Prev, Str - Prev); 162139f7f9bSDimitry Andric Value[Str - Prev] = '\0'; 163139f7f9bSDimitry Andric A->getValues().push_back(Value); 164139f7f9bSDimitry Andric } 165139f7f9bSDimitry Andric 166139f7f9bSDimitry Andric if (!c) 167139f7f9bSDimitry Andric break; 168139f7f9bSDimitry Andric 169139f7f9bSDimitry Andric Prev = Str + 1; 170139f7f9bSDimitry Andric } 171139f7f9bSDimitry Andric } 172139f7f9bSDimitry Andric A->setOwnsValues(true); 173139f7f9bSDimitry Andric 174139f7f9bSDimitry Andric return A; 175139f7f9bSDimitry Andric } 176139f7f9bSDimitry Andric case SeparateClass: 177139f7f9bSDimitry Andric // Matches iff this is an exact match. 178139f7f9bSDimitry Andric // FIXME: Avoid strlen. 179139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 18091bc56edSDimitry Andric return nullptr; 181139f7f9bSDimitry Andric 182139f7f9bSDimitry Andric Index += 2; 18339d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 18439d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 18591bc56edSDimitry Andric return nullptr; 186139f7f9bSDimitry Andric 187139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 188139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 189139f7f9bSDimitry Andric case MultiArgClass: { 190139f7f9bSDimitry Andric // Matches iff this is an exact match. 191139f7f9bSDimitry Andric // FIXME: Avoid strlen. 192139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 19391bc56edSDimitry Andric return nullptr; 194139f7f9bSDimitry Andric 195139f7f9bSDimitry Andric Index += 1 + getNumArgs(); 196139f7f9bSDimitry Andric if (Index > Args.getNumInputArgStrings()) 19791bc56edSDimitry Andric return nullptr; 198139f7f9bSDimitry Andric 199139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 200139f7f9bSDimitry Andric Args.getArgString(Index - getNumArgs())); 201139f7f9bSDimitry Andric for (unsigned i = 1; i != getNumArgs(); ++i) 202139f7f9bSDimitry Andric A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 203139f7f9bSDimitry Andric return A; 204139f7f9bSDimitry Andric } 205139f7f9bSDimitry Andric case JoinedOrSeparateClass: { 206139f7f9bSDimitry Andric // If this is not an exact match, it is a joined arg. 207139f7f9bSDimitry Andric // FIXME: Avoid strlen. 208139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 209139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 210139f7f9bSDimitry Andric return new Arg(*this, Spelling, Index++, Value); 211139f7f9bSDimitry Andric } 212139f7f9bSDimitry Andric 213139f7f9bSDimitry Andric // Otherwise it must be separate. 214139f7f9bSDimitry Andric Index += 2; 21539d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 21639d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 21791bc56edSDimitry Andric return nullptr; 218139f7f9bSDimitry Andric 219139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 220139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 221139f7f9bSDimitry Andric } 222139f7f9bSDimitry Andric case JoinedAndSeparateClass: 223139f7f9bSDimitry Andric // Always matches. 224139f7f9bSDimitry Andric Index += 2; 22539d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 22639d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 22791bc56edSDimitry Andric return nullptr; 228139f7f9bSDimitry Andric 229139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index - 2, 230139f7f9bSDimitry Andric Args.getArgString(Index - 2) + ArgSize, 231139f7f9bSDimitry Andric Args.getArgString(Index - 1)); 232f785676fSDimitry Andric case RemainingArgsClass: { 233f785676fSDimitry Andric // Matches iff this is an exact match. 234f785676fSDimitry Andric // FIXME: Avoid strlen. 235f785676fSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 23691bc56edSDimitry Andric return nullptr; 237f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 23839d628a0SDimitry Andric while (Index < Args.getNumInputArgStrings() && 23939d628a0SDimitry Andric Args.getArgString(Index) != nullptr) 240f785676fSDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 241f785676fSDimitry Andric return A; 242f785676fSDimitry Andric } 2433ca95b02SDimitry Andric case RemainingArgsJoinedClass: { 2443ca95b02SDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index); 2453ca95b02SDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 2463ca95b02SDimitry Andric // An inexact match means there is a joined arg. 2473ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index) + ArgSize); 2483ca95b02SDimitry Andric } 2493ca95b02SDimitry Andric Index++; 2503ca95b02SDimitry Andric while (Index < Args.getNumInputArgStrings() && 2513ca95b02SDimitry Andric Args.getArgString(Index) != nullptr) 2523ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 2533ca95b02SDimitry Andric return A; 2543ca95b02SDimitry Andric } 2553ca95b02SDimitry Andric 256139f7f9bSDimitry Andric default: 257139f7f9bSDimitry Andric llvm_unreachable("Invalid option kind!"); 258139f7f9bSDimitry Andric } 259139f7f9bSDimitry Andric } 260