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