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