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