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