From 1e13fd23d34e53b63cb08c0fe54f0857757ec200 Mon Sep 17 00:00:00 2001 From: Reid Spencer Date: Fri, 13 Aug 2004 19:47:30 +0000 Subject: [PATCH] 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 --- include/Support/CommandLine.h | 58 +++++++++++++++++------------- include/llvm/Support/CommandLine.h | 58 +++++++++++++++++------------- lib/Support/CommandLine.cpp | 51 ++++++++++++++++---------- 3 files changed, 100 insertions(+), 67 deletions(-) diff --git a/include/Support/CommandLine.h b/include/Support/CommandLine.h index 7455f623ecd..053b823669e 100644 --- a/include/Support/CommandLine.h +++ b/include/Support/CommandLine.h @@ -51,7 +51,7 @@ void ParseEnvironmentOptions(const char *progName, const char *envvar, // 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 @@ enum FormattingFlags { 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 @@ class Option { // 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 @@ class Option { 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 @@ public: 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 @@ public: 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 @@ public: // 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 @@ struct value_desc { 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 @@ public: } // 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 @@ struct basic_parser_impl { // non-template implementation of basic_parser // 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 @@ template<> struct parser : public basic_parser { // 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 @@ struct parser : public basic_parser { template<> struct parser : public basic_parser { // 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 @@ struct parser : public basic_parser { 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 @@ class opt : public Option, is_class::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 @@ struct list_storage : public std::vector { template > class list : public Option, public list_storage { + std::vector Positions; ParserClass Parser; virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { @@ -884,11 +887,14 @@ class list : public Option, public list_storage { 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 @@ class list : public Option, public list_storage { public: ParserClass &getParser() { return Parser; } + unsigned getPosition(unsigned optnum) { + assert(optnum < this->size() && "Invalid option index"); + return Positions[optnum]; + } + // One option... template list(const M0t &M0) { @@ -966,16 +977,15 @@ public: } }; - - //===----------------------------------------------------------------------===// // 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 7455f623ecd..053b823669e 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -51,7 +51,7 @@ void ParseEnvironmentOptions(const char *progName, const char *envvar, // 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 @@ enum FormattingFlags { 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 @@ class Option { // 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 @@ class Option { 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 @@ public: 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 @@ public: 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 @@ public: // 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 @@ struct value_desc { 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 @@ public: } // 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 @@ struct basic_parser_impl { // non-template implementation of basic_parser // 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 @@ template<> struct parser : public basic_parser { // 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 @@ struct parser : public basic_parser { template<> struct parser : public basic_parser { // 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 @@ struct parser : public basic_parser { 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 @@ class opt : public Option, is_class::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 @@ struct list_storage : public std::vector { template > class list : public Option, public list_storage { + std::vector Positions; ParserClass Parser; virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { @@ -884,11 +887,14 @@ class list : public Option, public list_storage { 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 @@ class list : public Option, public list_storage { public: ParserClass &getParser() { return Parser; } + unsigned getPosition(unsigned optnum) { + assert(optnum < this->size() && "Invalid option index"); + return Positions[optnum]; + } + // One option... template list(const M0t &M0) { @@ -966,16 +977,15 @@ public: } }; - - //===----------------------------------------------------------------------===// // 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 131b95a75cf..13de27eb5d5 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -111,11 +111,12 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName, } // 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } } - // 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 PositionalVals; + std::vector > 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, // 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 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 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 @@ bool Option::error(std::string Message, const char *ArgName) { 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 @@ bool Option::addOccurrence(const char *ArgName, const std::string &Value) { 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