OptTable.cpp revision 9a242512a8b319cc4df7d050166a1c65bf66abeb
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
18using namespace clang::driver;
19using 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
28static int StrCmpOptionName(const char *A, const char *B) {
29  char a = *A, b = *B;
30  while (a == b) {
31    if (a == '\0')
32      return 0;
33
34    a = *++A;
35    b = *++B;
36  }
37
38  if (a == '\0') // A is a prefix of B.
39    return 1;
40  if (b == '\0') // B is a prefix of A.
41    return -1;
42
43  // Otherwise lexicographic.
44  return (a < b) ? -1 : 1;
45}
46
47namespace clang {
48namespace driver {
49static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
50  if (&A == &B)
51    return false;
52
53  if (int N = StrCmpOptionName(A.Name, B.Name))
54    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)) &&
59         "Unexpected classes for options with same name.");
60  return B.Kind == Option::JoinedClass;
61}
62
63// Support lower_bound between info and an option name.
64static inline bool operator<(const OptTable::Info &I, const char *Name) {
65  return StrCmpOptionName(I.Name, Name) == -1;
66}
67static inline bool operator<(const char *Name, const OptTable::Info &I) {
68  return StrCmpOptionName(Name, I.Name) == -1;
69}
70}
71}
72
73//
74
75OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
76
77//
78
79OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
80  : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos),
81    Options(new Option*[NumOptionInfos]),
82    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  memset(Options, 0, sizeof(*Options) * NumOptionInfos);
87
88  // Find start of normal options.
89  for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
90    unsigned Kind = getInfo(i + 1).Kind;
91    if (Kind == Option::InputClass) {
92      assert(!TheInputOption && "Cannot have multiple input options!");
93      TheInputOption = getOption(i + 1);
94    } else if (Kind == Option::UnknownClass) {
95      assert(!TheUnknownOption && "Cannot have multiple input options!");
96      TheUnknownOption = getOption(i + 1);
97    } else if (Kind != Option::GroupClass) {
98      FirstSearchableIndex = i;
99      break;
100    }
101  }
102  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.
107  for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
108    Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
109    assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
110            Kind != Option::GroupClass) &&
111           "Special options should be defined first!");
112  }
113
114  // Check that options are in order.
115  for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
116    if (!(getInfo(i) < getInfo(i + 1))) {
117      getOption(i)->dump();
118      getOption(i + 1)->dump();
119      assert(0 && "Options are not in order!");
120    }
121  }
122#endif
123}
124
125OptTable::~OptTable() {
126  for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
127    delete Options[i];
128  delete[] Options;
129}
130
131Option *OptTable::CreateOption(unsigned id) const {
132  const Info &info = getInfo(id);
133  const OptionGroup *Group =
134    cast_or_null<OptionGroup>(getOption(info.GroupID));
135  const Option *Alias = getOption(info.AliasID);
136
137  Option *Opt = 0;
138  switch (info.Kind) {
139  case Option::InputClass:
140    Opt = new InputOption(id); break;
141  case Option::UnknownClass:
142    Opt = new UnknownOption(id); break;
143  case Option::GroupClass:
144    Opt = new OptionGroup(id, info.Name, Group); break;
145  case Option::FlagClass:
146    Opt = new FlagOption(id, info.Name, Group, Alias); break;
147  case Option::JoinedClass:
148    Opt = new JoinedOption(id, info.Name, Group, Alias); break;
149  case Option::SeparateClass:
150    Opt = new SeparateOption(id, info.Name, Group, Alias); break;
151  case Option::CommaJoinedClass:
152    Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
153  case Option::MultiArgClass:
154    Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
155  case Option::JoinedOrSeparateClass:
156    Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
157  case Option::JoinedAndSeparateClass:
158    Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
159  }
160
161  if (info.Flags & DriverOption)
162    Opt->setDriverOption(true);
163  if (info.Flags & LinkerInput)
164    Opt->setLinkerInput(true);
165  if (info.Flags & NoArgumentUnused)
166    Opt->setNoArgumentUnused(true);
167  if (info.Flags & RenderAsInput)
168    Opt->setNoOptAsInput(true);
169  if (info.Flags & RenderJoined) {
170    assert(info.Kind == Option::SeparateClass && "Invalid option.");
171    Opt->setForceJoinedRender(true);
172  }
173  if (info.Flags & RenderSeparate) {
174    assert(info.Kind == Option::JoinedClass && "Invalid option.");
175    Opt->setForceSeparateRender(true);
176  }
177  if (info.Flags & Unsupported)
178    Opt->setUnsupported(true);
179
180  return Opt;
181}
182
183Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const {
184  unsigned Prev = Index;
185  const char *Str = Args.getArgString(Index);
186
187  // Anything that doesn't start with '-' is an input, as is '-' itself.
188  if (Str[0] != '-' || Str[1] == '\0')
189    return new PositionalArg(TheInputOption, Index++);
190
191  const Info *Start = OptionInfos + FirstSearchableIndex;
192  const Info *End = OptionInfos + getNumOptions();
193
194  // Search for the first next option which could be a prefix.
195  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.
205  for (; Start != End; ++Start) {
206    // Scan for first option which is a proper prefix.
207    for (; Start != End; ++Start)
208      if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
209        break;
210    if (Start == End)
211      break;
212
213    // See if this option matches.
214    if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index))
215      return A;
216
217    // Otherwise, see if this argument was missing values.
218    if (Prev != Index)
219      return 0;
220  }
221
222  return new PositionalArg(TheUnknownOption, Index++);
223}
224
225InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd,
226                                  unsigned &MissingArgIndex,
227                                  unsigned &MissingArgCount) const {
228  InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
229
230  // FIXME: Handle '@' args (or at least error on them).
231
232  MissingArgIndex = MissingArgCount = 0;
233  unsigned Index = 0, End = ArgEnd - ArgBegin;
234  while (Index < End) {
235    // Ignore empty arguments (other things may still take them as arguments).
236    if (Args->getArgString(Index)[0] == '\0') {
237      ++Index;
238      continue;
239    }
240
241    unsigned Prev = Index;
242    Arg *A = ParseOneArg(*Args, Index);
243    assert(Index > Prev && "Parser failed to consume argument.");
244
245    // Check for missing argument error.
246    if (!A) {
247      assert(Index >= End && "Unexpected parser error.");
248      assert(Index - Prev - 1 && "No missing arguments!");
249      MissingArgIndex = Prev;
250      MissingArgCount = Index - Prev - 1;
251      break;
252    }
253
254    Args->append(A);
255  }
256
257  return Args;
258}
259
260static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
261  std::string Name = Opts.getOptionName(Id);
262
263  // Add metavar, if used.
264  switch (Opts.getOptionKind(Id)) {
265  case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
266    assert(0 && "Invalid option with help text.");
267
268  case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
269    assert(0 && "Cannot print metavar for this kind of option.");
270
271  case Option::FlagClass:
272    break;
273
274  case Option::SeparateClass: case Option::JoinedOrSeparateClass:
275    Name += ' ';
276    // FALLTHROUGH
277  case Option::JoinedClass: case Option::CommaJoinedClass:
278    if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
279      Name += MetaVarName;
280    else
281      Name += "<value>";
282    break;
283  }
284
285  return Name;
286}
287
288void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name,
289                         const char *Title, bool ShowHidden) const {
290  OS << "OVERVIEW: " << Title << "\n";
291  OS << '\n';
292  OS << "USAGE: " << Name << " [options] <inputs>\n";
293  OS << '\n';
294  OS << "OPTIONS:\n";
295
296  // Render help text into (option, help) pairs.
297  std::vector< std::pair<std::string, const char*> > OptionHelp;
298  for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
299    unsigned Id = i + 1;
300
301    if (!ShowHidden && isOptionHelpHidden(Id))
302      continue;
303
304    if (const char *Text = getOptionHelpText(Id))
305      OptionHelp.push_back(std::make_pair(getOptionHelpName(*this, Id), Text));
306  }
307
308  // Find the maximum option length.
309  unsigned OptionFieldWidth = 0;
310  for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
311    // Skip titles.
312    if (!OptionHelp[i].second)
313      continue;
314
315    // Limit the amount of padding we are willing to give up for alignment.
316    unsigned Length = OptionHelp[i].first.size();
317    if (Length <= 23)
318      OptionFieldWidth = std::max(OptionFieldWidth, Length);
319  }
320
321  const unsigned InitialPad = 2;
322  for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
323    const std::string &Option = OptionHelp[i].first;
324    int Pad = OptionFieldWidth - int(Option.size());
325    OS.indent(InitialPad) << Option;
326
327    // Break on long option names.
328    if (Pad < 0) {
329      OS << "\n";
330      Pad = OptionFieldWidth + InitialPad;
331    }
332    OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
333  }
334
335  OS.flush();
336}
337