Allow any cl::opt to use the method getPosition() to retrieve the option's
absolute position on the command line. Similarly allow any cl::list to
use the method getPosition(n) to retrieve the absolute position of the nth
option in the list. This provides support for two things: (a) options like
-l that are actually positional and their order of occurrence matters when
they are intermixed with positional arguments like "a.o"; and (b) options
like -x LANG which affect only the positional arguments that come after
the option. In both cases, knowing the absolute position of a given option
helps.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15725 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/Support/CommandLine.h b/include/Support/CommandLine.h
index 7455f62..053b823 100644
--- a/include/Support/CommandLine.h
+++ b/include/Support/CommandLine.h
@@ -51,7 +51,7 @@
 // Flags permitted to be passed to command line arguments
 //
 
-enum NumOccurrences {           // Flags for the number of occurrences allowed
+enum NumOccurrences {          // Flags for the number of occurrences allowed
   Optional        = 0x01,      // Zero or One occurrence
   ZeroOrMore      = 0x02,      // Zero or more occurrences allowed
   Required        = 0x03,      // One occurrence required
@@ -103,13 +103,13 @@
   Positional       = 0x080,     // Is a positional argument, no '-' required
   Prefix           = 0x100,     // Can this option directly prefix its value?
   Grouping         = 0x180,     // Can this option group with other options?
-  FormattingMask   = 0x180,
+  FormattingMask   = 0x180,     // Union of the above flags.
 };
 
-enum MiscFlags {                // Miscellaneous flags to adjust argument
-  CommaSeparated     = 0x200,   // Should this cl::list split between commas?
-  PositionalEatsArgs = 0x400,   // Should this positional cl::list eat -args?
-  MiscMask           = 0x600,
+enum MiscFlags {               // Miscellaneous flags to adjust argument
+  CommaSeparated     = 0x200,  // Should this cl::list split between commas?
+  PositionalEatsArgs = 0x400,  // Should this positional cl::list eat -args?
+  MiscMask           = 0x600,  // Union of the above flags.
 };
 
 
@@ -126,7 +126,8 @@
   // an argument.  Should return true if there was an error processing the
   // argument and the program should exit.
   //
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) = 0;
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) = 0;
 
   virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { 
     return Optional;
@@ -141,8 +142,9 @@
     return NormalFormatting;
   }
 
-  int NumOccurrences;    // The number of times specified
+  int NumOccurrences;   // The number of times specified
   int Flags;            // Flags for the argument
+  unsigned Position;    // Position of last occurrence of the option
 public:
   const char *ArgStr;   // The argument string itself (ex: "help", "o")
   const char *HelpStr;  // The descriptive text message for --help
@@ -171,6 +173,7 @@
   inline unsigned getMiscFlags() const {
     return Flags & MiscMask;
   }
+  inline unsigned getPosition() const { return Position; }
 
   // hasArgStr - Return true if the argstr != ""
   bool hasArgStr() const { return ArgStr[0] != 0; }
@@ -198,8 +201,9 @@
   void setHiddenFlag(enum OptionHidden Val) { setFlag(Val, HiddenMask); }
   void setFormattingFlag(enum FormattingFlags V) { setFlag(V, FormattingMask); }
   void setMiscFlag(enum MiscFlags M) { setFlag(M, M); }
+  void setPosition(unsigned pos) { Position = pos; }
 protected:
-  Option() : NumOccurrences(0), Flags(0),
+  Option() : NumOccurrences(0), Flags(0), Position(0),
              ArgStr(""), HelpStr(""), ValueStr("") {}
 
 public:
@@ -219,7 +223,8 @@
 
   // addOccurrence - Wrapper around handleOccurrence that enforces Flags
   //
-  bool addOccurrence(const char *ArgName, const std::string &Value);
+  bool addOccurrence(unsigned pos, const char *ArgName, 
+                     const std::string &Value);
 
   // Prints option name followed by message.  Always returns true.
   bool error(std::string Message, const char *ArgName = 0);
