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