diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 4758ff5b399..328aae1c98b 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -142,16 +142,18 @@ class Option { virtual enum ValueExpected getValueExpectedFlagDefault() const { return ValueOptional; } + // Out of line virtual function to provide home for the class. virtual void anchor(); - int NumOccurrences; // The number of times specified - int Flags; // Flags for the argument - unsigned Position; // Position of last occurrence of the option + int NumOccurrences; // The number of times specified + int Flags; // Flags for the argument + unsigned Position; // Position of last occurrence of the option + Option *NextRegistered; // Singly linked list of registered options. public: - const char *ArgStr; // The argument string itself (ex: "help", "o") - const char *HelpStr; // The descriptive text message for --help - const char *ValueStr; // String describing what the value of this option is + const char *ArgStr; // The argument string itself (ex: "help", "o") + const char *HelpStr; // The descriptive text message for --help + const char *ValueStr; // String describing what the value of this option is inline enum NumOccurrences getNumOccurrencesFlag() const { return static_cast(Flags & OccurrencesMask); @@ -198,16 +200,17 @@ public: protected: Option(unsigned DefaultFlags) : NumOccurrences(0), Flags(DefaultFlags | NormalFormatting), Position(0), - ArgStr(""), HelpStr(""), ValueStr("") { + NextRegistered(0), ArgStr(""), HelpStr(""), ValueStr("") { assert(getNumOccurrencesFlag() != 0 && getOptionHiddenFlag() != 0 && "Not all default flags specified!"); } public: - // addArgument - Tell the system that this Option subclass will handle all - // occurrences of -ArgStr on the command line. + // addArgument - Register this argument with the commandline system. // - void addArgument(const char *ArgStr); + void addArgument(); + + Option *getNextRegisteredOption() const { return NextRegistered; } // Return the width of the option tag for printing... virtual unsigned getOptionWidth() const = 0; @@ -217,6 +220,8 @@ public: // virtual void printOptionInfo(unsigned GlobalWidth) const = 0; + virtual void getExtraOptionNames(std::vector &OptionNames) {} + // addOccurrence - Wrapper around handleOccurrence that enforces Flags // bool addOccurrence(unsigned pos, const char *ArgName, @@ -379,16 +384,18 @@ struct generic_parser_base { // argstr field should be stable, copy it down now. // hasArgStr = O.hasArgStr(); - + } + + void getExtraOptionNames(std::vector &OptionNames) { // If there has been no argstr specified, that means that we need to add an // argument for every possible option. This ensures that our options are // vectored to us. - // if (!hasArgStr) for (unsigned i = 0, e = getNumOptions(); i != e; ++i) - O.addArgument(getOption(i)); + OptionNames.push_back(getOption(i)); } + enum ValueExpected getValueExpectedFlagDefault() const { // If there is an ArgStr specified, then we are of the form: // @@ -483,6 +490,8 @@ struct basic_parser_impl { // non-template implementation of basic_parser return ValueRequired; } + void getExtraOptionNames(std::vector &OptionNames) {} + void initialize(Option &O) {} // Return the width of the option tag for printing... @@ -772,6 +781,9 @@ class opt : public Option, virtual enum ValueExpected getValueExpectedFlagDefault() const { return Parser.getValueExpectedFlagDefault(); } + virtual void getExtraOptionNames(std::vector &OptionNames) { + return Parser.getExtraOptionNames(OptionNames); + } // Forward printing stuff to the parser... virtual unsigned getOptionWidth() const {return Parser.getOptionWidth(*this);} @@ -780,7 +792,7 @@ class opt : public Option, } void done() { - addArgument(ArgStr); + addArgument(); Parser.initialize(*this); } public: @@ -923,7 +935,10 @@ class list : public Option, public list_storage { virtual enum ValueExpected getValueExpectedFlagDefault() const { return Parser.getValueExpectedFlagDefault(); } - + virtual void getExtraOptionNames(std::vector &OptionNames) { + return Parser.getExtraOptionNames(OptionNames); + } + virtual bool handleOccurrence(unsigned pos, const char *ArgName, const std::string &Arg) { typename ParserClass::parser_data_type Val = @@ -943,7 +958,7 @@ class list : public Option, public list_storage { } void done() { - addArgument(ArgStr); + addArgument(); Parser.initialize(*this); } public: @@ -1106,7 +1121,10 @@ class bits : public Option, public bits_storage { virtual enum ValueExpected getValueExpectedFlagDefault() const { return Parser.getValueExpectedFlagDefault(); } - + virtual void getExtraOptionNames(std::vector &OptionNames) { + return Parser.getExtraOptionNames(OptionNames); + } + virtual bool handleOccurrence(unsigned pos, const char *ArgName, const std::string &Arg) { typename ParserClass::parser_data_type Val = @@ -1126,7 +1144,7 @@ class bits : public Option, public bits_storage { } void done() { - addArgument(ArgStr); + addArgument(); Parser.initialize(*this); } public: @@ -1221,7 +1239,7 @@ class alias : public Option { error(": cl::alias must have argument name specified!"); if (AliasFor == 0) error(": cl::alias must have an cl::aliasopt(option) specified!"); - addArgument(ArgStr); + addArgument(); } public: void setAliasFor(Option &O) { diff --git a/include/llvm/Support/PassNameParser.h b/include/llvm/Support/PassNameParser.h index 83653aa7453..e87e16a21bb 100644 --- a/include/llvm/Support/PassNameParser.h +++ b/include/llvm/Support/PassNameParser.h @@ -70,7 +70,6 @@ public: abort(); } addLiteralOption(P->getPassArgument(), P, P->getPassName()); - Opt->addArgument(P->getPassArgument()); } virtual void passEnumerate(const PassInfo *P) { passRegistered(P); } diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 5fa65d82ba5..e349eaa514c 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -71,32 +71,63 @@ extrahelp::extrahelp(const char *Help) MoreHelp->push_back(Help); } +/// RegisteredOptionList - This is the list of the command line options that +/// have statically constructed themselves. +static Option *RegisteredOptionList = 0; + +void Option::addArgument() { + assert(NextRegistered == 0 && "argument multiply registered!"); + + NextRegistered = RegisteredOptionList; + RegisteredOptionList = this; +} + //===----------------------------------------------------------------------===// // Basic, shared command line option processing machinery. // -static ManagedStatic > OptionsMap; -static ManagedStatic > PositionalOptions; - -static Option *getOption(const std::string &Str) { - std::map::iterator I = OptionsMap->find(Str); - return I != OptionsMap->end() ? I->second : 0; -} - -static void AddArgument(const char *ArgName, Option *Opt) { - if (getOption(ArgName)) { - cerr << ProgramName << ": CommandLine Error: Argument '" - << ArgName << "' defined more than once!\n"; - } else { - // Add argument to the argument map! - (*OptionsMap)[ArgName] = Opt; +/// GetOptionInfo - Scan the list of registered options, turning them into data +/// structures that are easier to handle. +static void GetOptionInfo(std::vector &PositionalOpts, + std::map &OptionsMap) { + std::vector OptionNames; + for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) { + // If this option wants to handle multiple option names, get the full set. + // This handles enum options like "-O1 -O2" etc. + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + + // Handle named options. + for (unsigned i = 0, e = OptionNames.size(); i != e; ++i) { + // Add argument to the argument map! + if (!OptionsMap.insert(std::pair(OptionNames[i], + O)).second) { + cerr << ProgramName << ": CommandLine Error: Argument '" + << OptionNames[0] << "' defined more than once!\n"; + } + } + + OptionNames.clear(); + + // Remember information about positional options. + if (O->getFormattingFlag() == cl::Positional) + PositionalOpts.push_back(O); + else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { + if (!PositionalOpts.empty() && + PositionalOpts.front()->getNumOccurrencesFlag() == cl::ConsumeAfter) + O->error("Cannot specify more than one option with cl::ConsumeAfter!"); + PositionalOpts.insert(PositionalOpts.begin(), O); + } } } + /// LookupOption - Lookup the option specified by the specified option on the /// command line. If there is a value specified (after an equal sign) return /// that as well. -static Option *LookupOption(const char *&Arg, const char *&Value) { +static Option *LookupOption(const char *&Arg, const char *&Value, + std::map &OptionsMap) { while (*Arg == '-') ++Arg; // Eat leading dashes const char *ArgEnd = Arg; @@ -110,10 +141,9 @@ static Option *LookupOption(const char *&Arg, const char *&Value) { if (*Arg == 0) return 0; // Look up the option. - std::map &Opts = *OptionsMap; std::map::iterator I = - Opts.find(std::string(Arg, ArgEnd)); - return (I != Opts.end()) ? I->second : 0; + OptionsMap.find(std::string(Arg, ArgEnd)); + return I != OptionsMap.end() ? I->second : 0; } static inline bool ProvideOption(Option *Handler, const char *ArgName, @@ -171,27 +201,28 @@ static inline bool isPrefixedOrGrouping(const Option *O) { // otherwise return null. // static Option *getOptionPred(std::string Name, unsigned &Length, - bool (*Pred)(const Option*)) { + bool (*Pred)(const Option*), + std::map &OptionsMap) { - Option *Op = getOption(Name); - if (Op && Pred(Op)) { + std::map::iterator OMI = OptionsMap.find(Name); + if (OMI != OptionsMap.end() && Pred(OMI->second)) { Length = Name.length(); - return Op; + return OMI->second; } if (Name.size() == 1) return 0; do { Name.erase(Name.end()-1, Name.end()); // Chop off the last character... - Op = getOption(Name); + OMI = OptionsMap.find(Name); // Loop while we haven't found an option and Name still has at least two // characters in it (so that the next iteration will not be the empty // string... - } while ((Op == 0 || !Pred(Op)) && Name.size() > 1); + } while ((OMI == OptionsMap.end() || !Pred(OMI->second)) && Name.size() > 1); - if (Op && Pred(Op)) { + if (OMI != OptionsMap.end() && Pred(OMI->second)) { Length = Name.length(); - return Op; // Found one! + return OMI->second; // Found one! } return 0; // No option found! } @@ -286,9 +317,13 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, void cl::ParseCommandLineOptions(int &argc, char **argv, const char *Overview) { - assert((!OptionsMap->empty() || !PositionalOptions->empty()) && - "No options specified, or ParseCommandLineOptions called more" - " than once!"); + // Process all registered options. + std::vector PositionalOpts; + std::map Opts; + GetOptionInfo(PositionalOpts, Opts); + + assert((!Opts.empty() || !PositionalOpts.empty()) && + "No options specified!"); sys::Path progname(argv[0]); // Copy the program name into ProgName, making sure not to overflow it. @@ -299,9 +334,6 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, ProgramOverview = Overview; bool ErrorParsing = false; - std::map &Opts = *OptionsMap; - std::vector &PositionalOpts = *PositionalOptions; - // Check out the positional arguments to collect information about them. unsigned NumPositionalRequired = 0; @@ -398,7 +430,7 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, // option is another positional argument. If so, treat it as an argument, // otherwise feed it to the eating positional. ArgName = argv[i]+1; - Handler = LookupOption(ArgName, Value); + Handler = LookupOption(ArgName, Value, Opts); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! @@ -406,14 +438,15 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } else { // We start with a '-', must be an argument... ArgName = argv[i]+1; - Handler = LookupOption(ArgName, Value); + Handler = LookupOption(ArgName, Value, Opts); // Check to see if this "option" is really a prefixed or grouped argument. if (Handler == 0) { std::string RealName(ArgName); if (RealName.size() > 1) { unsigned Length = 0; - Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping); + Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping, + Opts); // If the option is a prefixed option, then the value is simply the // rest of the name... so fall through to later processing, by @@ -444,7 +477,7 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, 0, 0, 0, Dummy); // Get the next grouping option... - PGOpt = getOptionPred(RealName, Length, isGrouping); + PGOpt = getOptionPred(RealName, Length, isGrouping, Opts); } while (PGOpt && Length != RealName.size()); Handler = PGOpt; // Ate all of the options. @@ -633,23 +666,6 @@ bool Option::addOccurrence(unsigned pos, const char *ArgName, return handleOccurrence(pos, ArgName, Value); } -// addArgument - Tell the system that this Option subclass will handle all -// occurrences of -ArgStr on the command line. -// -void Option::addArgument(const char *ArgStr) { - if (ArgStr[0]) - AddArgument(ArgStr, this); - - if (getFormattingFlag() == Positional) - PositionalOptions->push_back(this); - else if (getNumOccurrencesFlag() == ConsumeAfter) { - if (!PositionalOptions->empty() && - PositionalOptions->front()->getNumOccurrencesFlag() == ConsumeAfter) - error("Cannot specify more than one option with cl::ConsumeAfter!"); - PositionalOptions->insert(PositionalOptions->begin(), this); - } -} - // getValueStr - Get the value description string, using "DefaultMsg" if nothing // has been specified yet. @@ -867,9 +883,14 @@ public: void operator=(bool Value) { if (Value == false) return; + // Get all the options. + std::vector PositionalOpts; + std::map OptMap; + GetOptionInfo(PositionalOpts, OptMap); + // Copy Options into a vector so we can sort them as we like... std::vector > Opts; - copy(OptionsMap->begin(), OptionsMap->end(), std::back_inserter(Opts)); + copy(OptMap.begin(), OptMap.end(), std::back_inserter(Opts)); // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden Opts.erase(std::remove_if(Opts.begin(), Opts.end(), @@ -892,15 +913,15 @@ public: cout << "USAGE: " << ProgramName << " [options]"; // Print out the positional options. - std::vector &PosOpts = *PositionalOptions; Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists... - if (!PosOpts.empty() && PosOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) - CAOpt = PosOpts[0]; + if (!PositionalOpts.empty() && + PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) + CAOpt = PositionalOpts[0]; - for (unsigned i = CAOpt != 0, e = PosOpts.size(); i != e; ++i) { - if (PosOpts[i]->ArgStr[0]) - cout << " --" << PosOpts[i]->ArgStr; - cout << " " << PosOpts[i]->HelpStr; + for (unsigned i = CAOpt != 0, e = PositionalOpts.size(); i != e; ++i) { + if (PositionalOpts[i]->ArgStr[0]) + cout << " --" << PositionalOpts[i]->ArgStr; + cout << " " << PositionalOpts[i]->HelpStr; } // Print the consume after option info if it exists... @@ -924,7 +945,6 @@ public: MoreHelp->clear(); // Halt the program since help information was printed - OptionsMap->clear(); // Don't bother making option dtors remove from map. exit(1); } }; @@ -970,7 +990,6 @@ public: if (OptionWasSpecified) { if (OverrideVersionPrinter == 0) { print(); - OptionsMap->clear();// Don't bother making option dtors remove from map. exit(1); } else { (*OverrideVersionPrinter)();