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