1249259Sdim//===--- Option.cpp - Abstract Driver Options -----------------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim
10249259Sdim#include "llvm/Option/Option.h"
11249259Sdim#include "llvm/ADT/Twine.h"
12249259Sdim#include "llvm/Option/Arg.h"
13249259Sdim#include "llvm/Option/ArgList.h"
14249259Sdim#include "llvm/Support/ErrorHandling.h"
15249259Sdim#include "llvm/Support/raw_ostream.h"
16249259Sdim#include <algorithm>
17249259Sdim#include <cassert>
18249259Sdim
19249259Sdimusing namespace llvm;
20249259Sdimusing namespace llvm::opt;
21249259Sdim
22249259SdimOption::Option(const OptTable::Info *info, const OptTable *owner)
23249259Sdim  : Info(info), Owner(owner) {
24249259Sdim
25249259Sdim  // Multi-level aliases are not supported, and alias options cannot
26249259Sdim  // have groups. This just simplifies option tracking, it is not an
27249259Sdim  // inherent limitation.
28249259Sdim  assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
29249259Sdim         !getGroup().isValid())) &&
30249259Sdim         "Multi-level aliases and aliases with groups are unsupported.");
31249259Sdim}
32249259Sdim
33249259SdimOption::~Option() {
34249259Sdim}
35249259Sdim
36249259Sdimvoid Option::dump() const {
37249259Sdim  llvm::errs() << "<";
38249259Sdim  switch (getKind()) {
39249259Sdim#define P(N) case N: llvm::errs() << #N; break
40249259Sdim    P(GroupClass);
41249259Sdim    P(InputClass);
42249259Sdim    P(UnknownClass);
43249259Sdim    P(FlagClass);
44249259Sdim    P(JoinedClass);
45249259Sdim    P(SeparateClass);
46249259Sdim    P(CommaJoinedClass);
47249259Sdim    P(MultiArgClass);
48249259Sdim    P(JoinedOrSeparateClass);
49249259Sdim    P(JoinedAndSeparateClass);
50249259Sdim#undef P
51249259Sdim  }
52249259Sdim
53249259Sdim  llvm::errs() << " Prefixes:[";
54249259Sdim  for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
55249259Sdim    llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
56249259Sdim  }
57249259Sdim  llvm::errs() << ']';
58249259Sdim
59249259Sdim  llvm::errs() << " Name:\"" << getName() << '"';
60249259Sdim
61249259Sdim  const Option Group = getGroup();
62249259Sdim  if (Group.isValid()) {
63249259Sdim    llvm::errs() << " Group:";
64249259Sdim    Group.dump();
65249259Sdim  }
66249259Sdim
67249259Sdim  const Option Alias = getAlias();
68249259Sdim  if (Alias.isValid()) {
69249259Sdim    llvm::errs() << " Alias:";
70249259Sdim    Alias.dump();
71249259Sdim  }
72249259Sdim
73249259Sdim  if (getKind() == MultiArgClass)
74249259Sdim    llvm::errs() << " NumArgs:" << getNumArgs();
75249259Sdim
76249259Sdim  llvm::errs() << ">\n";
77249259Sdim}
78249259Sdim
79249259Sdimbool Option::matches(OptSpecifier Opt) const {
80249259Sdim  // Aliases are never considered in matching, look through them.
81249259Sdim  const Option Alias = getAlias();
82249259Sdim  if (Alias.isValid())
83249259Sdim    return Alias.matches(Opt);
84249259Sdim
85249259Sdim  // Check exact match.
86249259Sdim  if (getID() == Opt.getID())
87249259Sdim    return true;
88249259Sdim
89249259Sdim  const Option Group = getGroup();
90249259Sdim  if (Group.isValid())
91249259Sdim    return Group.matches(Opt);
92249259Sdim  return false;
93249259Sdim}
94249259Sdim
95249259SdimArg *Option::accept(const ArgList &Args,
96249259Sdim                    unsigned &Index,
97249259Sdim                    unsigned ArgSize) const {
98249259Sdim  const Option &UnaliasedOption = getUnaliasedOption();
99249259Sdim  StringRef Spelling;
100249259Sdim  // If the option was an alias, get the spelling from the unaliased one.
101249259Sdim  if (getID() == UnaliasedOption.getID()) {
102249259Sdim    Spelling = StringRef(Args.getArgString(Index), ArgSize);
103249259Sdim  } else {
104249259Sdim    Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
105249259Sdim                                  Twine(UnaliasedOption.getName()));
106249259Sdim  }
107249259Sdim
108249259Sdim  switch (getKind()) {
109249259Sdim  case FlagClass:
110249259Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
111249259Sdim      return 0;
112249259Sdim
113249259Sdim    return new Arg(UnaliasedOption, Spelling, Index++);
114249259Sdim  case JoinedClass: {
115249259Sdim    const char *Value = Args.getArgString(Index) + ArgSize;
116249259Sdim    return new Arg(UnaliasedOption, Spelling, Index++, Value);
117249259Sdim  }
118249259Sdim  case CommaJoinedClass: {
119249259Sdim    // Always matches.
120249259Sdim    const char *Str = Args.getArgString(Index) + ArgSize;
121249259Sdim    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
122249259Sdim
123249259Sdim    // Parse out the comma separated values.
124249259Sdim    const char *Prev = Str;
125249259Sdim    for (;; ++Str) {
126249259Sdim      char c = *Str;
127249259Sdim
128249259Sdim      if (!c || c == ',') {
129249259Sdim        if (Prev != Str) {
130249259Sdim          char *Value = new char[Str - Prev + 1];
131249259Sdim          memcpy(Value, Prev, Str - Prev);
132249259Sdim          Value[Str - Prev] = '\0';
133249259Sdim          A->getValues().push_back(Value);
134249259Sdim        }
135249259Sdim
136249259Sdim        if (!c)
137249259Sdim          break;
138249259Sdim
139249259Sdim        Prev = Str + 1;
140249259Sdim      }
141249259Sdim    }
142249259Sdim    A->setOwnsValues(true);
143249259Sdim
144249259Sdim    return A;
145249259Sdim  }
146249259Sdim  case SeparateClass:
147249259Sdim    // Matches iff this is an exact match.
148249259Sdim    // FIXME: Avoid strlen.
149249259Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
150249259Sdim      return 0;
151249259Sdim
152249259Sdim    Index += 2;
153249259Sdim    if (Index > Args.getNumInputArgStrings())
154249259Sdim      return 0;
155249259Sdim
156249259Sdim    return new Arg(UnaliasedOption, Spelling,
157249259Sdim                   Index - 2, Args.getArgString(Index - 1));
158249259Sdim  case MultiArgClass: {
159249259Sdim    // Matches iff this is an exact match.
160249259Sdim    // FIXME: Avoid strlen.
161249259Sdim    if (ArgSize != strlen(Args.getArgString(Index)))
162249259Sdim      return 0;
163249259Sdim
164249259Sdim    Index += 1 + getNumArgs();
165249259Sdim    if (Index > Args.getNumInputArgStrings())
166249259Sdim      return 0;
167249259Sdim
168249259Sdim    Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
169249259Sdim                      Args.getArgString(Index - getNumArgs()));
170249259Sdim    for (unsigned i = 1; i != getNumArgs(); ++i)
171249259Sdim      A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
172249259Sdim    return A;
173249259Sdim  }
174249259Sdim  case JoinedOrSeparateClass: {
175249259Sdim    // If this is not an exact match, it is a joined arg.
176249259Sdim    // FIXME: Avoid strlen.
177249259Sdim    if (ArgSize != strlen(Args.getArgString(Index))) {
178249259Sdim      const char *Value = Args.getArgString(Index) + ArgSize;
179249259Sdim      return new Arg(*this, Spelling, Index++, Value);
180249259Sdim    }
181249259Sdim
182249259Sdim    // Otherwise it must be separate.
183249259Sdim    Index += 2;
184249259Sdim    if (Index > Args.getNumInputArgStrings())
185249259Sdim      return 0;
186249259Sdim
187249259Sdim    return new Arg(UnaliasedOption, Spelling,
188249259Sdim                   Index - 2, Args.getArgString(Index - 1));
189249259Sdim  }
190249259Sdim  case JoinedAndSeparateClass:
191249259Sdim    // Always matches.
192249259Sdim    Index += 2;
193249259Sdim    if (Index > Args.getNumInputArgStrings())
194249259Sdim      return 0;
195249259Sdim
196249259Sdim    return new Arg(UnaliasedOption, Spelling, Index - 2,
197249259Sdim                   Args.getArgString(Index - 2) + ArgSize,
198249259Sdim                   Args.getArgString(Index - 1));
199249259Sdim  default:
200249259Sdim    llvm_unreachable("Invalid option kind!");
201249259Sdim  }
202249259Sdim}
203