* Implement support for folding multiple single letter arguments together like
authorChris Lattner <sabre@nondot.org>
Mon, 26 Nov 2001 18:58:34 +0000 (18:58 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 26 Nov 2001 18:58:34 +0000 (18:58 +0000)
  with ls: ls -la  === ls -l -a
* Implement support for trimming arguments that start with a single letter
  argument so that -lfoo is recognized as -l foo for the linker

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1378 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Support/CommandLine.cpp
support/lib/Support/CommandLine.cpp

index 84dd26dff92005387f830b73482cedc48989d8d1..bc337ee8b5c0ae7acf3342e4a4ed74d9a14b4be8 100644 (file)
@@ -18,7 +18,7 @@
 using namespace cl;
 
 // Return the global command line option vector.  Making it a function scoped
 using namespace cl;
 
 // Return the global command line option vector.  Making it a function scoped
-// static ensures that it will be initialized before its first use correctly.
+// static ensures that it will be initialized correctly before its first use.
 //
 static map<string, Option*> &getOpts() {
   static map<string,Option*> CommandLineOptions;
 //
 static map<string, Option*> &getOpts() {
   static map<string,Option*> CommandLineOptions;
@@ -30,7 +30,8 @@ static void AddArgument(const string &ArgName, Option *Opt) {
     cerr << "CommandLine Error: Argument '" << ArgName
         << "' specified more than once!\n";
   } else {
     cerr << "CommandLine Error: Argument '" << ArgName
         << "' specified more than once!\n";
   } else {
-    getOpts()[ArgName] = Opt;  // Add argument to the argument map!
+    // Add argument to the argument map!
+    getOpts().insert(make_pair(ArgName, Opt));
   }
 }
 
   }
 }
 
@@ -65,9 +66,29 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName,
   return Handler->addOccurance(ArgName, Value);
 }
 
   return Handler->addOccurance(ArgName, Value);
 }
 
+// ValueGroupedArgs - Return true if the specified string is valid as a group
+// of single letter arguments stuck together like the 'ls -la' case.
+//
+static inline bool ValidGroupedArgs(string Args) {
+  for (unsigned i = 0; i < Args.size(); ++i) {
+    map<string, Option*>::iterator I = getOpts().find(string(1, Args[i]));
+    if (I == getOpts().end()) return false;   // Make sure option exists
+
+    // Grouped arguments have no value specified, make sure that if this option
+    // exists that it can accept no argument.
+    //
+    switch (I->second->getValueExpectedFlag()) {
+    case ValueDisallowed:
+    case ValueOptional: break;
+    default: return false;
+    }
+  }
+
+  return true;
+}
 
 void cl::ParseCommandLineOptions(int &argc, char **argv,
 
 void cl::ParseCommandLineOptions(int &argc, char **argv,
-                                const char *Overview = 0) {
+                                const char *Overview = 0, int Flags = 0) {
   ProgramName = argv[0];  // Save this away safe and snug
   ProgramOverview = Overview;
   bool ErrorParsing = false;
   ProgramName = argv[0];  // Save this away safe and snug
   ProgramOverview = Overview;
   bool ErrorParsing = false;
@@ -86,18 +107,55 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
       while (*ArgName == '-') ++ArgName;  // Eat leading dashes
 
       const char *ArgNameEnd = ArgName;
       while (*ArgName == '-') ++ArgName;  // Eat leading dashes
 
       const char *ArgNameEnd = ArgName;
-      while (*ArgNameEnd && *ArgNameEnd != '=' &&
-             *ArgNameEnd != '/') ++ArgNameEnd; // Scan till end
-      // TODO: Remove '/' case.  Implement single letter args properly!
+      while (*ArgNameEnd && *ArgNameEnd != '=')
+       ++ArgNameEnd; // Scan till end of argument name...
 
       Value = ArgNameEnd;
       if (*Value)           // If we have an equals sign...
        ++Value;            // Advance to value...
 
       if (*ArgName != 0) {
 
       Value = ArgNameEnd;
       if (*Value)           // If we have an equals sign...
        ++Value;            // Advance to value...
 
       if (*ArgName != 0) {
+       string RealName(ArgName, ArgNameEnd);
        // Extract arg name part
        // Extract arg name part
-        map<string, Option*>::iterator I = 
-          getOpts().find(string(ArgName, ArgNameEnd));
+        map<string, Option*>::iterator I = getOpts().find(RealName);
+
+       if (I == getOpts().end() && !*Value && RealName.size() > 1) {
+         // If grouping of single letter arguments is enabled, see if this is a
+         // legal grouping...
+         //
+         if (!(Flags & DisableSingleLetterArgGrouping) &&
+             ValidGroupedArgs(RealName)) {
+
+           for (unsigned i = 0; i < RealName.size(); ++i) {
+             char ArgName[2] = { 0, 0 }; int Dummy;
+             ArgName[0] = RealName[i];
+             I = getOpts().find(ArgName);
+             assert(I != getOpts().end() && "ValidGroupedArgs failed!");
+
+             // Because ValueRequired is an invalid flag for grouped arguments,
+             // we don't need to pass argc/argv in...
+             //
+             ErrorParsing |= ProvideOption(I->second, ArgName, "",
+                                           0, 0, Dummy);
+           }
+           continue;
+         } else if (Flags & EnableSingleLetterArgValue) {
+           // Check to see if the first letter is a single letter argument that
+           // have a value that is equal to the rest of the string.  If this
+           // is the case, recognize it now.  (Example:  -lfoo for a linker)
+           //
+           I = getOpts().find(string(1, RealName[0]));
+           if (I != getOpts().end()) {
+             // If we are successful, fall through to later processing, by
+             // setting up the argument name flags and value fields.
+             //
+             ArgNameEnd = ArgName+1;
+             Value = ArgNameEnd;
+           }
+         }
+       }
+
+
         Handler = I != getOpts().end() ? I->second : 0;
       }
     }
         Handler = I != getOpts().end() ? I->second : 0;
       }
     }