@@ -250,7 +255,6 @@
   void apply(Option &O) const { O.setValueStr(Desc); }
 };
 
-
 // init - Specify a default (initial) value for the command line argument, if
 // the default constructor for the argument type does not give you what you
 // want.  This is only valid on "opt" arguments, not on "list" arguments.
@@ -438,7 +442,7 @@
   }
 
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
+  bool parse(Option &O, const char *ArgName, const std::string &Arg, 
              DataType &V) {
     std::string ArgVal;
     if (hasArgStr)
@@ -492,7 +496,6 @@
   //
   void printOptionInfo(const Option &O, unsigned GlobalWidth) const;
 
-
   // getValueName - Overload in subclass to provide a better default value.
   virtual const char *getValueName() const { return "value"; }
 };
@@ -545,8 +548,7 @@
 struct parser<unsigned> : public basic_parser<unsigned> {
   
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
-             unsigned &Val);
+  bool parse(Option &O, const char *AN, const std::string &Arg, unsigned &Val);
 
   // getValueName - Overload in subclass to provide a better default value.
   virtual const char *getValueName() const { return "uint"; }
@@ -585,7 +587,7 @@
 template<>
 struct parser<std::string> : public basic_parser<std::string> {
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
+  bool parse(Option &O, const char *AN, const std::string &Arg, 
              std::string &Value) {
     Value = Arg;
     return false;
@@ -595,8 +597,6 @@
   virtual const char *getValueName() const { return "string"; }
 };
 
-
-
 //===----------------------------------------------------------------------===//
 // applicator class - This class is used because we must use partial
 // specialization to handle literal string arguments specially (const char* does
@@ -728,11 +728,13 @@
                                is_class<DataType>::value> {
   ParserClass Parser;
 
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
     typename ParserClass::parser_data_type Val;
     if (Parser.parse(*this, ArgName, Arg, Val))
       return true;                            // Parse error!
     setValue(Val);
+    setPosition(pos);
     return false;
   }
 
@@ -875,6 +877,7 @@
 template <class DataType, class Storage = bool,
           class ParserClass = parser<DataType> >
 class list : public Option, public list_storage<DataType, Storage> {
+  std::vector<unsigned> Positions;
   ParserClass Parser;
 
   virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { 
@@ -884,11 +887,14 @@
     return Parser.getValueExpectedFlagDefault();
   }
 
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
     typename ParserClass::parser_data_type Val;
     if (Parser.parse(*this, ArgName, Arg, Val))
       return true;  // Parse Error!
     addValue(Val);
+    setPosition(pos);
+    Positions.push_back(pos);
     return false;
   }
 
@@ -905,6 +911,11 @@
 public:
   ParserClass &getParser() { return Parser; }
 
+  unsigned getPosition(unsigned optnum) { 
+    assert(optnum < this->size() && "Invalid option index");
+    return Positions[optnum]; 
+  }
+
   // One option...
   template<class M0t>
   list(const M0t &M0) {
@@ -966,16 +977,15 @@
   }
 };
 
-
-
 //===----------------------------------------------------------------------===//
 // Aliased command line option (alias this name to a preexisting name)
 //
 
 class alias : public Option {
   Option *AliasFor;
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
-    return AliasFor->handleOccurrence(AliasFor->ArgStr, Arg);
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
+    return AliasFor->handleOccurrence(pos, AliasFor->ArgStr, Arg);
   }
   // Aliases default to be hidden...
   virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;}
diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h
index 7455f62..053b823 100644
--- a/include/llvm/Support/CommandLine.h
+++ b/include/llvm/Support/CommandLine.h
@@ -51,7 +51,7 @@
 // Flags permitted to be passed to command line arguments
 //
 
