xref: /llvm-project/llvm/lib/Option/Option.cpp (revision 8c209aa8779de57771b64896f805e14cc0016dcd)
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 
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 
39 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     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 
86 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
87 LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); }
88 #endif
89 
90 bool Option::matches(OptSpecifier Opt) const {
91   // Aliases are never considered in matching, look through them.
92   const Option Alias = getAlias();
93   if (Alias.isValid())
94     return Alias.matches(Opt);
95 
96   // Check exact match.
97   if (getID() == Opt.getID())
98     return true;
99 
100   const Option Group = getGroup();
101   if (Group.isValid())
102     return Group.matches(Opt);
103   return false;
104 }
105 
106 Arg *Option::accept(const ArgList &Args,
107                     unsigned &Index,
108                     unsigned ArgSize) const {
109   const Option &UnaliasedOption = getUnaliasedOption();
110   StringRef Spelling;
111   // If the option was an alias, get the spelling from the unaliased one.
112   if (getID() == UnaliasedOption.getID()) {
113     Spelling = StringRef(Args.getArgString(Index), ArgSize);
114   } else {
115     Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
116                                   Twine(UnaliasedOption.getName()));
117   }
118 
119   switch (getKind()) {
120   case FlagClass: {
121     if (ArgSize != strlen(Args.getArgString(Index)))
122       return nullptr;
123 
124     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
125     if (getAliasArgs()) {
126       const char *Val = getAliasArgs();
127       while (*Val != '\0') {
128         A->getValues().push_back(Val);
129 
130         // Move past the '\0' to the next argument.
131         Val += strlen(Val) + 1;
132       }
133     }
134 
135     if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
136       // A Flag alias for a Joined option must provide an argument.
137       A->getValues().push_back("");
138 
139     return A;
140   }
141   case JoinedClass: {
142     const char *Value = Args.getArgString(Index) + ArgSize;
143     return new Arg(UnaliasedOption, Spelling, Index++, Value);
144   }
145   case CommaJoinedClass: {
146     // Always matches.
147     const char *Str = Args.getArgString(Index) + ArgSize;
148     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
149 
150     // Parse out the comma separated values.
151     const char *Prev = Str;
152     for (;; ++Str) {
153       char c = *Str;
154 
155       if (!c || c == ',') {
156         if (Prev != Str) {
157           char *Value = new char[Str - Prev + 1];
158           memcpy(Value, Prev, Str - Prev);
159           Value[Str - Prev] = '\0';
160           A->getValues().push_back(Value);
161         }
162 
163         if (!c)
164           break;
165 
166         Prev = Str + 1;
167       }
168     }
169     A->setOwnsValues(true);
170 
171     return A;
172   }
173   case SeparateClass:
174     // Matches iff this is an exact match.
175     // FIXME: Avoid strlen.
176     if (ArgSize != strlen(Args.getArgString(Index)))
177       return nullptr;
178 
179     Index += 2;
180     if (Index > Args.getNumInputArgStrings() ||
181         Args.getArgString(Index - 1) == nullptr)
182       return nullptr;
183 
184     return new Arg(UnaliasedOption, Spelling,
185                    Index - 2, Args.getArgString(Index - 1));
186   case MultiArgClass: {
187     // Matches iff this is an exact match.
188     // FIXME: Avoid strlen.
189     if (ArgSize != strlen(Args.getArgString(Index)))
190       return nullptr;
191 
192     Index += 1 + getNumArgs();
193     if (Index > Args.getNumInputArgStrings())
194       return nullptr;
195 
196     Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
197                       Args.getArgString(Index - getNumArgs()));
198     for (unsigned i = 1; i != getNumArgs(); ++i)
199       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
200     return A;
201   }
202   case JoinedOrSeparateClass: {
203     // If this is not an exact match, it is a joined arg.
204     // FIXME: Avoid strlen.
205     if (ArgSize != strlen(Args.getArgString(Index))) {
206       const char *Value = Args.getArgString(Index) + ArgSize;
207       return new Arg(*this, Spelling, Index++, Value);
208     }
209 
210     // Otherwise it must be separate.
211     Index += 2;
212     if (Index > Args.getNumInputArgStrings() ||
213         Args.getArgString(Index - 1) == nullptr)
214       return nullptr;
215 
216     return new Arg(UnaliasedOption, Spelling,
217                    Index - 2, Args.getArgString(Index - 1));
218   }
219   case JoinedAndSeparateClass:
220     // Always matches.
221     Index += 2;
222     if (Index > Args.getNumInputArgStrings() ||
223         Args.getArgString(Index - 1) == nullptr)
224       return nullptr;
225 
226     return new Arg(UnaliasedOption, Spelling, Index - 2,
227                    Args.getArgString(Index - 2) + ArgSize,
228                    Args.getArgString(Index - 1));
229   case RemainingArgsClass: {
230     // Matches iff this is an exact match.
231     // FIXME: Avoid strlen.
232     if (ArgSize != strlen(Args.getArgString(Index)))
233       return nullptr;
234     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
235     while (Index < Args.getNumInputArgStrings() &&
236            Args.getArgString(Index) != nullptr)
237       A->getValues().push_back(Args.getArgString(Index++));
238     return A;
239   }
240   case RemainingArgsJoinedClass: {
241     Arg *A = new Arg(UnaliasedOption, Spelling, Index);
242     if (ArgSize != strlen(Args.getArgString(Index))) {
243       // An inexact match means there is a joined arg.
244       A->getValues().push_back(Args.getArgString(Index) + ArgSize);
245     }
246     Index++;
247     while (Index < Args.getNumInputArgStrings() &&
248            Args.getArgString(Index) != nullptr)
249       A->getValues().push_back(Args.getArgString(Index++));
250     return A;
251   }
252 
253   default:
254     llvm_unreachable("Invalid option kind!");
255   }
256 }
257