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#include "clang/Driver/Arg.h"
12#include "clang/Driver/ArgList.h"
13#include "llvm/ADT/Twine.h"
14#include "llvm/Support/ErrorHandling.h"
15#include "llvm/Support/raw_ostream.h"
16#include <algorithm>
17#include <cassert>
18using namespace clang::driver;
19
20Option::Option(const OptTable::Info *info, const OptTable *owner)
21  : Info(info), Owner(owner) {
22
23  // Multi-level aliases are not supported, and alias options cannot
24  // have groups. This just simplifies option tracking, it is not an
25  // inherent limitation.
26  assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
27         !getGroup().isValid())) &&
28         "Multi-level aliases and aliases with groups are unsupported.");
29}
30
31Option::~Option() {
32}
33
34void Option::dump() const {
35  llvm::errs() << "<";
36  switch (getKind()) {
37#define P(N) case N: llvm::errs() << #N; break
38    P(GroupClass);
39    P(InputClass);
40    P(UnknownClass);
41    P(FlagClass);
42    P(JoinedClass);
43    P(SeparateClass);
44    P(CommaJoinedClass);
45    P(MultiArgClass);
46    P(JoinedOrSeparateClass);
47    P(JoinedAndSeparateClass);
48#undef P
49  }
50
51  llvm::errs() << " Prefixes:[";
52  for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
53    llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
54  }
55  llvm::errs() << ']';
56
57  llvm::errs() << " Name:\"" << getName() << '"';
58
59  const Option Group = getGroup();
60  if (Group.isValid()) {
61    llvm::errs() << " Group:";
62    Group.dump();
63  }
64
65  const Option Alias = getAlias();
66  if (Alias.isValid()) {
67    llvm::errs() << " Alias:";
68    Alias.dump();
69  }
70
71  if (getKind() == MultiArgClass)
72    llvm::errs() << " NumArgs:" << getNumArgs();
73
74  llvm::errs() << ">\n";
75}
76
77bool Option::matches(OptSpecifier Opt) const {
78  // Aliases are never considered in matching, look through them.
79  const Option Alias = getAlias();
80  if (Alias.isValid())
81    return Alias.matches(Opt);
82
83  // Check exact match.
84  if (getID() == Opt.getID())
85    return true;
86
87  const Option Group = getGroup();
88  if (Group.isValid())
89    return Group.matches(Opt);
90  return false;
91}
92
93Arg *Option::accept(const ArgList &Args,
94                    unsigned &Index,
95                    unsigned ArgSize) const {
96  const Option &UnaliasedOption = getUnaliasedOption();
97  StringRef Spelling;
98  // If the option was an alias, get the spelling from the unaliased one.
99  if (getID() == UnaliasedOption.getID()) {
100    Spelling = StringRef(Args.getArgString(Index), ArgSize);
101  } else {
102    Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
103                                  Twine(UnaliasedOption.getName()));
104  }
105
106  switch (getKind()) {
107  case FlagClass:
108    if (ArgSize != strlen(Args.getArgString(Index)))
109      return 0;
110
111    return new Arg(UnaliasedOption, Spelling, Index++);
112  case JoinedClass: {
113    const char *Value = Args.getArgString(Index) + ArgSize;
114    return new Arg(UnaliasedOption, Spelling, Index++, Value);
115  }
116  case CommaJoinedClass: {
117    // Always matches.
118    const char *Str = Args.getArgString(Index) + ArgSize;
119    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
120
121    // Parse out the comma separated values.
122    const char *Prev = Str;
123    for (;; ++Str) {
124      char c = *Str;
125
126      if (!c || c == ',') {
127        if (Prev != Str) {
128          char *Value = new char[Str - Prev + 1];
129          memcpy(Value, Prev, Str - Prev);
130          Value[Str - Prev] = '\0';
131          A->getValues().push_back(Value);
132        }
133
134        if (!c)
135          break;
136
137        Prev = Str + 1;
138      }
139    }
140    A->setOwnsValues(true);
141
142    return A;
143  }
144  case SeparateClass:
145    // Matches iff this is an exact match.
146    // FIXME: Avoid strlen.
147    if (ArgSize != strlen(Args.getArgString(Index)))
148      return 0;
149
150    Index += 2;
151    if (Index > Args.getNumInputArgStrings())
152      return 0;
153
154    return new Arg(UnaliasedOption, Spelling,
155                   Index - 2, Args.getArgString(Index - 1));
156  case MultiArgClass: {
157    // Matches iff this is an exact match.
158    // FIXME: Avoid strlen.
159    if (ArgSize != strlen(Args.getArgString(Index)))
160      return 0;
161
162    Index += 1 + getNumArgs();
163    if (Index > Args.getNumInputArgStrings())
164      return 0;
165
166    Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
167                      Args.getArgString(Index - getNumArgs()));
168    for (unsigned i = 1; i != getNumArgs(); ++i)
169      A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
170    return A;
171  }
172  case JoinedOrSeparateClass: {
173    // If this is not an exact match, it is a joined arg.
174    // FIXME: Avoid strlen.
175    if (ArgSize != strlen(Args.getArgString(Index))) {
176      const char *Value = Args.getArgString(Index) + ArgSize;
177      return new Arg(*this, Spelling, Index++, Value);
178    }
179
180    // Otherwise it must be separate.
181    Index += 2;
182    if (Index > Args.getNumInputArgStrings())
183      return 0;
184
185    return new Arg(UnaliasedOption, Spelling,
186                   Index - 2, Args.getArgString(Index - 1));
187  }
188  case JoinedAndSeparateClass:
189    // Always matches.
190    Index += 2;
191    if (Index > Args.getNumInputArgStrings())
192      return 0;
193
194    return new Arg(UnaliasedOption, Spelling, Index - 2,
195                   Args.getArgString(Index - 2) + ArgSize,
196                   Args.getArgString(Index - 1));
197  default:
198    llvm_unreachable("Invalid option kind!");
199  }
200}
201