-enum NumOccurrences {           // Flags for the number of occurrences allowed
+enum NumOccurrences {          // Flags for the number of occurrences allowed
   Optional        = 0x01,      // Zero or One occurrence
   ZeroOrMore      = 0x02,      // Zero or more occurrences allowed
   Required        = 0x03,      // One occurrence required
@@ -103,13 +103,13 @@
   Positional       = 0x080,     // Is a positional argument, no '-' required
   Prefix           = 0x100,     // Can this option directly prefix its value?
   Grouping         = 0x180,     // Can this option group with other options?
-  FormattingMask   = 0x180,
+  FormattingMask   = 0x180,     // Union of the above flags.
 };
 
-enum MiscFlags {                // Miscellaneous flags to adjust argument
-  CommaSeparated     = 0x200,   // Should this cl::list split between commas?
-  PositionalEatsArgs = 0x400,   // Should this positional cl::list eat -args?
-  MiscMask           = 0x600,
+enum MiscFlags {               // Miscellaneous flags to adjust argument
+  CommaSeparated     = 0x200,  // Should this cl::list split between commas?
+  PositionalEatsArgs = 0x400,  // Should this positional cl::list eat -args?
+  MiscMask           = 0x600,  // Union of the above flags.
 };
 
 
@@ -126,7 +126,8 @@
   // an argument.  Should return true if there was an error processing the
   // argument and the program should exit.
   //
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) = 0;
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) = 0;
 
   virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { 
     return Optional;
@@ -141,8 +142,9 @@
     return NormalFormatting;
   }
 
-  int NumOccurrences;    // The number of times specified
+  int NumOccurrences;   // The number of times specified
   int Flags;            // Flags for the argument
+  unsigned Position;    // Position of last occurrence of the option
 public:
   const char *ArgStr;   // The argument string itself (ex: "help", "o")
   const char *HelpStr;  // The descriptive text message for --help
@@ -171,6 +173,7 @@
   inline unsigned getMiscFlags() const {
     return Flags & MiscMask;
   }
+  inline unsigned getPosition() const { return Position; }
 
   // hasArgStr - Return true if the argstr != ""
   bool hasArgStr() const { return ArgStr[0] != 0; }
@@ -198,8 +201,9 @@
   void setHiddenFlag(enum OptionHidden Val) { setFlag(Val, HiddenMask); }
   void setFormattingFlag(enum FormattingFlags V) { setFlag(V, FormattingMask); }
   void setMiscFlag(enum MiscFlags M) { setFlag(M, M); }
+  void setPosition(unsigned pos) { Position = pos; }
 protected:
-  Option() : NumOccurrences(0), Flags(0),
+  Option() : NumOccurrences(0), Flags(0), Position(0),
              ArgStr(""), HelpStr(""), ValueStr("") {}
 
 public:
@@ -219,7 +223,8 @@
 
   // addOccurrence - Wrapper around handleOccurrence that enforces Flags
   //
-  bool addOccurrence(const char *ArgName, const std::string &Value);
+  bool addOccurrence(unsigned pos, const char *ArgName, 
+                     const std::string &Value);
 
   // Prints option name followed by message.  Always returns true.
   bool error(std::string Message, const char *ArgName = 0);
@@ -250,7 +255,6 @@
   void apply(Option &O) const { O.setValueStr(Desc); }
 };
 
-
 // init - Specify a default (initial) value for the command line argument, if
 // the default constructor for the argument type does not give you what you
 // want.  This is only valid on "opt" arguments, not on "list" arguments.
@@ -438,7 +442,7 @@
   }
 
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
+  bool parse(Option &O, const char *ArgName, const std::string &Arg, 
              DataType &V) {
     std::string ArgVal;
     if (hasArgStr)
@@ -492,7 +496,6 @@
   //
   void printOptionInfo(const Option &O, unsigned GlobalWidth) const;
 
-
   // getValueName - Overload in subclass to provide a better default value.
   virtual const char *getValueName() const { return "value"; }
 };
@@ -545,8 +548,7 @@
 struct parser<unsigned> : public basic_parser<unsigned> {
   
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
-             unsigned &Val);
+  bool parse(Option &O, const char *AN, const std::string &Arg, unsigned &Val);
 
   // getValueName - Overload in subclass to provide a better default value.
   virtual const char *getValueName() const { return "uint"; }
