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