124d58133SDimitry 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
1024d58133SDimitry Andric #include "llvm/ADT/StringRef.h"
11139f7f9bSDimitry Andric #include "llvm/ADT/Twine.h"
12*4ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
13139f7f9bSDimitry Andric #include "llvm/Option/Arg.h"
14139f7f9bSDimitry Andric #include "llvm/Option/ArgList.h"
1524d58133SDimitry Andric #include "llvm/Option/Option.h"
1624d58133SDimitry Andric #include "llvm/Option/OptTable.h"
1724d58133SDimitry Andric #include "llvm/Support/Compiler.h"
187d523365SDimitry Andric #include "llvm/Support/Debug.h"
19139f7f9bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
20139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h"
21139f7f9bSDimitry Andric #include <cassert>
2224d58133SDimitry Andric #include <cstring>
23139f7f9bSDimitry Andric
24139f7f9bSDimitry Andric using namespace llvm;
25139f7f9bSDimitry Andric using namespace llvm::opt;
26139f7f9bSDimitry Andric
Option(const OptTable::Info * info,const OptTable * owner)27139f7f9bSDimitry Andric Option::Option(const OptTable::Info *info, const OptTable *owner)
28139f7f9bSDimitry Andric : Info(info), Owner(owner) {
29f785676fSDimitry Andric // Multi-level aliases are not supported. This just simplifies option
30f785676fSDimitry Andric // tracking, it is not an inherent limitation.
31f785676fSDimitry Andric assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
32f785676fSDimitry Andric "Multi-level aliases are not supported.");
33f785676fSDimitry Andric
34f785676fSDimitry Andric if (Info && getAliasArgs()) {
35f785676fSDimitry Andric assert(getAlias().isValid() && "Only alias options can have alias args.");
36f785676fSDimitry Andric assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");
37f785676fSDimitry Andric assert(getAlias().getKind() != FlagClass &&
38f785676fSDimitry Andric "Cannot provide alias args to a flag option.");
39f785676fSDimitry Andric }
40139f7f9bSDimitry Andric }
41139f7f9bSDimitry Andric
print(raw_ostream & O) const427d523365SDimitry Andric void Option::print(raw_ostream &O) const {
437d523365SDimitry Andric O << "<";
44139f7f9bSDimitry Andric switch (getKind()) {
457d523365SDimitry Andric #define P(N) case N: O << #N; break
46139f7f9bSDimitry Andric P(GroupClass);
47139f7f9bSDimitry Andric P(InputClass);
48139f7f9bSDimitry Andric P(UnknownClass);
49139f7f9bSDimitry Andric P(FlagClass);
50139f7f9bSDimitry Andric P(JoinedClass);
51edd7eaddSDimitry Andric P(ValuesClass);
52139f7f9bSDimitry Andric P(SeparateClass);
53139f7f9bSDimitry Andric P(CommaJoinedClass);
54139f7f9bSDimitry Andric P(MultiArgClass);
55139f7f9bSDimitry Andric P(JoinedOrSeparateClass);
56139f7f9bSDimitry Andric P(JoinedAndSeparateClass);
57f785676fSDimitry Andric P(RemainingArgsClass);
583ca95b02SDimitry Andric P(RemainingArgsJoinedClass);
59139f7f9bSDimitry Andric #undef P
60139f7f9bSDimitry Andric }
61139f7f9bSDimitry Andric
62f785676fSDimitry Andric if (Info->Prefixes) {
637d523365SDimitry Andric O << " Prefixes:[";
6491bc56edSDimitry Andric for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) {
657d523365SDimitry Andric O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
66139f7f9bSDimitry Andric }
677d523365SDimitry Andric O << ']';
68f785676fSDimitry Andric }
69139f7f9bSDimitry Andric
707d523365SDimitry Andric O << " Name:\"" << getName() << '"';
71139f7f9bSDimitry Andric
72139f7f9bSDimitry Andric const Option Group = getGroup();
73139f7f9bSDimitry Andric if (Group.isValid()) {
747d523365SDimitry Andric O << " Group:";
757d523365SDimitry Andric Group.print(O);
76139f7f9bSDimitry Andric }
77139f7f9bSDimitry Andric
78139f7f9bSDimitry Andric const Option Alias = getAlias();
79139f7f9bSDimitry Andric if (Alias.isValid()) {
807d523365SDimitry Andric O << " Alias:";
817d523365SDimitry Andric Alias.print(O);
82139f7f9bSDimitry Andric }
83139f7f9bSDimitry Andric
84139f7f9bSDimitry Andric if (getKind() == MultiArgClass)
857d523365SDimitry Andric O << " NumArgs:" << getNumArgs();
86139f7f9bSDimitry Andric
877d523365SDimitry Andric O << ">\n";
88139f7f9bSDimitry Andric }
89139f7f9bSDimitry Andric
907a7e6055SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const913ca95b02SDimitry Andric LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); }
927a7e6055SDimitry Andric #endif
937d523365SDimitry Andric
matches(OptSpecifier Opt) const94139f7f9bSDimitry Andric bool Option::matches(OptSpecifier Opt) const {
95139f7f9bSDimitry Andric // Aliases are never considered in matching, look through them.
96139f7f9bSDimitry Andric const Option Alias = getAlias();
97139f7f9bSDimitry Andric if (Alias.isValid())
98139f7f9bSDimitry Andric return Alias.matches(Opt);
99139f7f9bSDimitry Andric
100139f7f9bSDimitry Andric // Check exact match.
101139f7f9bSDimitry Andric if (getID() == Opt.getID())
102139f7f9bSDimitry Andric return true;
103139f7f9bSDimitry Andric
104139f7f9bSDimitry Andric const Option Group = getGroup();
105139f7f9bSDimitry Andric if (Group.isValid())
106139f7f9bSDimitry Andric return Group.matches(Opt);
107139f7f9bSDimitry Andric return false;
108139f7f9bSDimitry Andric }
109139f7f9bSDimitry Andric
accept(const ArgList & Args,unsigned & Index,unsigned ArgSize) const110139f7f9bSDimitry Andric Arg *Option::accept(const ArgList &Args,
111139f7f9bSDimitry Andric unsigned &Index,
112139f7f9bSDimitry Andric unsigned ArgSize) const {
113139f7f9bSDimitry Andric const Option &UnaliasedOption = getUnaliasedOption();
114139f7f9bSDimitry Andric StringRef Spelling;
115139f7f9bSDimitry Andric // If the option was an alias, get the spelling from the unaliased one.
116139f7f9bSDimitry Andric if (getID() == UnaliasedOption.getID()) {
117139f7f9bSDimitry Andric Spelling = StringRef(Args.getArgString(Index), ArgSize);
118139f7f9bSDimitry Andric } else {
119139f7f9bSDimitry Andric Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
120139f7f9bSDimitry Andric Twine(UnaliasedOption.getName()));
121139f7f9bSDimitry Andric }
122139f7f9bSDimitry Andric
123139f7f9bSDimitry Andric switch (getKind()) {
124f785676fSDimitry Andric case FlagClass: {
125139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index)))
12691bc56edSDimitry Andric return nullptr;
127139f7f9bSDimitry Andric
128f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
129f785676fSDimitry Andric if (getAliasArgs()) {
130f785676fSDimitry Andric const char *Val = getAliasArgs();
131f785676fSDimitry Andric while (*Val != '\0') {
132f785676fSDimitry Andric A->getValues().push_back(Val);
133f785676fSDimitry Andric
134f785676fSDimitry Andric // Move past the '\0' to the next argument.
135f785676fSDimitry Andric Val += strlen(Val) + 1;
136f785676fSDimitry Andric }
137f785676fSDimitry Andric }
138ff0cc061SDimitry Andric
139ff0cc061SDimitry Andric if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
140ff0cc061SDimitry Andric // A Flag alias for a Joined option must provide an argument.
141ff0cc061SDimitry Andric A->getValues().push_back("");
142ff0cc061SDimitry Andric
143f785676fSDimitry Andric return A;
144f785676fSDimitry Andric }
145139f7f9bSDimitry Andric case JoinedClass: {
146139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize;
147139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index++, Value);
148139f7f9bSDimitry Andric }
149139f7f9bSDimitry Andric case CommaJoinedClass: {
150139f7f9bSDimitry Andric // Always matches.
151139f7f9bSDimitry Andric const char *Str = Args.getArgString(Index) + ArgSize;
152139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
153139f7f9bSDimitry Andric
154139f7f9bSDimitry Andric // Parse out the comma separated values.
155139f7f9bSDimitry Andric const char *Prev = Str;
156139f7f9bSDimitry Andric for (;; ++Str) {
157139f7f9bSDimitry Andric char c = *Str;
158139f7f9bSDimitry Andric
159139f7f9bSDimitry Andric if (!c || c == ',') {
160139f7f9bSDimitry Andric if (Prev != Str) {
161139f7f9bSDimitry Andric char *Value = new char[Str - Prev + 1];
162139f7f9bSDimitry Andric memcpy(Value, Prev, Str - Prev);
163139f7f9bSDimitry Andric Value[Str - Prev] = '\0';
164139f7f9bSDimitry Andric A->getValues().push_back(Value);
165139f7f9bSDimitry Andric }
166139f7f9bSDimitry Andric
167139f7f9bSDimitry Andric if (!c)
168139f7f9bSDimitry Andric break;
169139f7f9bSDimitry Andric
170139f7f9bSDimitry Andric Prev = Str + 1;
171139f7f9bSDimitry Andric }
172139f7f9bSDimitry Andric }
173139f7f9bSDimitry Andric A->setOwnsValues(true);
174139f7f9bSDimitry Andric
175139f7f9bSDimitry Andric return A;
176139f7f9bSDimitry Andric }
177139f7f9bSDimitry Andric case SeparateClass:
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 += 2;
18439d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() ||
18539d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr)
18691bc56edSDimitry Andric return nullptr;
187139f7f9bSDimitry Andric
188139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling,
189139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1));
190139f7f9bSDimitry Andric case MultiArgClass: {
191139f7f9bSDimitry Andric // Matches iff this is an exact match.
192139f7f9bSDimitry Andric // FIXME: Avoid strlen.
193139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index)))
19491bc56edSDimitry Andric return nullptr;
195139f7f9bSDimitry Andric
196139f7f9bSDimitry Andric Index += 1 + getNumArgs();
197139f7f9bSDimitry Andric if (Index > Args.getNumInputArgStrings())
19891bc56edSDimitry Andric return nullptr;
199139f7f9bSDimitry Andric
200139f7f9bSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
201139f7f9bSDimitry Andric Args.getArgString(Index - getNumArgs()));
202139f7f9bSDimitry Andric for (unsigned i = 1; i != getNumArgs(); ++i)
203139f7f9bSDimitry Andric A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
204139f7f9bSDimitry Andric return A;
205139f7f9bSDimitry Andric }
206139f7f9bSDimitry Andric case JoinedOrSeparateClass: {
207139f7f9bSDimitry Andric // If this is not an exact match, it is a joined arg.
208139f7f9bSDimitry Andric // FIXME: Avoid strlen.
209139f7f9bSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) {
210139f7f9bSDimitry Andric const char *Value = Args.getArgString(Index) + ArgSize;
211139f7f9bSDimitry Andric return new Arg(*this, Spelling, Index++, Value);
212139f7f9bSDimitry Andric }
213139f7f9bSDimitry Andric
214139f7f9bSDimitry Andric // Otherwise it must be separate.
215139f7f9bSDimitry Andric Index += 2;
21639d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() ||
21739d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr)
21891bc56edSDimitry Andric return nullptr;
219139f7f9bSDimitry Andric
220139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling,
221139f7f9bSDimitry Andric Index - 2, Args.getArgString(Index - 1));
222139f7f9bSDimitry Andric }
223139f7f9bSDimitry Andric case JoinedAndSeparateClass:
224139f7f9bSDimitry Andric // Always matches.
225139f7f9bSDimitry Andric Index += 2;
22639d628a0SDimitry Andric if (Index > Args.getNumInputArgStrings() ||
22739d628a0SDimitry Andric Args.getArgString(Index - 1) == nullptr)
22891bc56edSDimitry Andric return nullptr;
229139f7f9bSDimitry Andric
230139f7f9bSDimitry Andric return new Arg(UnaliasedOption, Spelling, Index - 2,
231139f7f9bSDimitry Andric Args.getArgString(Index - 2) + ArgSize,
232139f7f9bSDimitry Andric Args.getArgString(Index - 1));
233f785676fSDimitry Andric case RemainingArgsClass: {
234f785676fSDimitry Andric // Matches iff this is an exact match.
235f785676fSDimitry Andric // FIXME: Avoid strlen.
236f785676fSDimitry Andric if (ArgSize != strlen(Args.getArgString(Index)))
23791bc56edSDimitry Andric return nullptr;
238f785676fSDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
23939d628a0SDimitry Andric while (Index < Args.getNumInputArgStrings() &&
24039d628a0SDimitry Andric Args.getArgString(Index) != nullptr)
241f785676fSDimitry Andric A->getValues().push_back(Args.getArgString(Index++));
242f785676fSDimitry Andric return A;
243f785676fSDimitry Andric }
2443ca95b02SDimitry Andric case RemainingArgsJoinedClass: {
2453ca95b02SDimitry Andric Arg *A = new Arg(UnaliasedOption, Spelling, Index);
2463ca95b02SDimitry Andric if (ArgSize != strlen(Args.getArgString(Index))) {
2473ca95b02SDimitry Andric // An inexact match means there is a joined arg.
2483ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index) + ArgSize);
2493ca95b02SDimitry Andric }
2503ca95b02SDimitry Andric Index++;
2513ca95b02SDimitry Andric while (Index < Args.getNumInputArgStrings() &&
2523ca95b02SDimitry Andric Args.getArgString(Index) != nullptr)
2533ca95b02SDimitry Andric A->getValues().push_back(Args.getArgString(Index++));
2543ca95b02SDimitry Andric return A;
2553ca95b02SDimitry Andric }
2563ca95b02SDimitry Andric
257139f7f9bSDimitry Andric default:
258139f7f9bSDimitry Andric llvm_unreachable("Invalid option kind!");
259139f7f9bSDimitry Andric }
260139f7f9bSDimitry Andric }
261