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