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