1218893Sdim//===--- Option.cpp - Abstract Driver Options -----------------------------===//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed
10193326Sed#include "clang/Driver/Option.h"
11193326Sed#include "clang/Driver/Arg.h"
12193326Sed#include "clang/Driver/ArgList.h"
13249423Sdim#include "llvm/ADT/Twine.h"
14249423Sdim#include "llvm/Support/ErrorHandling.h"
15193326Sed#include "llvm/Support/raw_ostream.h"
16249423Sdim#include <algorithm>
17193326Sed#include <cassert>
18193326Sedusing namespace clang::driver;
19193326Sed
20243830SdimOption::Option(const OptTable::Info *info, const OptTable *owner)
21243830Sdim  : Info(info), Owner(owner) {
22193326Sed
23193326Sed  // Multi-level aliases are not supported, and alias options cannot
24193326Sed  // have groups. This just simplifies option tracking, it is not an
25193326Sed  // inherent limitation.
26243830Sdim  assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
27243830Sdim         !getGroup().isValid())) &&
28198092Srdivacky         "Multi-level aliases and aliases with groups are unsupported.");
29193326Sed}
30193326Sed
31193326SedOption::~Option() {
32193326Sed}
33193326Sed
34193326Sedvoid Option::dump() const {
35193326Sed  llvm::errs() << "<";
36243830Sdim  switch (getKind()) {
37193326Sed#define P(N) case N: llvm::errs() << #N; break
38193326Sed    P(GroupClass);
39193326Sed    P(InputClass);
40193326Sed    P(UnknownClass);
41193326Sed    P(FlagClass);
42193326Sed    P(JoinedClass);
43193326Sed    P(SeparateClass);
44193326Sed    P(CommaJoinedClass);
45193326Sed    P(MultiArgClass);
46193326Sed    P(JoinedOrSeparateClass);
47193326Sed    P(JoinedAndSeparateClass);
48193326Sed#undef P
49193326Sed  }
50193326Sed
51243830Sdim  llvm::errs() << " Prefixes:[";
52243830Sdim  for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
53243830Sdim    llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
54243830Sdim  }
55243830Sdim  llvm::errs() << ']';
56193326Sed
57243830Sdim  llvm::errs() << " Name:\"" << getName() << '"';
58243830Sdim
59243830Sdim  const Option Group = getGroup();
60243830Sdim  if (Group.isValid()) {
61193326Sed    llvm::errs() << " Group:";
62243830Sdim    Group.dump();
63193326Sed  }
64198092Srdivacky
65243830Sdim  const Option Alias = getAlias();
66243830Sdim  if (Alias.isValid()) {
67193326Sed    llvm::errs() << " Alias:";
68243830Sdim    Alias.dump();
69193326Sed  }
70198092Srdivacky
71243830Sdim  if (getKind() == MultiArgClass)
72243830Sdim    llvm::errs() << " NumArgs:" << getNumArgs();
73193326Sed
74193326Sed  llvm::errs() << ">\n";
75193326Sed}
76193326Sed
77199512Srdivackybool Option::matches(OptSpecifier Opt) const {
78199512Srdivacky  // Aliases are never considered in matching, look through them.
79243830Sdim  const Option Alias = getAlias();
80243830Sdim  if (Alias.isValid())
81243830Sdim    return Alias.matches(Opt);
82198092Srdivacky
83199512Srdivacky  // Check exact match.
84243830Sdim  if (getID() == Opt.getID())
85193326Sed    return true;
86198092Srdivacky
87243830Sdim  const Option Group = getGroup();
88243830Sdim  if (Group.isValid())
89243830Sdim    return Group.matches(Opt);
90193326Sed  return false;
91193326Sed}
92193326Sed
93243830SdimArg *Option::accept(const ArgList &Args,
94243830Sdim                    unsigned &Index,
95243830Sdim                    unsigned ArgSize) const {
96243830Sdim  const Option &UnaliasedOption = getUnaliasedOption();
97243830Sdim  StringRef Spelling;
98243830Sdim  // If the option was an alias, get the spelling from the unaliased one.
99243830Sdim  if (getID() == UnaliasedOption.getID()) {
100243830Sdim    Spelling = StringRef(Args.getArgString(Index), ArgSize);
101243830Sdim  } else {
102243830Sdim    Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
103243830Sdim                                  Twine(UnaliasedOption.getName()));
104243830Sdim  }
105193326Sed
106243830Sdim  switch (getKind()) {
107243830Sdim  case FlagClass:
108243830Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
109243830Sdim      return 0;
110193326Sed
111243830Sdim    return new Arg(UnaliasedOption, Spelling, Index++);
112243830Sdim  case JoinedClass: {
113243830Sdim    const char *Value = Args.getArgString(Index) + ArgSize;
114243830Sdim    return new Arg(UnaliasedOption, Spelling, Index++, Value);
115243830Sdim  }
116243830Sdim  case CommaJoinedClass: {
117243830Sdim    // Always matches.
118243830Sdim    const char *Str = Args.getArgString(Index) + ArgSize;
119243830Sdim    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
120193326Sed
121243830Sdim    // Parse out the comma separated values.
122243830Sdim    const char *Prev = Str;
123243830Sdim    for (;; ++Str) {
124243830Sdim      char c = *Str;
125193326Sed
126243830Sdim      if (!c || c == ',') {
127243830Sdim        if (Prev != Str) {
128243830Sdim          char *Value = new char[Str - Prev + 1];
129243830Sdim          memcpy(Value, Prev, Str - Prev);
130243830Sdim          Value[Str - Prev] = '\0';
131243830Sdim          A->getValues().push_back(Value);
132243830Sdim        }
133193326Sed
134243830Sdim        if (!c)
135243830Sdim          break;
136193326Sed
137243830Sdim        Prev = Str + 1;
138210299Sed      }
139243830Sdim    }
140243830Sdim    A->setOwnsValues(true);
141210299Sed
142243830Sdim    return A;
143210299Sed  }
144243830Sdim  case SeparateClass:
145243830Sdim    // Matches iff this is an exact match.
146243830Sdim    // FIXME: Avoid strlen.
147243830Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
148243830Sdim      return 0;
149210299Sed
150243830Sdim    Index += 2;
151243830Sdim    if (Index > Args.getNumInputArgStrings())
152243830Sdim      return 0;
153193326Sed
154243830Sdim    return new Arg(UnaliasedOption, Spelling,
155243830Sdim                   Index - 2, Args.getArgString(Index - 1));
156243830Sdim  case MultiArgClass: {
157243830Sdim    // Matches iff this is an exact match.
158243830Sdim    // FIXME: Avoid strlen.
159243830Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
160243830Sdim      return 0;
161193326Sed
162243830Sdim    Index += 1 + getNumArgs();
163243830Sdim    if (Index > Args.getNumInputArgStrings())
164243830Sdim      return 0;
165193326Sed
166243830Sdim    Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
167243830Sdim                      Args.getArgString(Index - getNumArgs()));
168243830Sdim    for (unsigned i = 1; i != getNumArgs(); ++i)
169243830Sdim      A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
170243830Sdim    return A;
171243830Sdim  }
172243830Sdim  case JoinedOrSeparateClass: {
173243830Sdim    // If this is not an exact match, it is a joined arg.
174243830Sdim    // FIXME: Avoid strlen.
175243830Sdim    if (ArgSize != strlen(Args.getArgString(Index))) {
176243830Sdim      const char *Value = Args.getArgString(Index) + ArgSize;
177243830Sdim      return new Arg(*this, Spelling, Index++, Value);
178243830Sdim    }
179193326Sed
180243830Sdim    // Otherwise it must be separate.
181243830Sdim    Index += 2;
182243830Sdim    if (Index > Args.getNumInputArgStrings())
183243830Sdim      return 0;
184193326Sed
185243830Sdim    return new Arg(UnaliasedOption, Spelling,
186243830Sdim                   Index - 2, Args.getArgString(Index - 1));
187243830Sdim  }
188243830Sdim  case JoinedAndSeparateClass:
189243830Sdim    // Always matches.
190243830Sdim    Index += 2;
191243830Sdim    if (Index > Args.getNumInputArgStrings())
192243830Sdim      return 0;
193193326Sed
194243830Sdim    return new Arg(UnaliasedOption, Spelling, Index - 2,
195243830Sdim                   Args.getArgString(Index - 2) + ArgSize,
196243830Sdim                   Args.getArgString(Index - 1));
197243830Sdim  default:
198243830Sdim    llvm_unreachable("Invalid option kind!");
199210299Sed  }
200193326Sed}
201