@@ -585,7 +587,7 @@
 template<>
 struct parser<std::string> : public basic_parser<std::string> {
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg,
+  bool parse(Option &O, const char *AN, const std::string &Arg, 
              std::string &Value) {
     Value = Arg;
     return false;
@@ -595,8 +597,6 @@
   virtual const char *getValueName() const { return "string"; }
 };
 
-
-
 //===----------------------------------------------------------------------===//
 // applicator class - This class is used because we must use partial
 // specialization to handle literal string arguments specially (const char* does
@@ -728,11 +728,13 @@
                                is_class<DataType>::value> {
   ParserClass Parser;
 
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
     typename ParserClass::parser_data_type Val;
     if (Parser.parse(*this, ArgName, Arg, Val))
       return true;                            // Parse error!
     setValue(Val);
+    setPosition(pos);
     return false;
   }
 
@@ -875,6 +877,7 @@
 template <class DataType, class Storage = bool,
           class ParserClass = parser<DataType> >
 class list : public Option, public list_storage<DataType, Storage> {
+  std::vector<unsigned> Positions;
   ParserClass Parser;
 
   virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { 
@@ -884,11 +887,14 @@
     return Parser.getValueExpectedFlagDefault();
   }
 
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
     typename ParserClass::parser_data_type Val;
     if (Parser.parse(*this, ArgName, Arg, Val))
       return true;  // Parse Error!
     addValue(Val);
+    setPosition(pos);
+    Positions.push_back(pos);
     return false;
   }
 
@@ -905,6 +911,11 @@
 public:
   ParserClass &getParser() { return Parser; }
 
+  unsigned getPosition(unsigned optnum) { 
+    assert(optnum < this->size() && "Invalid option index");
+    return Positions[optnum]; 
+  }
+
   // One option...
   template<class M0t>
   list(const M0t &M0) {
@@ -966,16 +977,15 @@
   }
 };
 
-
-
 //===----------------------------------------------------------------------===//
 // Aliased command line option (alias this name to a preexisting name)
 //
 
 class alias : public Option {
   Option *AliasFor;
-  virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) {
-    return AliasFor->handleOccurrence(AliasFor->ArgStr, Arg);
+  virtual bool handleOccurrence(unsigned pos, const char *ArgName, 
+                                const std::string &Arg) {
+    return AliasFor->handleOccurrence(pos, AliasFor->ArgStr, Arg);
   }
   // Aliases default to be hidden...
   virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;}
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 131b95a..13de27e 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -111,11 +111,12 @@
   }
 
   // Run the handler now!
-  return Handler->addOccurrence(ArgName, Value);
+  return Handler->addOccurrence(i, ArgName, Value);
 }
 
-static bool ProvidePositionalOption(Option *Handler, const std::string &Arg) {
-  int Dummy;
+static bool ProvidePositionalOption(Option *Handler, const std::string &Arg, 
+                                    int i) {
+  int Dummy = i;
   return ProvideOption(Handler, Handler->ArgStr, Arg.c_str(), 0, 0, Dummy);
 }
 
@@ -323,10 +324,10 @@
     }
   }
 
-  // PositionalVals - A vector of "positional" arguments we accumulate into to
-  // processes at the end...
+  // PositionalVals - A vector of "positional" arguments we accumulate into
+  // the process at the end...
   //
-  std::vector<std::string> PositionalVals;
+  std::vector<std::pair<std::string,unsigned> > PositionalVals;
 
   // If the program has named positional arguments, and the name has been run
   // across, keep track of which positional argument was named.  Otherwise put
