 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
79.4% |
139 / 175 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
79.4% |
139 / 175 |
| |
|
Line Coverage: |
93.9% |
170 / 181 |
| |
 |
|
 |
1 : //===--- OptTable.cpp - Option Table Implementation ---------------------*-===//
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/OptTable.h"
11 : #include "clang/Driver/Arg.h"
12 : #include "clang/Driver/ArgList.h"
13 : #include "clang/Driver/Option.h"
14 : #include "llvm/Support/raw_ostream.h"
15 : #include <algorithm>
16 : #include <cassert>
17 : #include <map>
18 : using namespace clang::driver;
19 : using namespace clang::driver::options;
20 :
21 : // Ordering on Info. The ordering is *almost* lexicographic, with two
22 : // exceptions. First, '\0' comes at the end of the alphabet instead of
23 : // the beginning (thus options preceed any other options which prefix
24 : // them). Second, for options with the same name, the less permissive
25 : // version should come first; a Flag option should preceed a Joined
26 : // option, for example.
27 :
28 688341: static int StrCmpOptionName(const char *A, const char *B) {
29 688341: char a = *A, b = *B;
3444839: branch 0 taken
678089: branch 1 taken
30 4811269: while (a == b) {
10252: branch 0 taken
3434587: branch 1 taken
31 3444839: if (a == '\0')
32 10252: return 0;
33 :
34 3434587: a = *++A;
35 3434587: b = *++B;
36 : }
37 :
2913: branch 0 taken
675176: branch 1 taken
38 678089: if (a == '\0') // A is a prefix of B.
39 2913: return 1;
81068: branch 0 taken
594108: branch 1 taken
40 675176: if (b == '\0') // B is a prefix of A.
41 81068: return -1;
42 :
43 : // Otherwise lexicographic.
569418: branch 0 taken
24690: branch 1 taken
44 594108: return (a < b) ? -1 : 1;
45 : }
46 :
47 : namespace clang {
48 : namespace driver {
49 610519: static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
0: branch 0 not taken
610519: branch 1 taken
50 610519: if (&A == &B)
51 0: return false;
52 :
609279: branch 1 taken
1240: branch 2 taken
53 610519: if (int N = StrCmpOptionName(A.Name, B.Name))
54 609279: return N == -1;
55 :
56 : // Names are the same, check that classes are in order; exactly one
57 : // should be joined, and it should succeed the other.
58 : assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
0: branch 0 not taken
1240: branch 1 taken
59 1240: "Unexpected classes for options with same name.");
60 1240: return B.Kind == Option::JoinedClass;
61 : }
62 :
63 : // Support lower_bound between info and an option name.
64 77822: static inline bool operator<(const OptTable::Info &I, const char *Name) {
65 77822: return StrCmpOptionName(I.Name, Name) == -1;
66 : }
67 : static inline bool operator<(const char *Name, const OptTable::Info &I) {
68 : return StrCmpOptionName(Name, I.Name) == -1;
69 : }
70 : }
71 : }
72 :
73 : //
74 :
75 18: OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
76 :
77 : //
78 :
79 2771: OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
80 : : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos),
81 : Options(new Option*[NumOptionInfos]),
82 2771: TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0)
83 : {
84 : // Explicitly zero initialize the error to work around a bug in array
85 : // value-initialization on MinGW with gcc 4.3.5.
86 2771: memset(Options, 0, sizeof(*Options) * NumOptionInfos);
87 :
88 : // Find start of normal options.
0: branch 1 not taken
0: branch 2 not taken
16292: branch 4 taken
0: branch 5 not taken
89 16292: for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
90 16292: unsigned Kind = getInfo(i + 1).Kind;
16292: branch 0 taken
16292: branch 1 taken
2771: branch 2 taken
13521: branch 3 taken
91 16292: if (Kind == Option::InputClass) {
2771: branch 0 taken
2771: branch 1 taken
0: branch 3 not taken
2771: branch 4 taken
92 2771: assert(!TheInputOption && "Cannot have multiple input options!");
93 2771: TheInputOption = getOption(i + 1);
13521: branch 0 taken
13521: branch 1 taken
2771: branch 2 taken
10750: branch 3 taken
94 13521: } else if (Kind == Option::UnknownClass) {
2771: branch 0 taken
2771: branch 1 taken
0: branch 3 not taken
2771: branch 4 taken
95 2771: assert(!TheUnknownOption && "Cannot have multiple input options!");
96 2771: TheUnknownOption = getOption(i + 1);
10750: branch 0 taken
10750: branch 1 taken
2771: branch 2 taken
7979: branch 3 taken
97 10750: } else if (Kind != Option::GroupClass) {
98 2771: FirstSearchableIndex = i;
99 2771: break;
100 : }
101 : }
2771: branch 0 taken
2771: branch 1 taken
0: branch 3 not taken
2771: branch 4 taken
102 2771: assert(FirstSearchableIndex != 0 && "No searchable options?");
103 :
104 : #ifndef NDEBUG
105 : // Check that everything after the first searchable option is a
106 : // regular option class.
0: branch 1 not taken
0: branch 2 not taken
613290: branch 4 taken
2771: branch 5 taken
107 616061: for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
108 613290: Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
109 : assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
110 : Kind != Option::GroupClass) &&
613290: branch 0 taken
613290: branch 1 taken
613290: branch 2 taken
613290: branch 3 taken
613290: branch 4 taken
613290: branch 5 taken
613290: branch 7 taken
0: branch 8 not taken
613290: branch 9 taken
0: branch 10 not taken
0: branch 11 not taken
613290: branch 12 taken
111 613290: "Special options should be defined first!");
112 : }
113 :
114 : // Check that options are in order.
0: branch 1 not taken
0: branch 2 not taken
610519: branch 4 taken
2771: branch 5 taken
115 613290: for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
0: branch 5 not taken
0: branch 6 not taken
0: branch 12 not taken
610519: branch 13 taken
116 610519: if (!(getInfo(i) < getInfo(i + 1))) {
117 0: getOption(i)->dump();
118 0: getOption(i + 1)->dump();
119 0: assert(0 && "Options are not in order!");
120 : }
121 : }
122 : #endif
123 2771: }
124 :
125 2771: OptTable::~OptTable() {
626811: branch 1 taken
2771: branch 2 taken
0: branch 4 not taken
0: branch 5 not taken
126 629582: for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
18773: branch 0 taken
608038: branch 1 taken
18773: branch 3 taken
18773: branch 4 taken
127 626811: delete Options[i];
2771: branch 0 taken
0: branch 1 not taken
2771: branch 3 taken
2771: branch 4 taken
128 2771: delete[] Options;
129 2771: }
130 :
131 18773: Option *OptTable::CreateOption(unsigned id) const {
132 18773: const Info &info = getInfo(id);
133 : const OptionGroup *Group =
134 18773: cast_or_null<OptionGroup>(getOption(info.GroupID));
135 18773: const Option *Alias = getOption(info.AliasID);
136 :
137 18773: Option *Opt = 0;
2771: branch 0 taken
2771: branch 1 taken
3056: branch 2 taken
6069: branch 3 taken
877: branch 4 taken
2985: branch 5 taken
1: branch 6 taken
9: branch 7 taken
230: branch 8 taken
4: branch 9 taken
0: branch 10 not taken
138 18773: switch (info.Kind) {
139 : case Option::InputClass:
140 2771: Opt = new InputOption(id); break;
141 : case Option::UnknownClass:
142 2771: Opt = new UnknownOption(id); break;
143 : case Option::GroupClass:
144 3056: Opt = new OptionGroup(id, info.Name, Group); break;
145 : case Option::FlagClass:
146 6069: Opt = new FlagOption(id, info.Name, Group, Alias); break;
147 : case Option::JoinedClass:
148 877: Opt = new JoinedOption(id, info.Name, Group, Alias); break;
149 : case Option::SeparateClass:
150 2985: Opt = new SeparateOption(id, info.Name, Group, Alias); break;
151 : case Option::CommaJoinedClass:
152 1: Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
153 : case Option::MultiArgClass:
154 9: Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
155 : case Option::JoinedOrSeparateClass:
156 230: Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
157 : case Option::JoinedAndSeparateClass:
158 4: Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
159 : }
160 :
3401: branch 0 taken
15372: branch 1 taken
161 18773: if (info.Flags & DriverOption)
162 3401: Opt->setDriverOption(true);
7: branch 0 taken
18766: branch 1 taken
163 18773: if (info.Flags & LinkerInput)
164 7: Opt->setLinkerInput(true);
8: branch 0 taken
18765: branch 1 taken
165 18773: if (info.Flags & NoArgumentUnused)
166 8: Opt->setNoArgumentUnused(true);
72: branch 0 taken
18701: branch 1 taken
167 18773: if (info.Flags & RenderAsInput)
168 72: Opt->setNoOptAsInput(true);
0: branch 0 not taken
18773: branch 1 taken
169 18773: if (info.Flags & RenderJoined) {
0: branch 0 not taken
0: branch 1 not taken
170 0: assert(info.Kind == Option::SeparateClass && "Invalid option.");
171 0: Opt->setForceJoinedRender(true);
172 : }
0: branch 0 not taken
18773: branch 1 taken
173 18773: if (info.Flags & RenderSeparate) {
0: branch 0 not taken
0: branch 1 not taken
174 0: assert(info.Kind == Option::JoinedClass && "Invalid option.");
175 0: Opt->setForceSeparateRender(true);
176 : }
1: branch 0 taken
18772: branch 1 taken
177 18773: if (info.Flags & Unsupported)
178 1: Opt->setUnsupported(true);
179 :
180 18773: return Opt;
181 : }
182 :
183 12572: Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const {
184 12572: unsigned Prev = Index;
185 12572: const char *Str = Args.getArgString(Index);
186 :
187 : // Anything that doesn't start with '-' is an input, as is '-' itself.
9911: branch 0 taken
2661: branch 1 taken
17: branch 2 taken
9894: branch 3 taken
188 12572: if (Str[0] != '-' || Str[1] == '\0')
189 2678: return new PositionalArg(TheInputOption, Index++);
190 :
191 9894: const Info *Start = OptionInfos + FirstSearchableIndex;
192 9894: const Info *End = OptionInfos + getNumOptions();
193 :
194 : // Search for the first next option which could be a prefix.
195 9894: Start = std::lower_bound(Start, End, Str);
196 :
197 : // Options are stored in sorted order, with '\0' at the end of the
198 : // alphabet. Since the only options which can accept a string must
199 : // prefix it, we iteratively search for the next option which could
200 : // be a prefix.
201 : //
202 : // FIXME: This is searching much more than necessary, but I am
203 : // blanking on the simplest way to make it fast. We can solve this
204 : // problem when we move to TableGen.
9902: branch 0 taken
0: branch 1 not taken
205 9902: for (; Start != End; ++Start) {
206 : // Scan for first option which is a proper prefix.
10746: branch 0 taken
6: branch 1 taken
207 10752: for (; Start != End; ++Start)
9896: branch 2 taken
850: branch 3 taken
208 10746: if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
209 9896: break;
6: branch 0 taken
9896: branch 1 taken
210 9902: if (Start == End)
211 6: break;
212 :
213 : // See if this option matches.
9885: branch 3 taken
11: branch 4 taken
214 9896: if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index))
215 9885: return A;
216 :
217 : // Otherwise, see if this argument was missing values.
3: branch 0 taken
8: branch 1 taken
218 11: if (Prev != Index)
219 3: return 0;
220 : }
221 :
222 6: return new PositionalArg(TheUnknownOption, Index++);
223 : }
224 :
225 : InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd,
226 : unsigned &MissingArgIndex,
227 2771: unsigned &MissingArgCount) const {
228 2771: InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
229 :
230 : // FIXME: Handle '@' args (or at least error on them).
231 :
232 2771: MissingArgIndex = MissingArgCount = 0;
233 2771: unsigned Index = 0, End = ArgEnd - ArgBegin;
12569: branch 0 taken
2769: branch 1 taken
234 18109: while (Index < End) {
235 : // Ignore empty arguments (other things may still take them as arguments).
1: branch 1 taken
12568: branch 2 taken
236 12569: if (Args->getArgString(Index)[0] == '\0') {
237 1: ++Index;
238 1: continue;
239 : }
240 :
241 12568: unsigned Prev = Index;
242 12568: Arg *A = ParseOneArg(*Args, Index);
0: branch 0 not taken
12568: branch 1 taken
243 12568: assert(Index > Prev && "Parser failed to consume argument.");
244 :
245 : // Check for missing argument error.
2: branch 0 taken
12566: branch 1 taken
246 12568: if (!A) {
0: branch 0 not taken
2: branch 1 taken
247 2: assert(Index >= End && "Unexpected parser error.");
0: branch 0 not taken
2: branch 1 taken
248 2: assert(Index - Prev - 1 && "No missing arguments!");
249 2: MissingArgIndex = Prev;
250 2: MissingArgCount = Index - Prev - 1;
251 2: break;
252 : }
253 :
254 12566: Args->append(A);
255 : }
256 :
257 2771: return Args;
258 : }
259 :
260 78: static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
261 78: std::string Name = Opts.getOptionName(Id);
262 :
263 : // Add metavar, if used.
0: branch 1 not taken
0: branch 2 not taken
50: branch 3 taken
18: branch 4 taken
10: branch 5 taken
0: branch 6 not taken
264 78: switch (Opts.getOptionKind(Id)) {
265 : case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
266 0: assert(0 && "Invalid option with help text.");
267 :
268 : case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
269 0: assert(0 && "Cannot print metavar for this kind of option.");
270 :
271 : case Option::FlagClass:
272 50: break;
273 :
274 : case Option::SeparateClass: case Option::JoinedOrSeparateClass:
275 18: Name += ' ';
276 : // FALLTHROUGH
277 : case Option::JoinedClass: case Option::CommaJoinedClass:
26: branch 1 taken
2: branch 2 taken
278 28: if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
279 26: Name += MetaVarName;
280 : else
281 2: Name += "<value>";
282 : break;
283 : }
284 :
285 : return Name;
286 : }
287 :
288 : static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title,
289 : std::vector<std::pair<std::string,
290 4: const char*> > &OptionHelp) {
291 4: OS << Title << ":\n";
292 :
293 : // Find the maximum option length.
294 4: unsigned OptionFieldWidth = 0;
78: branch 1 taken
4: branch 2 taken
295 82: for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
296 : // Skip titles.
0: branch 1 not taken
78: branch 2 taken
297 78: if (!OptionHelp[i].second)
298 0: continue;
299 :
300 : // Limit the amount of padding we are willing to give up for alignment.
301 78: unsigned Length = OptionHelp[i].first.size();
72: branch 0 taken
6: branch 1 taken
302 78: if (Length <= 23)
303 72: OptionFieldWidth = std::max(OptionFieldWidth, Length);
304 : }
305 :
306 4: const unsigned InitialPad = 2;
78: branch 1 taken
4: branch 2 taken
307 82: for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
308 78: const std::string &Option = OptionHelp[i].first;
309 78: int Pad = OptionFieldWidth - int(Option.size());
310 78: OS.indent(InitialPad) << Option;
311 :
312 : // Break on long option names.
6: branch 0 taken
72: branch 1 taken
313 78: if (Pad < 0) {
314 6: OS << "\n";
315 6: Pad = OptionFieldWidth + InitialPad;
316 : }
317 78: OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
318 : }
319 4: }
320 :
321 82: static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
322 82: unsigned GroupID = Opts.getOptionGroupID(Id);
323 :
324 : // If not in a group, return the default help group.
63: branch 0 taken
19: branch 1 taken
325 82: if (!GroupID)
326 63: return "OPTIONS";
327 :
328 : // Abuse the help text of the option groups to store the "help group"
329 : // name.
330 : //
331 : // FIXME: Split out option groups.
15: branch 2 taken
4: branch 3 taken
332 19: if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
333 15: return GroupHelp;
334 :
335 : // Otherwise keep looking.
336 4: return getOptionHelpGroup(Opts, GroupID);
337 : }
338 :
339 : void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name,
340 2: const char *Title, bool ShowHidden) const {
341 2: OS << "OVERVIEW: " << Title << "\n";
342 2: OS << '\n';
343 2: OS << "USAGE: " << Name << " [options] <inputs>\n";
344 2: OS << '\n';
345 :
346 : // Render help text into a map of group-name to a list of (option, help)
347 : // pairs.
348 : typedef std::map<std::string,
349 : std::vector<std::pair<std::string, const char*> > > helpmap_ty;
350 2: helpmap_ty GroupedOptionHelp;
351 :
1128: branch 1 taken
2: branch 2 taken
352 1130: for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
353 1128: unsigned Id = i + 1;
354 :
355 : // FIXME: Split out option groups.
44: branch 2 taken
1084: branch 3 taken
356 1128: if (getOptionKind(Id) == Option::GroupClass)
357 44: continue;
358 :
542: branch 0 taken
542: branch 1 taken
17: branch 4 taken
525: branch 5 taken
17: branch 6 taken
1067: branch 7 taken
359 1084: if (!ShowHidden && isOptionHelpHidden(Id))
360 17: continue;
361 :
78: branch 2 taken
989: branch 3 taken
362 1067: if (const char *Text = getOptionHelpText(Id)) {
363 78: const char *HelpGroup = getOptionHelpGroup(*this, Id);
364 78: const std::string &OptName = getOptionHelpName(*this, Id);
365 78: GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
366 : }
367 : }
368 :
4: branch 3 taken
2: branch 4 taken
369 8: for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
370 2: ie = GroupedOptionHelp.end(); it != ie; ++it) {
2: branch 2 taken
2: branch 3 taken
371 4: if (it != GroupedOptionHelp .begin())
372 2: OS << "\n";
373 4: PrintHelpOptionList(OS, it->first, it->second);
374 : }
375 :
376 2: OS.flush();
377 2: }
Generated: 2010-02-10 01:31 by zcov