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/ErrorHandling.h" 15#include "llvm/Support/raw_ostream.h" 16#include <algorithm> 17#include <cassert> 18 19using namespace llvm; 20using namespace llvm::opt; 21 22Option::Option(const OptTable::Info *info, const OptTable *owner) 23 : Info(info), Owner(owner) { 24 25 // Multi-level aliases are not supported. This just simplifies option 26 // tracking, it is not an inherent limitation. 27 assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && 28 "Multi-level aliases are not supported."); 29 30 if (Info && getAliasArgs()) { 31 assert(getAlias().isValid() && "Only alias options can have alias args."); 32 assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); 33 assert(getAlias().getKind() != FlagClass && 34 "Cannot provide alias args to a flag option."); 35 } 36} 37 38Option::~Option() { 39} 40 41void Option::dump() const { 42 llvm::errs() << "<"; 43 switch (getKind()) { 44#define P(N) case N: llvm::errs() << #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#undef P 57 } 58 59 if (Info->Prefixes) { 60 llvm::errs() << " Prefixes:["; 61 for (const char * const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { 62 llvm::errs() << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); 63 } 64 llvm::errs() << ']'; 65 } 66 67 llvm::errs() << " Name:\"" << getName() << '"'; 68 69 const Option Group = getGroup(); 70 if (Group.isValid()) { 71 llvm::errs() << " Group:"; 72 Group.dump(); 73 } 74 75 const Option Alias = getAlias(); 76 if (Alias.isValid()) { 77 llvm::errs() << " Alias:"; 78 Alias.dump(); 79 } 80 81 if (getKind() == MultiArgClass) 82 llvm::errs() << " NumArgs:" << getNumArgs(); 83 84 llvm::errs() << ">\n"; 85} 86 87bool 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 103Arg *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 return A; 132 } 133 case JoinedClass: { 134 const char *Value = Args.getArgString(Index) + ArgSize; 135 return new Arg(UnaliasedOption, Spelling, Index++, Value); 136 } 137 case CommaJoinedClass: { 138 // Always matches. 139 const char *Str = Args.getArgString(Index) + ArgSize; 140 Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 141 142 // Parse out the comma separated values. 143 const char *Prev = Str; 144 for (;; ++Str) { 145 char c = *Str; 146 147 if (!c || c == ',') { 148 if (Prev != Str) { 149 char *Value = new char[Str - Prev + 1]; 150 memcpy(Value, Prev, Str - Prev); 151 Value[Str - Prev] = '\0'; 152 A->getValues().push_back(Value); 153 } 154 155 if (!c) 156 break; 157 158 Prev = Str + 1; 159 } 160 } 161 A->setOwnsValues(true); 162 163 return A; 164 } 165 case SeparateClass: 166 // Matches iff this is an exact match. 167 // FIXME: Avoid strlen. 168 if (ArgSize != strlen(Args.getArgString(Index))) 169 return nullptr; 170 171 Index += 2; 172 if (Index > Args.getNumInputArgStrings()) 173 return nullptr; 174 175 return new Arg(UnaliasedOption, Spelling, 176 Index - 2, Args.getArgString(Index - 1)); 177 case MultiArgClass: { 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 += 1 + getNumArgs(); 184 if (Index > Args.getNumInputArgStrings()) 185 return nullptr; 186 187 Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), 188 Args.getArgString(Index - getNumArgs())); 189 for (unsigned i = 1; i != getNumArgs(); ++i) 190 A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); 191 return A; 192 } 193 case JoinedOrSeparateClass: { 194 // If this is not an exact match, it is a joined arg. 195 // FIXME: Avoid strlen. 196 if (ArgSize != strlen(Args.getArgString(Index))) { 197 const char *Value = Args.getArgString(Index) + ArgSize; 198 return new Arg(*this, Spelling, Index++, Value); 199 } 200 201 // Otherwise it must be separate. 202 Index += 2; 203 if (Index > Args.getNumInputArgStrings()) 204 return nullptr; 205 206 return new Arg(UnaliasedOption, Spelling, 207 Index - 2, Args.getArgString(Index - 1)); 208 } 209 case JoinedAndSeparateClass: 210 // Always matches. 211 Index += 2; 212 if (Index > Args.getNumInputArgStrings()) 213 return nullptr; 214 215 return new Arg(UnaliasedOption, Spelling, Index - 2, 216 Args.getArgString(Index - 2) + ArgSize, 217 Args.getArgString(Index - 1)); 218 case RemainingArgsClass: { 219 // Matches iff this is an exact match. 220 // FIXME: Avoid strlen. 221 if (ArgSize != strlen(Args.getArgString(Index))) 222 return nullptr; 223 Arg *A = new Arg(UnaliasedOption, Spelling, Index++); 224 while (Index < Args.getNumInputArgStrings()) 225 A->getValues().push_back(Args.getArgString(Index++)); 226 return A; 227 } 228 default: 229 llvm_unreachable("Invalid option kind!"); 230 } 231} 232