llvm.org GIT mirror llvm / 055f4e9
Option parsing: support case-insensitive option matching. Link.exe's command line options are case-insensitive. This patch adds a new attribute to OptTable to let the option parser to compare options, ignoring case. Command lines are generally case-insensitive on Windows. CL.exe is an exception. So this new attribute should be useful for other commands running on Windows. Differential Revision: http://llvm-reviews.chandlerc.com/D1485 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189416 91177308-0d34-0410-b5e6-96231b3b80d8 Rui Ueyama 5 years ago
4 changed file(s) with 90 addition(s) and 56 deletion(s). Raw diff Collapse all Expand all
5050 /// \brief The static option information table.
5151 const Info *OptionInfos;
5252 unsigned NumOptionInfos;
53 bool IgnoreCase;
5354
5455 unsigned TheInputOptionID;
5556 unsigned TheUnknownOptionID;
7172 }
7273
7374 protected:
74 OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos);
75 OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos,
76 bool _IgnoreCase = false);
7577 public:
7678 ~OptTable();
7779
1818 using namespace llvm;
1919 using namespace llvm::opt;
2020
21 // Ordering on Info. The ordering is *almost* lexicographic, with two
22 // exceptions. First, '\0' comes at the end of the alphabet instead of
23 // the beginning (thus options precede any other options which prefix
24 // them). Second, for options with the same name, the less permissive
25 // version should come first; a Flag option should precede a Joined
26 // option, for example.
27
28 static int StrCmpOptionName(const char *A, const char *B) {
29 char a = *A, b = *B;
30 while (a == b) {
31 if (a == '\0')
32 return 0;
33
34 a = *++A;
35 b = *++B;
36 }
37
38 if (a == '\0') // A is a prefix of B.
39 return 1;
40 if (b == '\0') // B is a prefix of A.
41 return -1;
42
43 // Otherwise lexicographic.
44 return (a < b) ? -1 : 1;
45 }
46
4721 namespace llvm {
4822 namespace opt {
23
24 // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
25 // with an exceptions. '\0' comes at the end of the alphabet instead of the
26 // beginning (thus options precede any other options which prefix them).
27 static int StrCmpOptionNameIgnoreCase(const char *A, const char *B) {
28 size_t I = strlen(A);
29 size_t J = strlen(B);
30 // If A and B are the same length, compare them ignoring case.
31 if (I == J)
32 return strcasecmp(A, B);
33 // A is shorter than B. In this case A is less than B only when it's
34 // lexicographically less than B. strncasecmp() == 0 means A is a prefix of B,
35 // which in turn means A should appear *after* B.
36 if (I < J)
37 return strncasecmp(A, B, I) < 0 ? -1 : 1;
38 // Otherwise, vice versa.
39 return strncasecmp(A, B, J) <= 0 ? -1 : 1;
40 }
41
42 static int StrCmpOptionName(const char *A, const char *B) {
43 if (int N = StrCmpOptionNameIgnoreCase(A, B))
44 return N;
45 return strcmp(A, B);
46 }
4947
5048 static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
5149 if (&A == &B)
5250 return false;
5351
5452 if (int N = StrCmpOptionName(A.Name, B.Name))
55 return N == -1;
53 return N < 0;
5654
5755 for (const char * const *APre = A.Prefixes,
5856 * const *BPre = B.Prefixes;
5957 *APre != 0 && *BPre != 0; ++APre, ++BPre) {
6058 if (int N = StrCmpOptionName(*APre, *BPre))
61 return N == -1;
59 return N < 0;
6260 }
6361
6462 // Names are the same, check that classes are in order; exactly one
7068
7169 // Support lower_bound between info and an option name.
7270 static inline bool operator<(const OptTable::Info &I, const char *Name) {
73 return StrCmpOptionName(I.Name, Name) == -1;
71 return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0;
7472 }
7573 static inline bool operator<(const char *Name, const OptTable::Info &I) {
76 return StrCmpOptionName(Name, I.Name) == -1;
74 return StrCmpOptionNameIgnoreCase(Name, I.Name) < 0;
7775 }
7876 }
7977 }
8078
8179 OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
8280
83 OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
81 OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos,
82 bool _IgnoreCase)
8483 : OptionInfos(_OptionInfos),
8584 NumOptionInfos(_NumOptionInfos),
85 IgnoreCase(_IgnoreCase),
8686 TheInputOptionID(0),
8787 TheUnknownOptionID(0),
8888 FirstSearchableIndex(0)
169169 return true;
170170 }
171171
172 // Returns true if X starts with Y, ignoring case.
173 static bool startsWithIgnoreCase(StringRef X, StringRef Y) {
174 if (X.size() < Y.size())
175 return false;
176 return X.substr(0, Y.size()).equals_lower(Y);
177 }
178
172179 /// \returns Matched size. 0 means no match.
173 static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
180 static unsigned matchOption(const OptTable::Info *I, StringRef Str,
181 bool IgnoreCase) {
174182 for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
175183 StringRef Prefix(*Pre);
176 if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
177 return Prefix.size() + StringRef(I->Name).size();
184 if (Str.startswith(Prefix)) {
185 StringRef Rest = Str.substr(Prefix.size());
186 bool Matched = IgnoreCase
187 ? startsWithIgnoreCase(Rest, I->Name)
188 : Rest.startswith(I->Name);
189 if (Matched)
190 return Prefix.size() + StringRef(I->Name).size();
191 }
178192 }
179193 return 0;
180194 }
209223 unsigned ArgSize = 0;
210224 // Scan for first option which is a proper prefix.
211225 for (; Start != End; ++Start)
212 if ((ArgSize = matchOption(Start, Str)))
226 if ((ArgSize = matchOption(Start, Str, IgnoreCase)))
213227 break;
214228 if (Start == End)
215229 break;
1919 enum ID {
2020 OPT_INVALID = 0, // This is not an option ID.
2121 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
22 HELPTEXT, METAVAR) OPT_##ID,
22 HELPTEXT, METAVAR) OPT_##ID,
2323 #include "Opts.inc"
2424 LastOption
2525 #undef OPTION
4747 namespace {
4848 class TestOptTable : public OptTable {
4949 public:
50 TestOptTable()
51 : OptTable(InfoTable, array_lengthof(InfoTable)) {}
50 TestOptTable(bool IgnoreCase = false)
51 : OptTable(InfoTable, array_lengthof(InfoTable), IgnoreCase) {}
5252 };
5353 }
5454
156156 EXPECT_EQ(AL->getAllArgValues(OPT_B)[1], "bar");
157157 }
158158
159 TEST(Option, IgnoreCase) {
160 TestOptTable T(true);
161 unsigned MAI, MAC;
162
163 const char *MyArgs[] = { "-a", "-joo" };
164 OwningPtr AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC));
165 EXPECT_TRUE(AL->hasArg(OPT_A));
166 EXPECT_TRUE(AL->hasArg(OPT_B));
167 }
168
169 TEST(Option, DoNotIgnoreCase) {
170 TestOptTable T;
171 unsigned MAI, MAC;
172
173 const char *MyArgs[] = { "-a", "-joo" };
174 OwningPtr AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC));
175 EXPECT_FALSE(AL->hasArg(OPT_A));
176 EXPECT_FALSE(AL->hasArg(OPT_B));
177 }
178
159179 TEST(Option, SlurpEmpty) {
160180 TestOptTable T;
161181 unsigned MAI, MAC;
1212 #include "llvm/ADT/Twine.h"
1313 #include "llvm/TableGen/Record.h"
1414 #include "llvm/TableGen/TableGenBackend.h"
15 #include
1516 #include
17 #include
1618
1719 using namespace llvm;
1820
21 // Ordering on Info. The logic should match with the consumer-side function in
22 // llvm/Option/OptTable.h.
1923 static int StrCmpOptionName(const char *A, const char *B) {
20 char a = *A, b = *B;
21 while (a == b) {
22 if (a == '\0')
23 return 0;
24
25 a = *++A;
26 b = *++B;
27 }
28
29 if (a == '\0') // A is a prefix of B.
30 return 1;
31 if (b == '\0') // B is a prefix of A.
32 return -1;
33
34 // Otherwise lexicographic.
35 return (a < b) ? -1 : 1;
24 size_t I = strlen(A);
25 size_t J = strlen(B);
26 if (I == J) {
27 if (int N = strcasecmp(A, B))
28 return N;
29 return strcmp(A, B);
30 }
31 if (I < J)
32 return strncasecmp(A, B, I) < 0 ? -1 : 1;
33 return strncasecmp(A, B, J) <= 0 ? -1 : 1;
3634 }
3735
3836 static int CompareOptionRecords(const void *Av, const void *Bv) {
4947 if (!ASent)
5048 if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
5149 B->getValueAsString("Name").c_str()))
52 return Cmp;
50 return Cmp;
5351
5452 if (!ASent) {
5553 std::vector APrefixes = A->getValueAsListOfStrings("Prefixes");