1139f7f9bSDimitry Andric //===--- Option.cpp - Abstract Driver Options -----------------------------===//
2139f7f9bSDimitry Andric //
3139f7f9bSDimitry Andric //                     The LLVM Compiler Infrastructure
4139f7f9bSDimitry Andric //
5139f7f9bSDimitry Andric // This file is distributed under the University of Illinois Open Source
6139f7f9bSDimitry Andric // License. See LICENSE.TXT for details.
7139f7f9bSDimitry Andric //
8139f7f9bSDimitry Andric //===----------------------------------------------------------------------===//
9139f7f9bSDimitry Andric 
10139f7f9bSDimitry Andric #include "llvm/Option/Option.h"
11139f7f9bSDimitry Andric #include "llvm/ADT/Twine.h"
12139f7f9bSDimitry Andric #include "llvm/Option/Arg.h"
13139f7f9bSDimitry Andric #include "llvm/Option/ArgList.h"
14139f7f9bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
15139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h"
16139f7f9bSDimitry Andric #include <algorithm>
17139f7f9bSDimitry Andric #include <cassert>
18139f7f9bSDimitry Andric 
19139f7f9bSDimitry Andric using namespace llvm;
20139f7f9bSDimitry Andric using namespace llvm::opt;
21139f7f9bSDimitry Andric 
22139f7f9bSDimitry Andric Option::Option(const OptTable::Info *info, const OptTable *owner)
23139f7f9bSDimitry Andric   : Info(info), Owner(owner) {
24139f7f9bSDimitry Andric 
25f785676fSDimitry Andric   // Multi-level aliases are not supported. This just simplifies option
26f785676fSDimitry Andric   // tracking, it is not an inherent limitation.
27f785676fSDimitry Andric   assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
28f785676fSDimitry Andric          "Multi-level aliases are not supported.");
29f785676fSDimitry Andric 
30f785676fSDimitry Andric   if (Info && getAliasArgs()) {
31f785676fSDimitry Andric     assert(getAlias().isValid() && "Only alias options can have alias args.");
32f785676fSDimitry Andric     assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");
33f785676fSDimitry Andric     assert(getAlias().getKind() != FlagClass &&
34f785676fSDimitry Andric            "Cannot provide alias args to a flag option.");
35f785676fSDimitry Andric   }
36139f7f9bSDimitry Andric }
37139f7f9bSDimitry Andric 
38139f7f9bSDimitry Andric Option::~Option() {
39139f7f9bSDimitry Andric }
40139f7f9bSDimitry Andric 
41139f7f9bSDimitry Andric void Option::dump() const {
42139f7f9bSDimitry Andric   llvm::errs() << "<";
43139f7f9bSDimitry Andric   switch (getKind()) {
44139f7f9bSDimitry Andric #define P(N) case N: llvm::errs() << #N; break
45139f7f9bSDimitry Andric     P(GroupClass);
46139f7f9bSDimitry Andric     P(InputClass);
47139f7f9bSDimitry Andric     P(UnknownClass);
48139f7f9bSDimitry Andric     P(FlagClass);
49139f7f9bSDimitry Andric     P(JoinedClass);
50139f7f9bSDimitry Andric     P(SeparateClass);
51139f7f9bSDimitry Andric     P(CommaJoinedClass);
52139f7f9bSDimitry Andric     P(MultiArgClass);
53139f7f9bSDimitry Andric     P(JoinedOrSeparateClass);
54139f7f9bSDimitry Andric     P(JoinedAndSeparateClass);
55f785676fSDimitry Andric     P(RemainingArgsClass);
56139f7f9bSDimitry Andric #undef P
57139f7f9bSDimitry Andric   }
58139f7f9bSDimitry Andric 
59f785676fSDimitry Andric   if (Info->Prefixes) {
60139f7f9bSDimitry Andric     llvm::errs() << " Prefixes:[";
6191bc56edSDimitry Andric     for (const char * const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) {
6291bc56edSDimitry Andric       llvm::errs() << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
63139f7f9bSDimitry Andric     }
64139f7f9bSDimitry Andric     llvm::errs() << ']';
65f785676fSDimitry Andric   }
66139f7f9bSDimitry Andric 
67139f7f9bSDimitry Andric   llvm::errs() << " Name:\"" << getName() << '"';
68139f7f9bSDimitry Andric 
69139f7f9bSDimitry Andric   const Option Group = getGroup();
70139f7f9bSDimitry Andric   if (Group.isValid()) {
71139f7f9bSDimitry Andric     llvm::errs() << " Group:";
72139f7f9bSDimitry Andric     Group.dump();
73139f7f9bSDimitry Andric   }
74139f7f9bSDimitry Andric 
75139f7f9bSDimitry Andric   const Option Alias = getAlias();
76139f7f9bSDimitry Andric   if (Alias.isValid()) {
77139f7f9bSDimitry Andric     llvm::errs() << " Alias:";
78139f7f9bSDimitry Andric     Alias.dump();
79139f7f9bSDimitry Andric   }
80139f7f9bSDimitry Andric 
81139f7f9bSDimitry Andric   if (getKind() == MultiArgClass)
82139f7f9bSDimitry Andric     llvm::errs() << " NumArgs:" << getNumArgs();
83139f7f9bSDimitry Andric 
84139f7f9bSDimitry Andric   llvm::errs() << ">\n";
85139f7f9bSDimitry Andric }
86139f7f9bSDimitry Andric 
87139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const {
88139f7f9bSDimitry Andric   // Aliases are never considered in matching, look through them.
89139f7f9bSDimitry Andric   const Option Alias = getAlias();
90139f7f9bSDimitry Andric   if (Alias.isValid())
91139f7f9bSDimitry Andric     return Alias.matches(Opt);
92139f7f9bSDimitry Andric 
93139f7f9bSDimitry Andric   // Check exact match.
94139f7f9bSDimitry Andric   if (getID() == Opt.getID())
95139f7f9bSDimitry Andric     return true;
96139f7f9bSDimitry Andric 
97139f7f9bSDimitry Andric   const Option Group = getGroup();
98139f7f9bSDimitry Andric   if (Group.isValid())
99139f7f9bSDimitry Andric     return Group.matches(Opt);
100139f7f9bSDimitry Andric   return false;
101139f7f9bSDimitry Andric }
102139f7f9bSDimitry Andric 
103139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args,
104139f7f9bSDimitry Andric                     unsigned &Index,
105139f7f9bSDimitry Andric                     unsigned ArgSize) const {
106139f7f9bSDimitry Andric   const Option &UnaliasedOption = getUnaliasedOption();
107139f7f9bSDimitry Andric   StringRef Spelling;
108139f7f9bSDimitry Andric   // If the option was an alias, get the spelling from the unaliased one.
109139f7f9bSDimitry Andric   if (getID() == UnaliasedOption.getID()) {
110139f7f9bSDimitry Andric     Spelling = StringRef(Args.getArgString(Index), ArgSize);
111139f7f9bSDimitry Andric   } else {
112139f7f9bSDimitry Andric     Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
113139f7f9bSDimitry Andric                                   Twine(UnaliasedOption.getName()));
114139f7f9bSDimitry Andric   }
115139f7f9bSDimitry Andric 
116139f7f9bSDimitry Andric   switch (getKind()) {
117f785676fSDimitry Andric   case FlagClass: {
118139f7f9bSDimitry Andric     if (ArgSize != strlen(Args.getArgString(Index)))
11991bc56edSDimitry Andric       return nullptr;
120139f7f9bSDimitry Andric 
121f785676fSDimitry Andric     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
122f785676fSDimitry Andric     if (getAliasArgs()) {
123f785676fSDimitry Andric       const char *Val = getAliasArgs();
124f785676fSDimitry Andric       while (*Val != '\0') {
125f785676fSDimitry Andric         A->getValues().push_back(Val);
126f785676fSDimitry Andric 
127f785676fSDimitry Andric         // Move past the '\0' to the next argument.
128f785676fSDimitry Andric         Val += strlen(Val) + 1;
129f785676fSDimitry Andric       }
130f785676fSDimitry Andric     }
131f785676fSDimitry Andric     return A;
132f785676fSDimitry Andric   }
133139f7f9bSDimitry Andric   case JoinedClass: {
134139f7f9bSDimitry Andric     const char *Value = Args.getArgString(Index) + ArgSize;
135139f7f9bSDimitry Andric     return new Arg(UnaliasedOption, Spelling, Index++, Value);
136139f7f9bSDimitry Andric   }
137139f7f9bSDimitry Andric   case CommaJoinedClass: {
138139f7f9bSDimitry Andric     // Always matches.
139139f7f9bSDimitry Andric     const char *Str = Args.getArgString(Index) + ArgSize;
140139f7f9bSDimitry Andric     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
141139f7f9bSDimitry Andric 
142139f7f9bSDimitry Andric     // Parse out the comma separated values.
143139f7f9bSDimitry Andric     const char *Prev = Str;
144139f7f9bSDimitry Andric     for (;; ++Str) {
145139f7f9bSDimitry Andric       char c = *Str;
146139f7f9bSDimitry Andric 
147139f7f9bSDimitry Andric       if (!c || c == ',') {
148139f7f9bSDimitry Andric         if (Prev != Str) {
149139f7f9bSDimitry Andric           char *Value = new char[Str - Prev + 1];
150139f7f9bSDimitry Andric           memcpy(Value, Prev, Str - Prev);
151139f7f9bSDimitry Andric           Value[Str - Prev] = '\0';
152139f7f9bSDimitry Andric           A->getValues().push_back(Value);
153139f7f9bSDimitry Andric         }
154139f7f9bSDimitry Andric 
155139f7f9bSDimitry Andric         if (!c)
156139f7f9bSDimitry Andric           break;
157139f7f9bSDimitry Andric 
158139f7f9bSDimitry Andric         Prev = Str + 1;
159139f7f9bSDimitry Andric       }
160139f7f9bSDimitry Andric     }
161139f7f9bSDimitry Andric     A->setOwnsValues(true);
162139f7f9bSDimitry Andric 
163139f7f9bSDimitry Andric     return A;
164139f7f9bSDimitry Andric   }
165139f7f9bSDimitry Andric   case SeparateClass:
166139f7f9bSDimitry Andric     // Matches iff this is an exact match.
167139f7f9bSDimitry Andric     // FIXME: Avoid strlen.
168139f7f9bSDimitry Andric     if (ArgSize != strlen(Args.getArgString(Index)))
16991bc56edSDimitry Andric       return nullptr;
170139f7f9bSDimitry Andric 
171139f7f9bSDimitry Andric     Index += 2;
172139f7f9bSDimitry Andric     if (Index > Args.getNumInputArgStrings())
17391bc56edSDimitry Andric       return nullptr;
174139f7f9bSDimitry Andric 
175139f7f9bSDimitry Andric     return new Arg(UnaliasedOption, Spelling,
176139f7f9bSDimitry Andric                    Index - 2, Args.getArgString(Index - 1));
177139f7f9bSDimitry Andric   case MultiArgClass: {
178139f7f9bSDimitry Andric     // Matches iff this is an exact match.
179139f7f9bSDimitry Andric     // FIXME: Avoid strlen.
180139f7f9bSDimitry Andric     if (ArgSize != strlen(Args.getArgString(Index)))
18191bc56edSDimitry Andric       return nullptr;
182139f7f9bSDimitry Andric 
183139f7f9bSDimitry Andric     Index += 1 + getNumArgs();
184139f7f9bSDimitry Andric     if (Index > Args.getNumInputArgStrings())
18591bc56edSDimitry Andric       return nullptr;
186139f7f9bSDimitry Andric 
187139f7f9bSDimitry Andric     Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
188139f7f9bSDimitry Andric                       Args.getArgString(Index - getNumArgs()));
189139f7f9bSDimitry Andric     for (unsigned i = 1; i != getNumArgs(); ++i)
190139f7f9bSDimitry Andric       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
191139f7f9bSDimitry Andric     return A;
192139f7f9bSDimitry Andric   }
193139f7f9bSDimitry Andric   case JoinedOrSeparateClass: {
194139f7f9bSDimitry Andric     // If this is not an exact match, it is a joined arg.
195139f7f9bSDimitry Andric     // FIXME: Avoid strlen.
196139f7f9bSDimitry Andric     if (ArgSize != strlen(Args.getArgString(Index))) {
197139f7f9bSDimitry Andric       const char *Value = Args.getArgString(Index) + ArgSize;
198139f7f9bSDimitry Andric       return new Arg(*this, Spelling, Index++, Value);
199139f7f9bSDimitry Andric     }
200139f7f9bSDimitry Andric 
201139f7f9bSDimitry Andric     // Otherwise it must be separate.
202139f7f9bSDimitry Andric     Index += 2;
203139f7f9bSDimitry Andric     if (Index > Args.getNumInputArgStrings())
20491bc56edSDimitry Andric       return nullptr;
205139f7f9bSDimitry Andric 
206139f7f9bSDimitry Andric     return new Arg(UnaliasedOption, Spelling,
207139f7f9bSDimitry Andric                    Index - 2, Args.getArgString(Index - 1));
208139f7f9bSDimitry Andric   }
209139f7f9bSDimitry Andric   case JoinedAndSeparateClass:
210139f7f9bSDimitry Andric     // Always matches.
211139f7f9bSDimitry Andric     Index += 2;
212139f7f9bSDimitry Andric     if (Index > Args.getNumInputArgStrings())
21391bc56edSDimitry Andric       return nullptr;
214139f7f9bSDimitry Andric 
215139f7f9bSDimitry Andric     return new Arg(UnaliasedOption, Spelling, Index - 2,
216139f7f9bSDimitry Andric                    Args.getArgString(Index - 2) + ArgSize,
217139f7f9bSDimitry Andric                    Args.getArgString(Index - 1));
218f785676fSDimitry Andric   case RemainingArgsClass: {
219f785676fSDimitry Andric     // Matches iff this is an exact match.
220f785676fSDimitry Andric     // FIXME: Avoid strlen.
221f785676fSDimitry Andric     if (ArgSize != strlen(Args.getArgString(Index)))
22291bc56edSDimitry Andric       return nullptr;
223f785676fSDimitry Andric     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
224f785676fSDimitry Andric     while (Index < Args.getNumInputArgStrings())
225f785676fSDimitry Andric       A->getValues().push_back(Args.getArgString(Index++));
226f785676fSDimitry Andric     return A;
227f785676fSDimitry Andric   }
228139f7f9bSDimitry Andric   default:
229139f7f9bSDimitry Andric     llvm_unreachable("Invalid option kind!");
230139f7f9bSDimitry Andric   }
231139f7f9bSDimitry Andric }
232