@@ -347,10 +348,10 @@
     if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) {
       // Positional argument!
       if (ActivePositionalArg) {
-        ProvidePositionalOption(ActivePositionalArg, argv[i]);
+        ProvidePositionalOption(ActivePositionalArg, argv[i], i);
         continue;  // We are done!
       } else if (!PositionalOpts.empty()) {
-        PositionalVals.push_back(argv[i]);
+        PositionalVals.push_back(std::make_pair(argv[i],i));
 
         // All of the positional arguments have been fulfulled, give the rest to
         // the consume after option... if it's specified...
@@ -358,7 +359,7 @@
         if (PositionalVals.size() >= NumPositionalRequired && 
             ConsumeAfterOpt != 0) {
           for (++i; i < argc; ++i)
-            PositionalVals.push_back(argv[i]);
+            PositionalVals.push_back(std::make_pair(argv[i],i));
           break;   // Handle outside of the argument processing loop...
         }
 
@@ -377,7 +378,7 @@
       ArgName = argv[i]+1;
       Handler = LookupOption(ArgName, Value);
       if (!Handler || Handler->getFormattingFlag() != cl::Positional) {
-        ProvidePositionalOption(ActivePositionalArg, argv[i]);
+        ProvidePositionalOption(ActivePositionalArg, argv[i], i);
         continue;  // We are done!
       }
 
@@ -479,7 +480,9 @@
     unsigned ValNo = 0, NumVals = PositionalVals.size();
     for (unsigned i = 0, e = PositionalOpts.size(); i != e; ++i) {
       if (RequiresValue(PositionalOpts[i])) {
-        ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]);
+        ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo].first, 
+                                PositionalVals[ValNo].second);
+        ValNo++;
         --NumPositionalRequired;  // We fulfilled our duty...
       }
 
@@ -495,7 +498,10 @@
           // FALL THROUGH
         case cl::ZeroOrMore:    // Zero or more will take all they can get...
         case cl::OneOrMore:     // One or more will take all they can get...
-          ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]);
+          ProvidePositionalOption(PositionalOpts[i],
+                                  PositionalVals[ValNo].first,
+                                  PositionalVals[ValNo].second);
+          ValNo++;
           break;
         default:
           assert(0 && "Internal error, unexpected NumOccurrences flag in "
@@ -507,24 +513,31 @@
     assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size());
     unsigned ValNo = 0;
     for (unsigned j = 1, e = PositionalOpts.size(); j != e; ++j)
-      if (RequiresValue(PositionalOpts[j]))
+      if (RequiresValue(PositionalOpts[j])) {
         ErrorParsing |= ProvidePositionalOption(PositionalOpts[j],
-                                                PositionalVals[ValNo++]);
+                                                PositionalVals[ValNo].first,
+                                                PositionalVals[ValNo].second);
+        ValNo++;
+      }
 
     // Handle the case where there is just one positional option, and it's
     // optional.  In this case, we want to give JUST THE FIRST option to the
     // positional option and keep the rest for the consume after.  The above
     // loop would have assigned no values to positional options in this case.
     //
-    if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty())
+    if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) {
       ErrorParsing |= ProvidePositionalOption(PositionalOpts[1],
-                                              PositionalVals[ValNo++]);
+                                              PositionalVals[ValNo].first,
+                                              PositionalVals[ValNo].second);
+      ValNo++;
+    }
     
     // Handle over all of the rest of the arguments to the
     // cl::ConsumeAfter command line option...
     for (; ValNo != PositionalVals.size(); ++ValNo)
       ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt,
-                                              PositionalVals[ValNo]);
+                                              PositionalVals[ValNo].first,
+                                              PositionalVals[ValNo].second);
   }
 
   // Loop over args and make sure all required args are specified!
@@ -567,7 +580,7 @@
   return true;
 }
 
-bool Option::addOccurrence(const char *ArgName, const std::string &Value) {
+bool Option::addOccurrence(unsigned pos, const char *ArgName, const std::string &Value) {
   NumOccurrences++;   // Increment the number of times we have been seen
 
   switch (getNumOccurrencesFlag()) {
@@ -585,7 +598,7 @@
   default: return error(": bad num occurrences flag value!");
   }
 
-  return handleOccurrence(ArgName, Value);
+  return handleOccurrence(pos, ArgName, Value);
 }
 
 // addArgument - Tell the system that this Option subclass will handle all