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 "clang/Driver/Option.h"
11
12 #include "clang/Driver/Arg.h"
13 #include "clang/Driver/ArgList.h"
14 #include "llvm/Support/raw_ostream.h"
15 #include <cassert>
16 #include <algorithm>
17 using namespace clang::driver;
18
Option(OptionClass _Kind,OptSpecifier _ID,const char * _Name,const OptionGroup * _Group,const Option * _Alias)19 Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name,
20 const OptionGroup *_Group, const Option *_Alias)
21 : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias),
22 Unsupported(false), LinkerInput(false), NoOptAsInput(false),
23 DriverOption(false), NoArgumentUnused(false), NoForward(false) {
24
25 // Multi-level aliases are not supported, and alias options cannot
26 // have groups. This just simplifies option tracking, it is not an
27 // inherent limitation.
28 assert((!Alias || (!Alias->Alias && !Group)) &&
29 "Multi-level aliases and aliases with groups are unsupported.");
30
31 // Initialize rendering options based on the class.
32 switch (Kind) {
33 case GroupClass:
34 case InputClass:
35 case UnknownClass:
36 RenderStyle = RenderValuesStyle;
37 break;
38
39 case JoinedClass:
40 case JoinedAndSeparateClass:
41 RenderStyle = RenderJoinedStyle;
42 break;
43
44 case CommaJoinedClass:
45 RenderStyle = RenderCommaJoinedStyle;
46 break;
47
48 case FlagClass:
49 case SeparateClass:
50 case MultiArgClass:
51 case JoinedOrSeparateClass:
52 RenderStyle = RenderSeparateStyle;
53 break;
54 }
55 }
56
~Option()57 Option::~Option() {
58 }
59
dump() const60 void Option::dump() const {
61 llvm::errs() << "<";
62 switch (Kind) {
63 default:
64 assert(0 && "Invalid kind");
65 #define P(N) case N: llvm::errs() << #N; break
66 P(GroupClass);
67 P(InputClass);
68 P(UnknownClass);
69 P(FlagClass);
70 P(JoinedClass);
71 P(SeparateClass);
72 P(CommaJoinedClass);
73 P(MultiArgClass);
74 P(JoinedOrSeparateClass);
75 P(JoinedAndSeparateClass);
76 #undef P
77 }
78
79 llvm::errs() << " Name:\"" << Name << '"';
80
81 if (Group) {
82 llvm::errs() << " Group:";
83 Group->dump();
84 }
85
86 if (Alias) {
87 llvm::errs() << " Alias:";
88 Alias->dump();
89 }
90
91 if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this))
92 llvm::errs() << " NumArgs:" << MOA->getNumArgs();
93
94 llvm::errs() << ">\n";
95 }
96
matches(OptSpecifier Opt) const97 bool Option::matches(OptSpecifier Opt) const {
98 // Aliases are never considered in matching, look through them.
99 if (Alias)
100 return Alias->matches(Opt);
101
102 // Check exact match.
103 if (ID == Opt)
104 return true;
105
106 if (Group)
107 return Group->matches(Opt);
108 return false;
109 }
110
OptionGroup(OptSpecifier ID,const char * Name,const OptionGroup * Group)111 OptionGroup::OptionGroup(OptSpecifier ID, const char *Name,
112 const OptionGroup *Group)
113 : Option(Option::GroupClass, ID, Name, Group, 0) {
114 }
115
accept(const ArgList & Args,unsigned & Index) const116 Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const {
117 assert(0 && "accept() should never be called on an OptionGroup");
118 return 0;
119 }
120
InputOption(OptSpecifier ID)121 InputOption::InputOption(OptSpecifier ID)
122 : Option(Option::InputClass, ID, "<input>", 0, 0) {
123 }
124
accept(const ArgList & Args,unsigned & Index) const125 Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const {
126 assert(0 && "accept() should never be called on an InputOption");
127 return 0;
128 }
129
UnknownOption(OptSpecifier ID)130 UnknownOption::UnknownOption(OptSpecifier ID)
131 : Option(Option::UnknownClass, ID, "<unknown>", 0, 0) {
132 }
133
accept(const ArgList & Args,unsigned & Index) const134 Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const {
135 assert(0 && "accept() should never be called on an UnknownOption");
136 return 0;
137 }
138
FlagOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)139 FlagOption::FlagOption(OptSpecifier ID, const char *Name,
140 const OptionGroup *Group, const Option *Alias)
141 : Option(Option::FlagClass, ID, Name, Group, Alias) {
142 }
143
accept(const ArgList & Args,unsigned & Index) const144 Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const {
145 // Matches iff this is an exact match.
146 // FIXME: Avoid strlen.
147 if (getName().size() != strlen(Args.getArgString(Index)))
148 return 0;
149
150 return new Arg(getUnaliasedOption(), Index++);
151 }
152
JoinedOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)153 JoinedOption::JoinedOption(OptSpecifier ID, const char *Name,
154 const OptionGroup *Group, const Option *Alias)
155 : Option(Option::JoinedClass, ID, Name, Group, Alias) {
156 }
157
accept(const ArgList & Args,unsigned & Index) const158 Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const {
159 // Always matches.
160 const char *Value = Args.getArgString(Index) + getName().size();
161 return new Arg(getUnaliasedOption(), Index++, Value);
162 }
163
CommaJoinedOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)164 CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name,
165 const OptionGroup *Group,
166 const Option *Alias)
167 : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) {
168 }
169
accept(const ArgList & Args,unsigned & Index) const170 Arg *CommaJoinedOption::accept(const ArgList &Args,
171 unsigned &Index) const {
172 // Always matches.
173 const char *Str = Args.getArgString(Index) + getName().size();
174 Arg *A = new Arg(getUnaliasedOption(), Index++);
175
176 // Parse out the comma separated values.
177 const char *Prev = Str;
178 for (;; ++Str) {
179 char c = *Str;
180
181 if (!c || c == ',') {
182 if (Prev != Str) {
183 char *Value = new char[Str - Prev + 1];
184 memcpy(Value, Prev, Str - Prev);
185 Value[Str - Prev] = '\0';
186 A->getValues().push_back(Value);
187 }
188
189 if (!c)
190 break;
191
192 Prev = Str + 1;
193 }
194 }
195 A->setOwnsValues(true);
196
197 return A;
198 }
199
SeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)200 SeparateOption::SeparateOption(OptSpecifier ID, const char *Name,
201 const OptionGroup *Group, const Option *Alias)
202 : Option(Option::SeparateClass, ID, Name, Group, Alias) {
203 }
204
accept(const ArgList & Args,unsigned & Index) const205 Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const {
206 // Matches iff this is an exact match.
207 // FIXME: Avoid strlen.
208 if (getName().size() != strlen(Args.getArgString(Index)))
209 return 0;
210
211 Index += 2;
212 if (Index > Args.getNumInputArgStrings())
213 return 0;
214
215 return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
216 }
217
MultiArgOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias,unsigned _NumArgs)218 MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name,
219 const OptionGroup *Group, const Option *Alias,
220 unsigned _NumArgs)
221 : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) {
222 assert(NumArgs > 1 && "Invalid MultiArgOption!");
223 }
224
accept(const ArgList & Args,unsigned & Index) const225 Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const {
226 // Matches iff this is an exact match.
227 // FIXME: Avoid strlen.
228 if (getName().size() != strlen(Args.getArgString(Index)))
229 return 0;
230
231 Index += 1 + NumArgs;
232 if (Index > Args.getNumInputArgStrings())
233 return 0;
234
235 Arg *A = new Arg(getUnaliasedOption(), Index - 1 - NumArgs,
236 Args.getArgString(Index - NumArgs));
237 for (unsigned i = 1; i != NumArgs; ++i)
238 A->getValues().push_back(Args.getArgString(Index - NumArgs + i));
239 return A;
240 }
241
JoinedOrSeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)242 JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID,
243 const char *Name,
244 const OptionGroup *Group,
245 const Option *Alias)
246 : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
247 }
248
accept(const ArgList & Args,unsigned & Index) const249 Arg *JoinedOrSeparateOption::accept(const ArgList &Args,
250 unsigned &Index) const {
251 // If this is not an exact match, it is a joined arg.
252 // FIXME: Avoid strlen.
253 if (getName().size() != strlen(Args.getArgString(Index))) {
254 const char *Value = Args.getArgString(Index) + getName().size();
255 return new Arg(this, Index++, Value);
256 }
257
258 // Otherwise it must be separate.
259 Index += 2;
260 if (Index > Args.getNumInputArgStrings())
261 return 0;
262
263 return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
264 }
265
JoinedAndSeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)266 JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID,
267 const char *Name,
268 const OptionGroup *Group,
269 const Option *Alias)
270 : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
271 }
272
accept(const ArgList & Args,unsigned & Index) const273 Arg *JoinedAndSeparateOption::accept(const ArgList &Args,
274 unsigned &Index) const {
275 // Always matches.
276
277 Index += 2;
278 if (Index > Args.getNumInputArgStrings())
279 return 0;
280
281 return new Arg(getUnaliasedOption(), Index - 2,
282 Args.getArgString(Index-2)+getName().size(),
283 Args.getArgString(Index-1));
284 }
285