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