1 //===--- Option.cpp - Abstract Driver Options -----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Option/Option.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/Option/Arg.h" 13 #include "llvm/Option/ArgList.h" 14 #include "llvm/Support/Debug.h" 15 #include "llvm/Support/ErrorHandling.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include <algorithm> 18 #include <cassert> 19 20 using namespace llvm; 21 using namespace llvm::opt; 22 23 Option::Option(const OptTable::Info *info, const OptTable *owner) 24 : Info(info), Owner(owner) { 25 26 // Multi-level aliases are not supported. This just simplifies option 27 // tracking, it is not an inherent limitation. 28 assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && 29 "Multi-level aliases are not supported."); 30 31 if (Info && getAliasArgs()) { 32 assert(getAlias().isValid() && "Only alias options can have alias args."); 33 assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); 34 assert(getAlias().getKind() != FlagClass && 35 "Cannot provide alias args to a flag option."); 36 } 37 } 38 39 void Option::print(raw_ostream &O) const { 40 O << "<"; 41 switch (getKind()) { 42 #define P(N) case N: O << #N; break 43 P(GroupClass); 44 P(InputClass); 45 P(UnknownClass); 46 P(FlagClass); 47 P(JoinedClass); 48 P(SeparateClass); 49 P(CommaJoinedClass); 50 P(MultiArgClass); 51 P(JoinedOrSeparateClass); 52 P(JoinedAndSeparateClass); 53 P(RemainingArgsClass); 54 P(RemainingArgsJoinedClass); 55 #undef P 56 } 57 58 if (Info->Prefixes) { 59 O << " Prefixes:["; 60 for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 61 O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 62 } 63 O << ']'; 64 } 65 66 O << " Name:\"" << getName() << '"'; 67 68 const Option Group = getGroup(); 69 if (Group.isValid()) { 70 O << " Group:"; 71 Group.print(O); 72 } 73 74 const Option Alias = getAlias(); 75 if (Alias.isValid()) { 76 O << " Alias:"; 77 Alias.print(O); 78 } 79 80 if (getKind() == MultiArgClass) 81 O << " NumArgs:" << getNumArgs(); 82 83 O << ">\n"; 84 } 85 86 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 87 LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); } 88 #endif 89 90 bool Option::matches(OptSpecifier Opt) const { 91 // Aliases are never considered in matching, look through them. 92 const Option Alias = getAlias(); 93 if (Alias.isValid()) 94 return Alias.matches(Opt); 95 96 // Check exact match. 97 if (getID() == Opt.getID()) 98 return true; 99 100 const Option Group = getGroup(); 101 if (Group.isValid()) 102 return Group.matches(Opt); 103 return false; 104 } 105 106 Arg *Option::accept(const ArgList &Args, 107 unsigned &Index, 108 unsigned ArgSize) const { 109 const Option &UnaliasedOption = getUnaliasedOption(); 110 StringRef Spelling; 111 // If the option was an alias, get the spelling from the unaliased one. 112 if (getID() == UnaliasedOption.getID()) { 113 Spelling = StringRef(Args.getArgString(Index), ArgSize); 114 } else { 115 Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + 116 Twine(UnaliasedOption.getName())); 117 } 118 119 switch (getKind()) { 120 case FlagClass: { 121 if (ArgSize != strlen(Args.getArgString(Index))) 122 return nullptr; 123 124 Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 125 if (getAliasArgs()) { 126 const char *Val = getAliasArgs(); 127 while (*Val != '\0') { 128 A->getValues().push_back(Val); 129 130 // Move past the '\0' to the next argument. 131 Val += strlen(Val) + 1; 132 } 133 } 134 135 if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) 136 // A Flag alias for a Joined option must provide an argument. 137 A->getValues().push_back(""); 138 139 return A; 140 } 141 case JoinedClass: { 142 const char *Value = Args.getArgString(Index) + ArgSize; 143 return new Arg(UnaliasedOption, Spelling, Index++, Value); 144 } 145 case CommaJoinedClass: { 146 // Always matches. 147 const char *Str = Args.getArgString(Index) + ArgSize; 148 Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 149 150 // Parse out the comma separated values. 151 const char *Prev = Str; 152 for (;; ++Str) { 153 char c = *Str; 154 155 if (!c || c == ',') { 156 if (Prev != Str) { 157 char *Value = new char[Str - Prev + 1]; 158 memcpy(Value, Prev, Str - Prev); 159 Value[Str - Prev] = '\0'; 160 A->getValues().push_back(Value); 161 } 162 163 if (!c) 164 break; 165 166 Prev = Str + 1; 167 } 168 } 169 A->setOwnsValues(true); 170 171 return A; 172 } 173 case SeparateClass: 174 // Matches iff this is an exact match. 175 // FIXME: Avoid strlen. 176 if (ArgSize != strlen(Args.getArgString(Index))) 177 return nullptr; 178 179 Index += 2; 180 if (Index > Args.getNumInputArgStrings() || 181 Args.getArgString(Index - 1) == nullptr) 182 return nullptr; 183 184 return new Arg(UnaliasedOption, Spelling, 185 Index - 2, Args.getArgString(Index - 1)); 186 case MultiArgClass: { 187 // Matches iff this is an exact match. 188 // FIXME: Avoid strlen. 189 if (ArgSize != strlen(Args.getArgString(Index))) 190 return nullptr; 191 192 Index += 1 + getNumArgs(); 193 if (Index > Args.getNumInputArgStrings()) 194 return nullptr; 195 196 Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 197 Args.getArgString(Index - getNumArgs())); 198 for (unsigned i = 1; i != getNumArgs(); ++i) 199 A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 200 return A; 201 } 202 case JoinedOrSeparateClass: { 203 // If this is not an exact match, it is a joined arg. 204 // FIXME: Avoid strlen. 205 if (ArgSize != strlen(Args.getArgString(Index))) { 206 const char *Value = Args.getArgString(Index) + ArgSize; 207 return new Arg(*this, Spelling, Index++, Value); 208 } 209 210 // Otherwise it must be separate. 211 Index += 2; 212 if (Index > Args.getNumInputArgStrings() || 213 Args.getArgString(Index - 1) == nullptr) 214 return nullptr; 215 216 return new Arg(UnaliasedOption, Spelling, 217 Index - 2, Args.getArgString(Index - 1)); 218 } 219 case JoinedAndSeparateClass: 220 // Always matches. 221 Index += 2; 222 if (Index > Args.getNumInputArgStrings() || 223 Args.getArgString(Index - 1) == nullptr) 224 return nullptr; 225 226 return new Arg(UnaliasedOption, Spelling, Index - 2, 227 Args.getArgString(Index - 2) + ArgSize, 228 Args.getArgString(Index - 1)); 229 case RemainingArgsClass: { 230 // Matches iff this is an exact match. 231 // FIXME: Avoid strlen. 232 if (ArgSize != strlen(Args.getArgString(Index))) 233 return nullptr; 234 Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 235 while (Index < Args.getNumInputArgStrings() && 236 Args.getArgString(Index) != nullptr) 237 A->getValues().push_back(Args.getArgString(Index++)); 238 return A; 239 } 240 case RemainingArgsJoinedClass: { 241 Arg *A = new Arg(UnaliasedOption, Spelling, Index); 242 if (ArgSize != strlen(Args.getArgString(Index))) { 243 // An inexact match means there is a joined arg. 244 A->getValues().push_back(Args.getArgString(Index) + ArgSize); 245 } 246 Index++; 247 while (Index < Args.getNumInputArgStrings() && 248 Args.getArgString(Index) != nullptr) 249 A->getValues().push_back(Args.getArgString(Index++)); 250 return A; 251 } 252 253 default: 254 llvm_unreachable("Invalid option kind!"); 255 } 256 } 257