[PATCH] Option parsing: support case-insensitive option matching.

Rui Ueyama ruiu at google.com
Fri Aug 23 09:33:13 PDT 2013


  The previous patch was incomplete so I'm sending the complete one for
  completeness. Ignore this patch because I'm still addressing your comment.

Hi hans,

http://llvm-reviews.chandlerc.com/D1485

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D1485?vs=3693&id=3699#toc

Files:
  include/llvm/Option/OptParser.td
  include/llvm/Option/OptTable.h
  lib/Option/OptTable.cpp
  unittests/Option/OptionParsingTest.cpp
  unittests/Option/Opts.td
  utils/TableGen/OptParserEmitter.cpp

Index: include/llvm/Option/OptParser.td
===================================================================
--- include/llvm/Option/OptParser.td
+++ include/llvm/Option/OptParser.td
@@ -92,6 +92,7 @@
   OptionGroup Group = ?;
   Option Alias = ?;
   list<string> AliasArgs = [];
+  bit IgnoreCase = ?;
 }
 
 // Helpers for defining options.
@@ -122,6 +123,7 @@
 class Group<OptionGroup group> { OptionGroup Group = group; }
 class HelpText<string text> { string HelpText = text; }
 class MetaVarName<string name> { string MetaVarName = name; }
+class IgnoreCase<bit value> { bit IgnoreCase = value; }
 
 // Predefined options.
 
Index: include/llvm/Option/OptTable.h
===================================================================
--- include/llvm/Option/OptTable.h
+++ include/llvm/Option/OptTable.h
@@ -45,6 +45,7 @@
     unsigned short GroupID;
     unsigned short AliasID;
     const char *AliasArgs;
+    bool IgnoreCase;
   };
 
 private:
Index: lib/Option/OptTable.cpp
===================================================================
--- lib/Option/OptTable.cpp
+++ lib/Option/OptTable.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Option/Option.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Debug.h"
 #include <algorithm>
 #include <map>
 
@@ -170,12 +171,25 @@
   return true;
 }
 
+// Returns true if X starts with Y, ignoreing case.
+static bool startsWithIgnoreCase(StringRef X, StringRef Y) {
+  if (X.size() < Y.size())
+    return false;
+  return X.substr(0, Y.size()).equals_lower(Y);
+}
+
 /// \returns Matched size. 0 means no match.
 static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
   for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
     StringRef Prefix(*Pre);
-    if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
-      return Prefix.size() + StringRef(I->Name).size();
+    if (Str.startswith(Prefix)) {
+      StringRef Rest = Str.substr(Prefix.size());
+      bool Matched = I->IgnoreCase
+          ? startsWithIgnoreCase(Rest, I->Name)
+          : Rest.startswith(I->Name);
+      if (Matched)
+        return Prefix.size() + StringRef(I->Name).size();
+    }
   }
   return 0;
 }
Index: unittests/Option/OptionParsingTest.cpp
===================================================================
--- unittests/Option/OptionParsingTest.cpp
+++ unittests/Option/OptionParsingTest.cpp
@@ -17,10 +17,12 @@
 using namespace llvm;
 using namespace llvm::opt;
 
+#define SUPPORT_IGNORECASE  // FIXME: Remove when no longer necessary
+
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
-              HELPTEXT, METAVAR) OPT_##ID,
+               HELPTEXT, METAVAR, IGNORECASE) OPT_##ID,
 #include "Opts.inc"
   LastOption
 #undef OPTION
@@ -38,9 +40,9 @@
 
 static const OptTable::Info InfoTable[] = {
 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
-               HELPTEXT, METAVAR)   \
+               HELPTEXT, METAVAR, IGNORECASE)                           \
   { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
-    FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+    FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, IGNORECASE },
 #include "Opts.inc"
 #undef OPTION
 };
@@ -157,6 +159,15 @@
   EXPECT_EQ(AL->getAllArgValues(OPT_B)[1], "bar");
 }
 
+TEST(Option, IgnoreCase) {
+  TestOptTable T;
+  unsigned MAI, MAC;
+
+  const char *MyArgs[] = { "-K" };
+  OwningPtr<InputArgList> AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC));
+  EXPECT_TRUE(AL->hasArg(OPT_K));
+}
+
 TEST(Option, SlurpEmpty) {
   TestOptTable T;
   unsigned MAI, MAC;
Index: unittests/Option/Opts.td
===================================================================
--- unittests/Option/Opts.td
+++ unittests/Option/Opts.td
@@ -23,4 +23,6 @@
 def J : Flag<["-"], "J">, Alias<B>, AliasArgs<["foo"]>;
 def Joo : Flag<["-"], "Joo">, Alias<B>, AliasArgs<["bar"]>;
 
+def K : Flag<["-"], "k">, IgnoreCase<1>;
+
 def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>;
Index: utils/TableGen/OptParserEmitter.cpp
===================================================================
--- utils/TableGen/OptParserEmitter.cpp
+++ utils/TableGen/OptParserEmitter.cpp
@@ -152,11 +152,22 @@
   OS << "/////////\n";
   OS << "// Groups\n\n";
   OS << "#ifdef OPTION\n";
+
+  // FIXME: Remove when option parsing clients are updated.
+  OS << "#ifdef SUPPORT_IGNORECASE\n";
+  OS << "#define OPTIONX OPTION\n";
+  OS << "#else\n";
+  OS << "#define OPTIONX(prefix, name, id, kind, group, alias, aliasargs, "
+     << "flags, param, helptext, metavar, ignorecase) "
+     << "OPTION(prefix, name, id, kind, "
+     << "group, alias, aliasargs, flags, param, helptext, metavar)\n";
+  OS << "#endif\n";
+
   for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
     const Record &R = *Groups[i];
 
     // Start a single option entry.
-    OS << "OPTION(";
+    OS << "OPTIONX(";
 
     // The option prefix;
     OS << "0";
@@ -188,8 +199,8 @@
     } else
       OS << ", 0";
 
-    // The option meta-variable name (unused).
-    OS << ", 0)\n";
+    // The option meta-variable name and ignore-case bit (unused).
+    OS << ", 0, 0)\n";
   }
   OS << "\n";
 
@@ -199,7 +210,7 @@
     const Record &R = *Opts[i];
 
     // Start a single option entry.
-    OS << "OPTION(";
+    OS << "OPTIONX(";
 
     // The option prefix;
     std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
@@ -274,8 +285,15 @@
     else
       OS << "0";
 
+    // The ignore-base bit.
+    OS << ", ";
+    bool IgnoreCase = !isa<UnsetInit>(R.getValueInit("IgnoreCase")) &&
+        R.getValueAsBit("IgnoreCase");
+    OS << (IgnoreCase ? "1" : "0");
+
     OS << ")\n";
   }
+  OS << "#undef OPTIONX\n"; // FIXME: Remove when option clients are updated.
   OS << "#endif\n";
 }
 } // end namespace llvm
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1485.2.patch
Type: text/x-patch
Size: 5963 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130823/7937b669/attachment.bin>


More information about the llvm-commits mailing list