OptTable.cpp revision ba7db7d8b4ea8f9c24aba8c75a228ffc0857964e
1//===--- Options.cpp - Option info table --------------------------------*-===//
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/Options.h"
11
12#include "clang/Driver/Arg.h"
13#include "clang/Driver/ArgList.h"
14#include "clang/Driver/Option.h"
15#include <cassert>
16
17using namespace clang::driver;
18using namespace clang::driver::options;
19
20struct Info {
21  const char *Name;
22  const char *Flags;
23
24  Option::OptionClass Kind;
25  unsigned GroupID;
26  unsigned AliasID;
27  unsigned Param;
28};
29
30static Info OptionInfos[] = {
31  // The InputOption info
32  { "<input>", "", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 },
33  // The UnknownOption info
34  { "<unknown>", "", Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 },
35
36#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM)              \
37  { NAME, FLAGS, Option::KIND##Class, OPT_##GROUP, OPT_##ALIAS, PARAM },
38#include "clang/Driver/Options.def"
39};
40static const unsigned numOptions = sizeof(OptionInfos) / sizeof(OptionInfos[0]);
41
42static Info &getInfo(unsigned id) {
43  assert(id > 0 && id - 1 < numOptions && "Invalid Option ID.");
44  return OptionInfos[id - 1];
45}
46
47OptTable::OptTable() : Options(new Option*[numOptions]) {
48  memset(Options, 0, sizeof(*Options) * numOptions);
49}
50
51OptTable::~OptTable() {
52  for (unsigned i=0; i<numOptions; ++i)
53    delete Options[i];
54  delete[] Options;
55}
56
57unsigned OptTable::getNumOptions() const {
58  return numOptions;
59}
60
61const char *OptTable::getOptionName(options::ID id) const {
62  return getInfo(id).Name;
63}
64
65const Option *OptTable::getOption(options::ID id) const {
66  if (id == OPT_INVALID)
67    return 0;
68
69  assert((unsigned) (id - 1) < numOptions && "Invalid ID.");
70
71  Option *&Entry = Options[id - 1];
72  if (!Entry)
73    Entry = constructOption(id);
74
75  return Entry;
76}
77
78Option *OptTable::constructOption(options::ID id) const {
79  Info &info = getInfo(id);
80  const OptionGroup *Group =
81    cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID));
82  const Option *Alias = getOption((options::ID) info.AliasID);
83
84  Option *Opt = 0;
85  switch (info.Kind) {
86  case Option::InputClass:
87    Opt = new InputOption(); break;
88  case Option::UnknownClass:
89    Opt = new UnknownOption(); break;
90  case Option::GroupClass:
91    Opt = new OptionGroup(id, info.Name, Group); break;
92  case Option::FlagClass:
93    Opt = new FlagOption(id, info.Name, Group, Alias); break;
94  case Option::JoinedClass:
95    Opt = new JoinedOption(id, info.Name, Group, Alias); break;
96  case Option::SeparateClass:
97    Opt = new SeparateOption(id, info.Name, Group, Alias); break;
98  case Option::CommaJoinedClass:
99    Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
100  case Option::MultiArgClass:
101    Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
102  case Option::JoinedOrSeparateClass:
103    Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
104  case Option::JoinedAndSeparateClass:
105    Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
106  }
107
108  for (const char *s = info.Flags; *s; ++s) {
109    switch (*s) {
110    default: assert(0 && "Invalid option flag.");
111    case 'J': Opt->setForceJoinedRender(true); break;
112    case 'S': Opt->setForceSeparateRender(true); break;
113    case 'i': Opt->setNoOptAsInput(true); break;
114    case 'l': Opt->setLinkerInput(true); break;
115    case 'u': Opt->setUnsupported(true); break;
116    }
117  }
118
119  return Opt;
120}
121
122Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
123                           unsigned IndexEnd) const {
124  const char *Str = Args.getArgString(Index);
125
126  // Anything that doesn't start with '-' is an input, as is '-' itself.
127  if (Str[0] != '-' || Str[1] == '\0')
128    return new PositionalArg(getOption(OPT_INPUT), Index++);
129
130  for (unsigned j = OPT_UNKNOWN + 1; j < LastOption; ++j) {
131    const char *OptName = getOptionName((options::ID) j);
132
133    // Arguments are only accepted by options which prefix them.
134    if (memcmp(Str, OptName, strlen(OptName)) == 0)
135      if (Arg *A = getOption((options::ID) j)->accept(Args, Index))
136        return A;
137  }
138
139  return new PositionalArg(getOption(OPT_UNKNOWN), Index++);
140}
141
142