index 84dd26dff92005387f830b73482cedc48989d8d1..bc337ee8b5c0ae7acf3342e4a4ed74d9a14b4be8 100644 (file)
@@ -18,7 +18,7 @@
 using namespace cl;
 
 // Return the global command line option vector.  Making it a function scoped
 using namespace cl;
 
 // Return the global command line option vector.  Making it a function scoped
-// static ensures that it will be initialized before its first use correctly.
+// static ensures that it will be initialized correctly before its first use.
 //
 static map<string, Option*> &getOpts() {
   static map<string,Option*> CommandLineOptions;
 //
 static map<string, Option*> &getOpts() {
   static map<string,Option*> CommandLineOptions;
@@ -30,7 +30,8 @@ static void AddArgument(const string &ArgName, Option *Opt) {
     cerr << "CommandLine Error: Argument '" << ArgName
         << "' specified more than once!\n";
   } else {
     cerr << "CommandLine Error: Argument '" << ArgName
         << "' specified more than once!\n";
   } else {
-    getOpts()[ArgName] = Opt;  // Add argument to the argument map!
+    // Add argument to the argument map!
+    getOpts().insert(make_pair(ArgName, Opt));
   }
 }
 
   }
 }
 
@@ -65,9 +66,29 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName,
   return Handler->addOccurance(ArgName, Value);
 }
 
   return Handler->addOccurance(ArgName, Value);
 }
 
+// ValueGroupedArgs - Return true if the specified string is valid as a group
+// of single letter arguments stuck together like the 'ls -la' case.
+//
+static inline bool ValidGroupedArgs(string Args) {
+  for (unsigned i = 0; i < Args.size(); ++i) {
+    map<string, Option*>::iterator I = getOpts().find(string(1, Args[i]));
+    if (I == getOpts().end()) return false;   // Make sure option exists
+
+    // Grouped arguments have no value specified, make sure that if this option
+    // exists that it can accept no argument.
+    //
+    switch (I->second->getValueExpectedFlag()) {
+    case ValueDisallowed:
+    case ValueOptional: break;
+    default: return false;
+    }
+  }
+
+  return true;
+}
 
 void cl::ParseCommandLineOptions(int &argc, char **argv,
 
 void cl::ParseCommandLineOptions(int &argc, char **argv,
-                                const char *Overview = 0) {
+                                const char *Overview = 0, int Flags = 0) {
   ProgramName = argv[0];  // Save this away safe and snug
   ProgramOverview = Overview;
   bool ErrorParsing = false;
   ProgramName = argv[0];  // Save this away safe and snug
   ProgramOverview = Overview;
   bool ErrorParsing = false;
@@ -86,18 +107,55 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
       while (*ArgName == '-') ++ArgName;  // Eat leading dashes
 
       const char *ArgNameEnd = ArgName;
       while (*ArgName == '-') ++ArgName;  // Eat leading dashes
 
       const char *ArgNameEnd = ArgName;
-      while (*ArgNameEnd && *ArgNameEnd != '=' &&
-             *ArgNameEnd != '/') ++ArgNameEnd; // Scan till end
-      // TODO: Remove '/' case.  Implement single letter args properly!
+      while (*ArgNameEnd && *ArgNameEnd != '=')
+       ++ArgNameEnd; // Scan till end of argument name...
 
       Value = ArgNameEnd;
       if (*Value)           // If we have an equals sign...
        ++Value;            // Advance to value...
 
       if (*ArgName != 0) {
 
       Value = ArgNameEnd;
       if (*Value)           // If we have an equals sign...
        ++Value;            // Advance to value...
 
       if (*ArgName != 0) {
+       string RealName(ArgName, ArgNameEnd);
        // Extract arg name part
        // Extract arg name part
-        map<string, Option*>::iterator I = 
-          getOpts().find(string(ArgName, ArgNameEnd));
+        map<string, Option*>::iterator I = getOpts().find(RealName);
+
+       if (I == getOpts().end() && !*Value && RealName.size() > 1) {
+         // If grouping of single letter arguments is enabled, see if this is a
+         // legal grouping...
+         //
+         if (!(Flags & DisableSingleLetterArgGrouping) &&
+             ValidGroupedArgs(RealName)) {
+
+           for (unsigned i = 0; i < RealName.size(); ++i) {
+             char ArgName[2] = { 0, 0 }; int Dummy;
+             ArgName[0] = RealName[i];
+             I = getOpts().find(ArgName);
+             assert(I != getOpts().end() && "ValidGroupedArgs failed!");
+
+             // Because ValueRequired is an invalid flag for grouped arguments,
+             // we don't need to pass argc/argv in...
+             //
+             ErrorParsing |= ProvideOption(I->second, ArgName, "",
+                                           0, 0, Dummy);
+           }
+           continue;
+         } else if (Flags & EnableSingleLetterArgValue) {
+           // Check to see if the first letter is a single letter argument that
+           // have a value that is equal to the rest of the string.  If this
+           // is the case, recognize it now.  (Example:  -lfoo for a linker)
+           //
+           I = getOpts().find(string(1, RealName[0]));
+           if (I != getOpts().end()) {
+             // If we are successful, fall through to later processing, by
+             // setting up the argument name flags and value fields.
+             //
+             ArgNameEnd = ArgName+1;
+             Value = ArgNameEnd;
+           }
+         }
+       }
+
+
         Handler = I != getOpts().end() ? I->second : 0;
       }
     }
         Handler = I != getOpts().end() ? I->second : 0;
       }
     }