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 void Option::dump() const { 39139f7f9bSDimitry Andric llvm::errs() << "<"; 40139f7f9bSDimitry Andric switch (getKind()) { 41139f7f9bSDimitry Andric #define P(N) case N: llvm::errs() << #N; break 42139f7f9bSDimitry Andric P(GroupClass); 43139f7f9bSDimitry Andric P(InputClass); 44139f7f9bSDimitry Andric P(UnknownClass); 45139f7f9bSDimitry Andric P(FlagClass); 46139f7f9bSDimitry Andric P(JoinedClass); 47139f7f9bSDimitry Andric P(SeparateClass); 48139f7f9bSDimitry Andric P(CommaJoinedClass); 49139f7f9bSDimitry Andric P(MultiArgClass); 50139f7f9bSDimitry Andric P(JoinedOrSeparateClass); 51139f7f9bSDimitry Andric P(JoinedAndSeparateClass); 52f785676fSDimitry Andric P(RemainingArgsClass); 53139f7f9bSDimitry Andric #undef P 54139f7f9bSDimitry Andric } 55139f7f9bSDimitry Andric 56f785676fSDimitry Andric if (Info->Prefixes) { 57139f7f9bSDimitry Andric llvm::errs() << " Prefixes:["; 5891bc56edSDimitry Andric for (const char * const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 5991bc56edSDimitry Andric llvm::errs() << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 60139f7f9bSDimitry Andric } 61139f7f9bSDimitry Andric llvm::errs() << ']'; 62f785676fSDimitry Andric } 63139f7f9bSDimitry Andric 64139f7f9bSDimitry Andric llvm::errs() << " Name:\"" << getName() << '"'; 65139f7f9bSDimitry Andric 66139f7f9bSDimitry Andric const Option Group = getGroup(); 67139f7f9bSDimitry Andric if (Group.isValid()) { 68139f7f9bSDimitry Andric llvm::errs() << " Group:"; 69139f7f9bSDimitry Andric Group.dump(); 70139f7f9bSDimitry Andric } 71139f7f9bSDimitry Andric 72139f7f9bSDimitry Andric const Option Alias = getAlias(); 73139f7f9bSDimitry Andric if (Alias.isValid()) { 74139f7f9bSDimitry Andric llvm::errs() << " Alias:"; 75139f7f9bSDimitry Andric Alias.dump(); 76139f7f9bSDimitry Andric } 77139f7f9bSDimitry Andric 78139f7f9bSDimitry Andric if (getKind() == MultiArgClass) 79139f7f9bSDimitry Andric llvm::errs() << " NumArgs:" << getNumArgs(); 80139f7f9bSDimitry Andric 81139f7f9bSDimitry Andric llvm::errs() << ">\n"; 82139f7f9bSDimitry Andric } 83139f7f9bSDimitry Andric 84139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const { 85139f7f9bSDimitry Andric // Aliases are never considered in matching, look through them. 86139f7f9bSDimitry Andric const Option Alias = getAlias(); 87139f7f9bSDimitry Andric if (Alias.isValid()) 88139f7f9bSDimitry Andric return Alias.matches(Opt); 89139f7f9bSDimitry Andric 90139f7f9bSDimitry Andric // Check exact match. 91139f7f9bSDimitry Andric if (getID() == Opt.getID()) 92139f7f9bSDimitry Andric return true; 93139f7f9bSDimitry Andric 94139f7f9bSDimitry Andric const Option Group = getGroup(); 95139f7f9bSDimitry Andric if (Group.isValid()) 96139f7f9bSDimitry Andric return Group.matches(Opt); 97139f7f9bSDimitry Andric return false; 98139f7f9bSDimitry Andric } 99139f7f9bSDimitry Andric 100139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args, 101139f7f9bSDimitry Andric unsigned &Index, 102139f7f9bSDimitry Andric unsigned ArgSize) const { 103139f7f9bSDimitry Andric const Option &UnaliasedOption = getUnaliasedOption(); 104139f7f9bSDimitry Andric StringRef Spelling; 105139f7f9bSDimitry Andric // If the option was an alias, get the spelling from the unaliased one. 106139f7f9bSDimitry Andric if (getID() == UnaliasedOption.getID()) { 107139f7f9bSDimitry Andric Spelling = StringRef(Args.getArgString(Index), ArgSize); 108139f7f9bSDimitry Andric } else { 109139f7f9bSDimitry Andric Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + 110139f7f9bSDimitry Andric Twine(UnaliasedOption.getName())); 111139f7f9bSDimitry Andric } 112139f7f9bSDimitry Andric 113139f7f9bSDimitry Andric switch (getKind()) { 114f785676fSDimitry Andric case FlagClass: { 115139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 11691bc56edSDimitry Andric return nullptr; 117139f7f9bSDimitry Andric 118f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 119f785676fSDimitry Andric if (getAliasArgs()) { 120f785676fSDimitry Andric const char *Val = getAliasArgs(); 121f785676fSDimitry Andric while (*Val != '\0') { 122f785676fSDimitry Andric A->getValues().push_back(Val); 123f785676fSDimitry Andric 124f785676fSDimitry Andric // Move past the '\0' to the next argument. 125f785676fSDimitry Andric Val += strlen(Val) + 1; 126f785676fSDimitry Andric } 127f785676fSDimitry Andric } 128ff0cc061SDimitry Andric 129ff0cc061SDimitry Andric if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) 130ff0cc061SDimitry Andric // A Flag alias for a Joined option must provide an argument. 131ff0cc061SDimitry Andric A->getValues().push_back(""); 132ff0cc061SDimitry Andric 133f785676fSDimitry Andric return A; 134f785676fSDimitry Andric } 135139f7f9bSDimitry Andric case JoinedClass: { 136139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 137139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index++, Value); 138139f7f9bSDimitry Andric } 139139f7f9bSDimitry Andric case CommaJoinedClass: { 140139f7f9bSDimitry Andric // Always matches. 141139f7f9bSDimitry Andric const char *Str = Args.getArgString(Index) + ArgSize; 142139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 143139f7f9bSDimitry Andric 144139f7f9bSDimitry Andric // Parse out the comma separated values. 145139f7f9bSDimitry Andric const char *Prev = Str; 146139f7f9bSDimitry Andric for (;; ++Str) { 147139f7f9bSDimitry Andric char c = *Str; 148139f7f9bSDimitry Andric 149139f7f9bSDimitry Andric if (!c || c == ',') { 150139f7f9bSDimitry Andric if (Prev != Str) { 151139f7f9bSDimitry Andric char *Value = new char[Str - Prev + 1]; 152139f7f9bSDimitry Andric memcpy(Value, Prev, Str - Prev); 153139f7f9bSDimitry Andric Value[Str - Prev] = '\0'; 154139f7f9bSDimitry Andric A->getValues().push_back(Value); 155139f7f9bSDimitry Andric } 156139f7f9bSDimitry Andric 157139f7f9bSDimitry Andric if (!c) 158139f7f9bSDimitry Andric break; 159139f7f9bSDimitry Andric 160139f7f9bSDimitry Andric Prev = Str + 1; 161139f7f9bSDimitry Andric } 162139f7f9bSDimitry Andric } 163139f7f9bSDimitry Andric A->setOwnsValues(true); 164139f7f9bSDimitry Andric 165139f7f9bSDimitry Andric return A; 166139f7f9bSDimitry Andric } 167139f7f9bSDimitry Andric case SeparateClass: 168139f7f9bSDimitry Andric // Matches iff this is an exact match. 169139f7f9bSDimitry Andric // FIXME: Avoid strlen. 170139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 17191bc56edSDimitry Andric return nullptr; 172139f7f9bSDimitry Andric 173139f7f9bSDimitry Andric Index += 2; 17439d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 17539d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 17691bc56edSDimitry Andric return nullptr; 177139f7f9bSDimitry Andric 178139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 179139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 180139f7f9bSDimitry Andric case MultiArgClass: { 181139f7f9bSDimitry Andric // Matches iff this is an exact match. 182139f7f9bSDimitry Andric // FIXME: Avoid strlen. 183139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 18491bc56edSDimitry Andric return nullptr; 185139f7f9bSDimitry Andric 186139f7f9bSDimitry Andric Index += 1 + getNumArgs(); 187139f7f9bSDimitry Andric if (Index > Args.getNumInputArgStrings()) 18891bc56edSDimitry Andric return nullptr; 189139f7f9bSDimitry Andric 190139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 191139f7f9bSDimitry Andric Args.getArgString(Index - getNumArgs())); 192139f7f9bSDimitry Andric for (unsigned i = 1; i != getNumArgs(); ++i) 193139f7f9bSDimitry Andric A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 194139f7f9bSDimitry Andric return A; 195139f7f9bSDimitry Andric } 196139f7f9bSDimitry Andric case JoinedOrSeparateClass: { 197139f7f9bSDimitry Andric // If this is not an exact match, it is a joined arg. 198139f7f9bSDimitry Andric // FIXME: Avoid strlen. 199139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) { 200139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize; 201139f7f9bSDimitry Andric return new Arg(*this, Spelling, Index++, Value); 202139f7f9bSDimitry Andric } 203139f7f9bSDimitry Andric 204139f7f9bSDimitry Andric // Otherwise it must be separate. 205139f7f9bSDimitry Andric Index += 2; 20639d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 20739d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 20891bc56edSDimitry Andric return nullptr; 209139f7f9bSDimitry Andric 210139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, 211139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1)); 212139f7f9bSDimitry Andric } 213139f7f9bSDimitry Andric case JoinedAndSeparateClass: 214139f7f9bSDimitry Andric // Always matches. 215139f7f9bSDimitry Andric Index += 2; 21639d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() || 21739d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr) 21891bc56edSDimitry Andric return nullptr; 219139f7f9bSDimitry Andric 220139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index - 2, 221139f7f9bSDimitry Andric Args.getArgString(Index - 2) + ArgSize, 222139f7f9bSDimitry Andric Args.getArgString(Index - 1)); 223f785676fSDimitry Andric case RemainingArgsClass: { 224f785676fSDimitry Andric // Matches iff this is an exact match. 225f785676fSDimitry Andric // FIXME: Avoid strlen. 226f785676fSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) 22791bc56edSDimitry Andric return nullptr; 228f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 22939d628a0SDimitry Andric while (Index < Args.getNumInputArgStrings() && 23039d628a0SDimitry Andric Args.getArgString(Index) != nullptr) 231f785676fSDimitry Andric A->getValues().push_back(Args.getArgString(Index++)); 232f785676fSDimitry Andric return A; 233f785676fSDimitry Andric } 234139f7f9bSDimitry Andric default: 235139f7f9bSDimitry Andric llvm_unreachable("Invalid option kind!"); 236139f7f9bSDimitry Andric } 237139f7f9bSDimitry Andric } 238