1139f7f9bSDimitry 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 10139f7f9bSDimitry Andric #include "llvm/Option/Option.h" 11139f7f9bSDimitry Andric #include "llvm/ADT/Twine.h" 12139f7f9bSDimitry Andric #include "llvm/Option/Arg.h" 13139f7f9bSDimitry Andric #include "llvm/Option/ArgList.h" 14139f7f9bSDimitry Andric #include "llvm/Support/ErrorHandling.h" 15139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h" 16139f7f9bSDimitry Andric #include <algorithm> 17139f7f9bSDimitry Andric #include <cassert> 18139f7f9bSDimitry Andric 19139f7f9bSDimitry Andric using namespace llvm; 20139f7f9bSDimitry Andric using namespace llvm::opt; 21139f7f9bSDimitry Andric 22139f7f9bSDimitry Andric Option::Option(const OptTable::Info *info, const OptTable *owner) 23139f7f9bSDimitry Andric : Info(info), Owner(owner) { 24139f7f9bSDimitry Andric 25f785676fSDimitry Andric // Multi-level aliases are not supported. This just simplifies option 26f785676fSDimitry Andric // tracking, it is not an inherent limitation. 27f785676fSDimitry Andric assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && 28f785676fSDimitry Andric "Multi-level aliases are not supported."); 29f785676fSDimitry Andric 30f785676fSDimitry Andric if (Info && getAliasArgs()) { 31f785676fSDimitry Andric assert(getAlias().isValid() && "Only alias options can have alias args."); 32f785676fSDimitry Andric assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); 33f785676fSDimitry Andric assert(getAlias().getKind() != FlagClass && 34f785676fSDimitry Andric "Cannot provide alias args to a flag option."); 35f785676fSDimitry Andric } 36139f7f9bSDimitry Andric } 37139f7f9bSDimitry Andric 38139f7f9bSDimitry Andric Option::~Option() { 39139f7f9bSDimitry Andric } 40139f7f9bSDimitry Andric 41139f7f9bSDimitry Andric void Option::dump() const { 42139f7f9bSDimitry Andric llvm::errs() << "<"; 43139f7f9bSDimitry Andric switch (getKind()) { 44139f7f9bSDimitry Andric #define P(N) case N: llvm::errs() << #N; break 45139f7f9bSDimitry Andric P(GroupClass); 46139f7f9bSDimitry Andric P(InputClass); 47139f7f9bSDimitry Andric P(UnknownClass); 48139f7f9bSDimitry Andric P(FlagClass); 49139f7f9bSDimitry Andric P(JoinedClass); 50139f7f9bSDimitry Andric P(SeparateClass); 51139f7f9bSDimitry Andric P(CommaJoinedClass); 52139f7f9bSDimitry Andric P(MultiArgClass); 53139f7f9bSDimitry Andric P(JoinedOrSeparateClass); 54139f7f9bSDimitry Andric P(JoinedAndSeparateClass); 55f785676fSDimitry Andric P(RemainingArgsClass); 56139f7f9bSDimitry Andric #undef P 57139f7f9bSDimitry Andric } 58139f7f9bSDimitry Andric 59f785676fSDimitry Andric if (Info->Prefixes) { 60139f7f9bSDimitry Andric llvm::errs() << " Prefixes:["; 6191bc56edSDimitry Andric for (const char * const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 6291bc56edSDimitry Andric llvm::errs() << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 63139f7f9bSDimitry Andric } 64139f7f9bSDimitry Andric llvm::errs() << ']'; 65f785676fSDimitry Andric } 66139f7f9bSDimitry Andric 67139f7f9bSDimitry Andric llvm::errs() << " Name:\"" << getName() << '"'; 68139f7f9bSDimitry Andric 69139f7f9bSDimitry Andric const Option Group = getGroup(); 70139f7f9bSDimitry Andric if (Group.isValid()) { 71139f7f9bSDimitry Andric llvm::errs() << " Group:"; 72139f7f9bSDimitry Andric Group.dump(); 73139f7f9bSDimitry Andric } 74139f7f9bSDimitry Andric 75139f7f9bSDimitry Andric const Option Alias = getAlias(); 76139f7f9bSDimitry Andric if (Alias.isValid()) { 77139f7f9bSDimitry Andric llvm::errs() << " Alias:"; 78139f7f9bSDimitry Andric Alias.dump(); 79139f7f9bSDimitry Andric } 80139f7f9bSDimitry Andric 81139f7f9bSDimitry Andric if (getKind() == MultiArgClass) 82139f7f9bSDimitry Andric llvm::errs() << " NumArgs:" << getNumArgs(); 83139f7f9bSDimitry Andric 84139f7f9bSDimitry Andric llvm::errs() << ">\n"; 85139f7f9bSDimitry Andric } 86139f7f9bSDimitry Andric 87139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const { 88139f7f9bSDimitry Andric // Aliases are never considered in matching, look through them. 89139f7f9bSDimitry Andric const Option Alias = getAlias(); 90139f7f9bSDimitry Andric if (Alias.isValid()) 91139f7f9bSDimitry Andric return Alias.matches(Opt); 92139f7f9bSDimitry Andric 93139f7f9bSDimitry Andric // Check exact match. 94139f7f9bSDimitry Andric if (getID() == Opt.getID()) 95139f7f9bSDimitry Andric return true; 96139f7f9bSDimitry Andric 97139f7f9bSDimitry Andric const Option Group = getGroup(); 98139f7f9bSDimitry Andric if (Group.isValid()) 99139f7f9bSDimitry Andric return Group.matches(Opt); 100139f7f9bSDimitry Andric return false; 101139f7f9bSDimitry Andric } 102139f7f9bSDimitry Andric 103139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args, 104139f7f9bSDimitry Andric unsigned &Index, 105139f7f9bSDimitry Andric unsigned ArgSize) const { 106139f7f9bSDimitry Andric const Option &UnaliasedOption = getUnaliasedOption(); 107139f7f9bSDimitry Andric StringRef Spelling; 108139f7f9bSDimitry Andric // If the option was an alias, get the spelling from the unaliased one. 109139f7f9bSDimitry Andric if (getID() == UnaliasedOption.getID()) { 110139f7f9bSDimitry Andric Spelling = StringRef(Args.getArgString(Index), ArgSize); 111139f7f9bSDimitry Andric } else { 112139f7f9bSDimitry Andric Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + 113139f7f9bSDimitry Andric Twine(UnaliasedOption.getName())); 114139f7f9bSDimitry Andric } 115139f7f9bSDimitry Andric 116139f7f9bSDimitry Andric switch (getKind()) { 117f785676fSDimitry Andric case FlagClass: { 118139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 11991bc56edSDimitry Andric return nullptr; 120139f7f9bSDimitry Andric 121f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 122f785676fSDimitry Andric if (getAliasArgs()) { 123f785676fSDimitry Andric const char *Val = getAliasArgs(); 124f785676fSDimitry Andric while (*Val != '\0') { 125f785676fSDimitry Andric A->getValues().push_back(Val); 126f785676fSDimitry Andric 127f785676fSDimitry Andric // Move past the '\0' to the next argument. 128f785676fSDimitry Andric Val += strlen(Val) + 1; 129f785676fSDimitry Andric } 130f785676fSDimitry Andric } 131f785676fSDimitry Andric return A; 132f785676fSDimitry Andric } 133139f7f9bSDimitry Andric case JoinedClass: { 134139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 135139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index++, Value); 136139f7f9bSDimitry Andric } 137139f7f9bSDimitry Andric case CommaJoinedClass: { 138139f7f9bSDimitry Andric // Always matches. 139139f7f9bSDimitry Andric const char *Str = Args.getArgString(Index) + ArgSize; 140139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 141139f7f9bSDimitry Andric 142139f7f9bSDimitry Andric // Parse out the comma separated values. 143139f7f9bSDimitry Andric const char *Prev = Str; 144139f7f9bSDimitry Andric for (;; ++Str) { 145139f7f9bSDimitry Andric char c = *Str; 146139f7f9bSDimitry Andric 147139f7f9bSDimitry Andric if (!c || c == ',') { 148139f7f9bSDimitry Andric if (Prev != Str) { 149139f7f9bSDimitry Andric char *Value = new char[Str - Prev + 1]; 150139f7f9bSDimitry Andric memcpy(Value, Prev, Str - Prev); 151139f7f9bSDimitry Andric Value[Str - Prev] = '\0'; 152139f7f9bSDimitry Andric A->getValues().push_back(Value); 153139f7f9bSDimitry Andric } 154139f7f9bSDimitry Andric 155139f7f9bSDimitry Andric if (!c) 156139f7f9bSDimitry Andric break; 157139f7f9bSDimitry Andric 158139f7f9bSDimitry Andric Prev = Str + 1; 159139f7f9bSDimitry Andric } 160139f7f9bSDimitry Andric } 161139f7f9bSDimitry Andric A->setOwnsValues(true); 162139f7f9bSDimitry Andric 163139f7f9bSDimitry Andric return A; 164139f7f9bSDimitry Andric } 165139f7f9bSDimitry Andric case SeparateClass: 166139f7f9bSDimitry Andric // Matches iff this is an exact match. 167139f7f9bSDimitry Andric // FIXME: Avoid strlen. 168139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 16991bc56edSDimitry Andric return nullptr; 170139f7f9bSDimitry Andric 171139f7f9bSDimitry Andric Index += 2; 17239d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 17339d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 17491bc56edSDimitry Andric return nullptr; 175139f7f9bSDimitry Andric 176139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 177139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 178139f7f9bSDimitry Andric case MultiArgClass: { 179139f7f9bSDimitry Andric // Matches iff this is an exact match. 180139f7f9bSDimitry Andric // FIXME: Avoid strlen. 181139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 18291bc56edSDimitry Andric return nullptr; 183139f7f9bSDimitry Andric 184139f7f9bSDimitry Andric Index += 1 + getNumArgs(); 185139f7f9bSDimitry Andric if (Index > Args.getNumInputArgStrings()) 18691bc56edSDimitry Andric return nullptr; 187139f7f9bSDimitry Andric 188139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 189139f7f9bSDimitry Andric Args.getArgString(Index - getNumArgs())); 190139f7f9bSDimitry Andric for (unsigned i = 1; i != getNumArgs(); ++i) 191139f7f9bSDimitry Andric A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 192139f7f9bSDimitry Andric return A; 193139f7f9bSDimitry Andric } 194139f7f9bSDimitry Andric case JoinedOrSeparateClass: { 195139f7f9bSDimitry Andric // If this is not an exact match, it is a joined arg. 196139f7f9bSDimitry Andric // FIXME: Avoid strlen. 197139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 198139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 199139f7f9bSDimitry Andric return new Arg(*this, Spelling, Index++, Value); 200139f7f9bSDimitry Andric } 201139f7f9bSDimitry Andric 202139f7f9bSDimitry Andric // Otherwise it must be separate. 203139f7f9bSDimitry Andric Index += 2; 20439d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 20539d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 20691bc56edSDimitry Andric return nullptr; 207139f7f9bSDimitry Andric 208139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 209139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 210139f7f9bSDimitry Andric } 211139f7f9bSDimitry Andric case JoinedAndSeparateClass: 212139f7f9bSDimitry Andric // Always matches. 213139f7f9bSDimitry Andric Index += 2; 21439d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 21539d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 21691bc56edSDimitry Andric return nullptr; 217139f7f9bSDimitry Andric 218139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index - 2, 219139f7f9bSDimitry Andric Args.getArgString(Index - 2) + ArgSize, 220139f7f9bSDimitry Andric Args.getArgString(Index - 1)); 221f785676fSDimitry Andric case RemainingArgsClass: { 222f785676fSDimitry Andric // Matches iff this is an exact match. 223f785676fSDimitry Andric // FIXME: Avoid strlen. 224f785676fSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 22591bc56edSDimitry Andric return nullptr; 226f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 22739d628a0SDimitry Andric while (Index < Args.getNumInputArgStrings() && 22839d628a0SDimitry Andric Args.getArgString(Index) != nullptr) 229f785676fSDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 230f785676fSDimitry Andric return A; 231f785676fSDimitry Andric } 232139f7f9bSDimitry Andric default: 233139f7f9bSDimitry Andric llvm_unreachable("Invalid option kind!"); 234139f7f9bSDimitry Andric } 235139f7f9bSDimitry Andric } 236