• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 using namespace llvm;
21 using namespace llvm::opt;
22 
Option(const OptTable::Info * info,const OptTable * owner)23 Option::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 
print(raw_ostream & O) const39 void 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 #undef P
55   }
56 
57   if (Info->Prefixes) {
58     O << " Prefixes:[";
59     for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) {
60       O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
61     }
62     O << ']';
63   }
64 
65   O << " Name:\"" << getName() << '"';
66 
67   const Option Group = getGroup();
68   if (Group.isValid()) {
69     O << " Group:";
70     Group.print(O);
71   }
72 
73   const Option Alias = getAlias();
74   if (Alias.isValid()) {
75     O << " Alias:";
76     Alias.print(O);
77   }
78 
79   if (getKind() == MultiArgClass)
80     O << " NumArgs:" << getNumArgs();
81 
82   O << ">\n";
83 }
84 
dump() const85 void Option::dump() const { print(dbgs()); }
86 
matches(OptSpecifier Opt) const87 bool 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 
accept(const ArgList & Args,unsigned & Index,unsigned ArgSize) const103 Arg *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 
132     if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
133       // A Flag alias for a Joined option must provide an argument.
134       A->getValues().push_back("");
135 
136     return A;
137   }
138   case JoinedClass: {
139     const char *Value = Args.getArgString(Index) + ArgSize;
140     return new Arg(UnaliasedOption, Spelling, Index++, Value);
141   }
142   case CommaJoinedClass: {
143     // Always matches.
144     const char *Str = Args.getArgString(Index) + ArgSize;
145     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
146 
147     // Parse out the comma separated values.
148     const char *Prev = Str;
149     for (;; ++Str) {
150       char c = *Str;
151 
152       if (!c || c == ',') {
153         if (Prev != Str) {
154           char *Value = new char[Str - Prev + 1];
155           memcpy(Value, Prev, Str - Prev);
156           Value[Str - Prev] = '\0';
157           A->getValues().push_back(Value);
158         }
159 
160         if (!c)
161           break;
162 
163         Prev = Str + 1;
164       }
165     }
166     A->setOwnsValues(true);
167 
168     return A;
169   }
170   case SeparateClass:
171     // Matches iff this is an exact match.
172     // FIXME: Avoid strlen.
173     if (ArgSize != strlen(Args.getArgString(Index)))
174       return nullptr;
175 
176     Index += 2;
177     if (Index > Args.getNumInputArgStrings() ||
178         Args.getArgString(Index - 1) == nullptr)
179       return nullptr;
180 
181     return new Arg(UnaliasedOption, Spelling,
182                    Index - 2, Args.getArgString(Index - 1));
183   case MultiArgClass: {
184     // Matches iff this is an exact match.
185     // FIXME: Avoid strlen.
186     if (ArgSize != strlen(Args.getArgString(Index)))
187       return nullptr;
188 
189     Index += 1 + getNumArgs();
190     if (Index > Args.getNumInputArgStrings())
191       return nullptr;
192 
193     Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
194                       Args.getArgString(Index - getNumArgs()));
195     for (unsigned i = 1; i != getNumArgs(); ++i)
196       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
197     return A;
198   }
199   case JoinedOrSeparateClass: {
200     // If this is not an exact match, it is a joined arg.
201     // FIXME: Avoid strlen.
202     if (ArgSize != strlen(Args.getArgString(Index))) {
203       const char *Value = Args.getArgString(Index) + ArgSize;
204       return new Arg(*this, Spelling, Index++, Value);
205     }
206 
207     // Otherwise it must be separate.
208     Index += 2;
209     if (Index > Args.getNumInputArgStrings() ||
210         Args.getArgString(Index - 1) == nullptr)
211       return nullptr;
212 
213     return new Arg(UnaliasedOption, Spelling,
214                    Index - 2, Args.getArgString(Index - 1));
215   }
216   case JoinedAndSeparateClass:
217     // Always matches.
218     Index += 2;
219     if (Index > Args.getNumInputArgStrings() ||
220         Args.getArgString(Index - 1) == nullptr)
221       return nullptr;
222 
223     return new Arg(UnaliasedOption, Spelling, Index - 2,
224                    Args.getArgString(Index - 2) + ArgSize,
225                    Args.getArgString(Index - 1));
226   case RemainingArgsClass: {
227     // Matches iff this is an exact match.
228     // FIXME: Avoid strlen.
229     if (ArgSize != strlen(Args.getArgString(Index)))
230       return nullptr;
231     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
232     while (Index < Args.getNumInputArgStrings() &&
233            Args.getArgString(Index) != nullptr)
234       A->getValues().push_back(Args.getArgString(Index++));
235     return A;
236   }
237   default:
238     llvm_unreachable("Invalid option kind!");
239   }
240 }
241