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" 147d523365SDimitry Andric #include "llvm/Support/Debug.h" 15139f7f9bSDimitry Andric #include "llvm/Support/ErrorHandling.h" 16139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h" 17139f7f9bSDimitry Andric #include <algorithm> 18139f7f9bSDimitry Andric #include <cassert> 19139f7f9bSDimitry Andric 20139f7f9bSDimitry Andric using namespace llvm; 21139f7f9bSDimitry Andric using namespace llvm::opt; 22139f7f9bSDimitry Andric 23139f7f9bSDimitry Andric Option::Option(const OptTable::Info *info, const OptTable *owner) 24139f7f9bSDimitry Andric : Info(info), Owner(owner) { 25139f7f9bSDimitry Andric 26f785676fSDimitry Andric // Multi-level aliases are not supported. This just simplifies option 27f785676fSDimitry Andric // tracking, it is not an inherent limitation. 28f785676fSDimitry Andric assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && 29f785676fSDimitry Andric "Multi-level aliases are not supported."); 30f785676fSDimitry Andric 31f785676fSDimitry Andric if (Info && getAliasArgs()) { 32f785676fSDimitry Andric assert(getAlias().isValid() && "Only alias options can have alias args."); 33f785676fSDimitry Andric assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); 34f785676fSDimitry Andric assert(getAlias().getKind() != FlagClass && 35f785676fSDimitry Andric "Cannot provide alias args to a flag option."); 36f785676fSDimitry Andric } 37139f7f9bSDimitry Andric } 38139f7f9bSDimitry Andric 397d523365SDimitry Andric void Option::print(raw_ostream &O) const { 407d523365SDimitry Andric O << "<"; 41139f7f9bSDimitry Andric switch (getKind()) { 427d523365SDimitry Andric #define P(N) case N: O << #N; break 43139f7f9bSDimitry Andric P(GroupClass); 44139f7f9bSDimitry Andric P(InputClass); 45139f7f9bSDimitry Andric P(UnknownClass); 46139f7f9bSDimitry Andric P(FlagClass); 47139f7f9bSDimitry Andric P(JoinedClass); 48139f7f9bSDimitry Andric P(SeparateClass); 49139f7f9bSDimitry Andric P(CommaJoinedClass); 50139f7f9bSDimitry Andric P(MultiArgClass); 51139f7f9bSDimitry Andric P(JoinedOrSeparateClass); 52139f7f9bSDimitry Andric P(JoinedAndSeparateClass); 53f785676fSDimitry Andric P(RemainingArgsClass); 543ca95b02SDimitry Andric P(RemainingArgsJoinedClass); 55139f7f9bSDimitry Andric #undef P 56139f7f9bSDimitry Andric } 57139f7f9bSDimitry Andric 58f785676fSDimitry Andric if (Info->Prefixes) { 597d523365SDimitry Andric O << " Prefixes:["; 6091bc56edSDimitry Andric for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 617d523365SDimitry Andric O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 62139f7f9bSDimitry Andric } 637d523365SDimitry Andric O << ']'; 64f785676fSDimitry Andric } 65139f7f9bSDimitry Andric 667d523365SDimitry Andric O << " Name:\"" << getName() << '"'; 67139f7f9bSDimitry Andric 68139f7f9bSDimitry Andric const Option Group = getGroup(); 69139f7f9bSDimitry Andric if (Group.isValid()) { 707d523365SDimitry Andric O << " Group:"; 717d523365SDimitry Andric Group.print(O); 72139f7f9bSDimitry Andric } 73139f7f9bSDimitry Andric 74139f7f9bSDimitry Andric const Option Alias = getAlias(); 75139f7f9bSDimitry Andric if (Alias.isValid()) { 767d523365SDimitry Andric O << " Alias:"; 777d523365SDimitry Andric Alias.print(O); 78139f7f9bSDimitry Andric } 79139f7f9bSDimitry Andric 80139f7f9bSDimitry Andric if (getKind() == MultiArgClass) 817d523365SDimitry Andric O << " NumArgs:" << getNumArgs(); 82139f7f9bSDimitry Andric 837d523365SDimitry Andric O << ">\n"; 84139f7f9bSDimitry Andric } 85139f7f9bSDimitry Andric 863ca95b02SDimitry Andric LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); } 877d523365SDimitry Andric 88139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const { 89139f7f9bSDimitry Andric // Aliases are never considered in matching, look through them. 90139f7f9bSDimitry Andric const Option Alias = getAlias(); 91139f7f9bSDimitry Andric if (Alias.isValid()) 92139f7f9bSDimitry Andric return Alias.matches(Opt); 93139f7f9bSDimitry Andric 94139f7f9bSDimitry Andric // Check exact match. 95139f7f9bSDimitry Andric if (getID() == Opt.getID()) 96139f7f9bSDimitry Andric return true; 97139f7f9bSDimitry Andric 98139f7f9bSDimitry Andric const Option Group = getGroup(); 99139f7f9bSDimitry Andric if (Group.isValid()) 100139f7f9bSDimitry Andric return Group.matches(Opt); 101139f7f9bSDimitry Andric return false; 102139f7f9bSDimitry Andric } 103139f7f9bSDimitry Andric 104139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args, 105139f7f9bSDimitry Andric unsigned &Index, 106139f7f9bSDimitry Andric unsigned ArgSize) const { 107139f7f9bSDimitry Andric const Option &UnaliasedOption = getUnaliasedOption(); 108139f7f9bSDimitry Andric StringRef Spelling; 109139f7f9bSDimitry Andric // If the option was an alias, get the spelling from the unaliased one. 110139f7f9bSDimitry Andric if (getID() == UnaliasedOption.getID()) { 111139f7f9bSDimitry Andric Spelling = StringRef(Args.getArgString(Index), ArgSize); 112139f7f9bSDimitry Andric } else { 113139f7f9bSDimitry Andric Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + 114139f7f9bSDimitry Andric Twine(UnaliasedOption.getName())); 115139f7f9bSDimitry Andric } 116139f7f9bSDimitry Andric 117139f7f9bSDimitry Andric switch (getKind()) { 118f785676fSDimitry Andric case FlagClass: { 119139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 12091bc56edSDimitry Andric return nullptr; 121139f7f9bSDimitry Andric 122f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 123f785676fSDimitry Andric if (getAliasArgs()) { 124f785676fSDimitry Andric const char *Val = getAliasArgs(); 125f785676fSDimitry Andric while (*Val != '\0') { 126f785676fSDimitry Andric A->getValues().push_back(Val); 127f785676fSDimitry Andric 128f785676fSDimitry Andric // Move past the '\0' to the next argument. 129f785676fSDimitry Andric Val += strlen(Val) + 1; 130f785676fSDimitry Andric } 131f785676fSDimitry Andric } 132ff0cc061SDimitry Andric 133ff0cc061SDimitry Andric if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) 134ff0cc061SDimitry Andric // A Flag alias for a Joined option must provide an argument. 135ff0cc061SDimitry Andric A->getValues().push_back(""); 136ff0cc061SDimitry Andric 137f785676fSDimitry Andric return A; 138f785676fSDimitry Andric } 139139f7f9bSDimitry Andric case JoinedClass: { 140139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 141139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index++, Value); 142139f7f9bSDimitry Andric } 143139f7f9bSDimitry Andric case CommaJoinedClass: { 144139f7f9bSDimitry Andric // Always matches. 145139f7f9bSDimitry Andric const char *Str = Args.getArgString(Index) + ArgSize; 146139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 147139f7f9bSDimitry Andric 148139f7f9bSDimitry Andric // Parse out the comma separated values. 149139f7f9bSDimitry Andric const char *Prev = Str; 150139f7f9bSDimitry Andric for (;; ++Str) { 151139f7f9bSDimitry Andric char c = *Str; 152139f7f9bSDimitry Andric 153139f7f9bSDimitry Andric if (!c || c == ',') { 154139f7f9bSDimitry Andric if (Prev != Str) { 155139f7f9bSDimitry Andric char *Value = new char[Str - Prev + 1]; 156139f7f9bSDimitry Andric memcpy(Value, Prev, Str - Prev); 157139f7f9bSDimitry Andric Value[Str - Prev] = '\0'; 158139f7f9bSDimitry Andric A->getValues().push_back(Value); 159139f7f9bSDimitry Andric } 160139f7f9bSDimitry Andric 161139f7f9bSDimitry Andric if (!c) 162139f7f9bSDimitry Andric break; 163139f7f9bSDimitry Andric 164139f7f9bSDimitry Andric Prev = Str + 1; 165139f7f9bSDimitry Andric } 166139f7f9bSDimitry Andric } 167139f7f9bSDimitry Andric A->setOwnsValues(true); 168139f7f9bSDimitry Andric 169139f7f9bSDimitry Andric return A; 170139f7f9bSDimitry Andric } 171139f7f9bSDimitry Andric case SeparateClass: 172139f7f9bSDimitry Andric // Matches iff this is an exact match. 173139f7f9bSDimitry Andric // FIXME: Avoid strlen. 174139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 17591bc56edSDimitry Andric return nullptr; 176139f7f9bSDimitry Andric 177139f7f9bSDimitry Andric Index += 2; 17839d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 17939d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 18091bc56edSDimitry Andric return nullptr; 181139f7f9bSDimitry Andric 182139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 183139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 184139f7f9bSDimitry Andric case MultiArgClass: { 185139f7f9bSDimitry Andric // Matches iff this is an exact match. 186139f7f9bSDimitry Andric // FIXME: Avoid strlen. 187139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 18891bc56edSDimitry Andric return nullptr; 189139f7f9bSDimitry Andric 190139f7f9bSDimitry Andric Index += 1 + getNumArgs(); 191139f7f9bSDimitry Andric if (Index > Args.getNumInputArgStrings()) 19291bc56edSDimitry Andric return nullptr; 193139f7f9bSDimitry Andric 194139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 195139f7f9bSDimitry Andric Args.getArgString(Index - getNumArgs())); 196139f7f9bSDimitry Andric for (unsigned i = 1; i != getNumArgs(); ++i) 197139f7f9bSDimitry Andric A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 198139f7f9bSDimitry Andric return A; 199139f7f9bSDimitry Andric } 200139f7f9bSDimitry Andric case JoinedOrSeparateClass: { 201139f7f9bSDimitry Andric // If this is not an exact match, it is a joined arg. 202139f7f9bSDimitry Andric // FIXME: Avoid strlen. 203139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 204139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 205139f7f9bSDimitry Andric return new Arg(*this, Spelling, Index++, Value); 206139f7f9bSDimitry Andric } 207139f7f9bSDimitry Andric 208139f7f9bSDimitry Andric // Otherwise it must be separate. 209139f7f9bSDimitry Andric Index += 2; 21039d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 21139d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 21291bc56edSDimitry Andric return nullptr; 213139f7f9bSDimitry Andric 214139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 215139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 216139f7f9bSDimitry Andric } 217139f7f9bSDimitry Andric case JoinedAndSeparateClass: 218139f7f9bSDimitry Andric // Always matches. 219139f7f9bSDimitry Andric Index += 2; 22039d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 22139d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 22291bc56edSDimitry Andric return nullptr; 223139f7f9bSDimitry Andric 224139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index - 2, 225139f7f9bSDimitry Andric Args.getArgString(Index - 2) + ArgSize, 226139f7f9bSDimitry Andric Args.getArgString(Index - 1)); 227f785676fSDimitry Andric case RemainingArgsClass: { 228f785676fSDimitry Andric // Matches iff this is an exact match. 229f785676fSDimitry Andric // FIXME: Avoid strlen. 230f785676fSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 23191bc56edSDimitry Andric return nullptr; 232f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 23339d628a0SDimitry Andric while (Index < Args.getNumInputArgStrings() && 23439d628a0SDimitry Andric Args.getArgString(Index) != nullptr) 235f785676fSDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 236f785676fSDimitry Andric return A; 237f785676fSDimitry Andric } 2383ca95b02SDimitry Andric case RemainingArgsJoinedClass: { 2393ca95b02SDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index); 2403ca95b02SDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 2413ca95b02SDimitry Andric // An inexact match means there is a joined arg. 2423ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index) + ArgSize); 2433ca95b02SDimitry Andric } 2443ca95b02SDimitry Andric Index++; 2453ca95b02SDimitry Andric while (Index < Args.getNumInputArgStrings() && 2463ca95b02SDimitry Andric Args.getArgString(Index) != nullptr) 2473ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 2483ca95b02SDimitry Andric return A; 2493ca95b02SDimitry Andric } 2503ca95b02SDimitry Andric 251139f7f9bSDimitry Andric default: 252139f7f9bSDimitry Andric llvm_unreachable("Invalid option kind!"); 253139f7f9bSDimitry Andric } 254139f7f9bSDimitry Andric } 255