diff options
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 328 |
1 files changed, 158 insertions, 170 deletions
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 35c49be02ce..bdebe97d872 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -83,46 +83,130 @@ void StringSaver::anchor() {} //===----------------------------------------------------------------------===// -// Globals for name and overview of program. Program name is not a string to -// avoid static ctor/dtor issues. -static char ProgramName[80] = "<premain>"; -static const char *ProgramOverview = nullptr; +class CommandLineParser { +public: + // Globals for name and overview of program. Program name is not a string to + // avoid static ctor/dtor issues. + char ProgramName[80] = "<premain>"; + const char *ProgramOverview = nullptr; -// This collects additional help to be printed. -static ManagedStatic<std::vector<const char *>> MoreHelp; + // This collects additional help to be printed. + std::vector<const char *> MoreHelp; -extrahelp::extrahelp(const char *Help) : morehelp(Help) { - MoreHelp->push_back(Help); -} + SmallVector<Option *, 4> PositionalOpts; + SmallVector<Option *, 4> SinkOpts; + StringMap<Option *> OptionsMap; -static bool OptionListChanged = false; + Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it exists. -// MarkOptionsChanged - Internal helper function. -void cl::MarkOptionsChanged() { OptionListChanged = true; } + void ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview); -/// RegisteredOptionList - This is the list of the command line options that -/// have statically constructed themselves. -static Option *RegisteredOptionList = nullptr; + void addLiteralOption(Option &Opt, const char *Name) { + if (!Opt.hasArgStr()) { + if (!OptionsMap.insert(std::make_pair(Name, &Opt)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << Name + << "' registered more than once!\n"; + report_fatal_error("inconsistency in registered CommandLine options"); + } + } + } -void Option::addArgument() { - assert(!NextRegistered && "argument multiply registered!"); + void addOption(Option *O) { + bool HadErrors = false; + if (O->ArgStr[0]) { + // Add argument to the argument map! + if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr + << "' registered more than once!\n"; + HadErrors = true; + } + } - NextRegistered = RegisteredOptionList; - RegisteredOptionList = this; - MarkOptionsChanged(); -} + // Remember information about positional options. + if (O->getFormattingFlag() == cl::Positional) + PositionalOpts.push_back(O); + else if (O->getMiscFlags() & cl::Sink) // Remember sink options + SinkOpts.push_back(O); + else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { + if (ConsumeAfterOpt) { + O->error("Cannot specify more than one option with cl::ConsumeAfter!"); + HadErrors = true; + } + ConsumeAfterOpt = O; + } -void Option::removeArgument() { - if (RegisteredOptionList == this) { - RegisteredOptionList = NextRegistered; - MarkOptionsChanged(); - return; + // Fail hard if there were errors. These are strictly unrecoverable and + // indicate serious issues such as conflicting option names or an + // incorrectly + // linked LLVM distribution. + if (HadErrors) + report_fatal_error("inconsistency in registered CommandLine options"); } - Option *O = RegisteredOptionList; - for (; O->NextRegistered != this; O = O->NextRegistered) - ; - O->NextRegistered = NextRegistered; - MarkOptionsChanged(); + + void removeOption(Option *O) { + SmallVector<const char *, 16> OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + for (auto Name : OptionNames) + OptionsMap.erase(StringRef(Name)); + + if (O->getFormattingFlag() == cl::Positional) + for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end(); + ++Opt) { + if (*Opt == O) { + PositionalOpts.erase(Opt); + break; + } + } + else if (O->getMiscFlags() & cl::Sink) + for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) { + if (*Opt == O) { + SinkOpts.erase(Opt); + break; + } + } + else if (O == ConsumeAfterOpt) + ConsumeAfterOpt = nullptr; + } + + bool hasOptions() { + return (!OptionsMap.empty() || !PositionalOpts.empty() || + nullptr != ConsumeAfterOpt); + } + + void updateArgStr(Option *O, const char* NewName) { + if (!OptionsMap.insert(std::make_pair(NewName, O)).second) { + errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr + << "' registered more than once!\n"; + report_fatal_error("inconsistency in registered CommandLine options"); + } + OptionsMap.erase(StringRef(O->ArgStr)); + } +}; + +static ManagedStatic<CommandLineParser> GlobalParser; + +void cl::AddLiteralOption(Option &O, const char *Name) { + GlobalParser->addLiteralOption(O, Name); +} + +extrahelp::extrahelp(const char *Help) : morehelp(Help) { + GlobalParser->MoreHelp.push_back(Help); +} + +void Option::addArgument() { + GlobalParser->addOption(this); + FullyInitialized = true; +} + +void Option::removeArgument() { GlobalParser->removeOption(this); } + +void Option::setArgStr(const char *S) { + if (FullyInitialized) + GlobalParser->updateArgStr(this, S); + ArgStr = S; } // This collects the different option categories that have been registered. @@ -147,60 +231,6 @@ void OptionCategory::registerCategory() { // Basic, shared command line option processing machinery. // -/// GetOptionInfo - Scan the list of registered options, turning them into data -/// structures that are easier to handle. -static void GetOptionInfo(SmallVectorImpl<Option *> &PositionalOpts, - SmallVectorImpl<Option *> &SinkOpts, - StringMap<Option *> &OptionsMap) { - bool HadErrors = false; - SmallVector<const char *, 16> OptionNames; - Option *CAOpt = nullptr; // The ConsumeAfter option if it exists. - 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 (size_t i = 0, e = OptionNames.size(); i != e; ++i) { - // Add argument to the argument map! - if (!OptionsMap.insert(std::make_pair(OptionNames[i], O)).second) { - errs() << ProgramName << ": CommandLine Error: Option '" - << OptionNames[i] << "' registered more than once!\n"; - HadErrors = true; - } - } - - OptionNames.clear(); - - // Remember information about positional options. - if (O->getFormattingFlag() == cl::Positional) - PositionalOpts.push_back(O); - else if (O->getMiscFlags() & cl::Sink) // Remember sink options - SinkOpts.push_back(O); - else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { - if (CAOpt) { - O->error("Cannot specify more than one option with cl::ConsumeAfter!"); - HadErrors = true; - } - CAOpt = O; - } - } - - if (CAOpt) - PositionalOpts.push_back(CAOpt); - - // Make sure that they are in order of registration not backwards. - std::reverse(PositionalOpts.begin(), PositionalOpts.end()); - - // Fail hard if there were errors. These are strictly unrecoverable and - // indicate serious issues such as conflicting option names or an incorrectly - // linked LLVM distribution. - if (HadErrors) - report_fatal_error("inconsistency in registered CommandLine options"); -} - /// 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. This assumes that leading dashes have already been stripped. @@ -789,13 +819,13 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, void cl::ParseCommandLineOptions(int argc, const char *const *argv, const char *Overview) { - // Process all registered options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> Opts; - GetOptionInfo(PositionalOpts, SinkOpts, Opts); + GlobalParser->ParseCommandLineOptions(argc, argv, Overview); +} - assert((!Opts.empty() || !PositionalOpts.empty()) && "No options specified!"); +void CommandLineParser::ParseCommandLineOptions(int argc, + const char *const *argv, + const char *Overview) { + assert(hasOptions() && "No options specified!"); // Expand response files. SmallVector<const char *, 20> newArgv; @@ -821,25 +851,22 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // Determine whether or not there are an unlimited number of positionals bool HasUnlimitedPositionals = false; - Option *ConsumeAfterOpt = nullptr; + if (ConsumeAfterOpt) { + assert(PositionalOpts.size() > 0 && + "Cannot specify cl::ConsumeAfter without a positional argument!"); + } if (!PositionalOpts.empty()) { - if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) { - assert(PositionalOpts.size() > 1 && - "Cannot specify cl::ConsumeAfter without a positional argument!"); - ConsumeAfterOpt = PositionalOpts[0]; - } // Calculate how many positional values are _required_. bool UnboundedFound = false; - for (size_t i = ConsumeAfterOpt ? 1 : 0, e = PositionalOpts.size(); i != e; - ++i) { + for (size_t i = 0, e = PositionalOpts.size(); i != e; ++i) { Option *Opt = PositionalOpts[i]; if (RequiresValue(Opt)) ++NumPositionalRequired; else if (ConsumeAfterOpt) { // ConsumeAfter cannot be combined with "optional" positional options // unless there is only one positional argument... - if (PositionalOpts.size() > 2) + if (PositionalOpts.size() > 1) ErrorParsing |= Opt->error( "error - this positional option will never be matched, " "because it does not Require a value, and a " @@ -853,6 +880,9 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, "another positional argument will match an " "unbounded number of values, and this option" " does not require a value!"); + errs() << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr + << "' is all messed up!\n"; + errs() << PositionalOpts.size(); } UnboundedFound |= EatsUnboundedNumberOfValues(Opt); } @@ -878,17 +908,6 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Value; StringRef ArgName = ""; - // If the option list changed, this means that some command line - // option has just been registered or deregistered. This can occur in - // response to things like -load, etc. If this happens, rescan the options. - if (OptionListChanged) { - PositionalOpts.clear(); - SinkOpts.clear(); - Opts.clear(); - GetOptionInfo(PositionalOpts, SinkOpts, Opts); - OptionListChanged = false; - } - // Check to see if this is a positional argument. This argument is // considered to be positional if it doesn't start with '-', if it is "-" // itself, or if we have seen "--" already. @@ -929,7 +948,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value, Opts); + Handler = LookupOption(ArgName, Value, OptionsMap); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! @@ -941,18 +960,18 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, while (!ArgName.empty() && ArgName[0] == '-') ArgName = ArgName.substr(1); - Handler = LookupOption(ArgName, Value, Opts); + Handler = LookupOption(ArgName, Value, OptionsMap); // Check to see if this "option" is really a prefixed or grouped argument. if (!Handler) - Handler = - HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, Opts); + Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, + OptionsMap); // Otherwise, look for the closest available option to report to the user // in the upcoming error. if (!Handler && SinkOpts.empty()) NearestHandler = - LookupNearestOption(ArgName, Opts, NearestHandlerString); + LookupNearestOption(ArgName, OptionsMap, NearestHandlerString); } if (!Handler) { @@ -1049,8 +1068,8 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // 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()) { - ErrorParsing |= ProvidePositionalOption(PositionalOpts[1], + if (PositionalOpts.size() == 1 && ValNo == 0 && !PositionalVals.empty()) { + ErrorParsing |= ProvidePositionalOption(PositionalOpts[0], PositionalVals[ValNo].first, PositionalVals[ValNo].second); ValNo++; @@ -1065,7 +1084,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, } // Loop over args and make sure all required args are specified! - for (const auto &Opt : Opts) { + for (const auto &Opt : OptionsMap) { switch (Opt.second->getNumOccurrencesFlag()) { case Required: case OneOrMore: @@ -1088,9 +1107,7 @@ void cl::ParseCommandLineOptions(int argc, const char *const *argv, // Free all of the memory allocated to the map. Command line options may only // be processed once! - Opts.clear(); - PositionalOpts.clear(); - MoreHelp->clear(); + MoreHelp.clear(); // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) @@ -1107,7 +1124,7 @@ bool Option::error(const Twine &Message, StringRef ArgName) { if (ArgName.empty()) errs() << HelpStr; // Be nice for positional arguments else - errs() << ProgramName << ": for the -" << ArgName; + errs() << GlobalParser->ProgramName << ": for the -" << ArgName; errs() << " option: " << Message << "\n"; return true; @@ -1495,35 +1512,23 @@ public: if (Value == false) return; - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> OptMap; - GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - StrOptionPairVector Opts; - sortOpts(OptMap, Opts, ShowHidden); - - if (ProgramOverview) - outs() << "OVERVIEW: " << ProgramOverview << "\n"; + sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden); - outs() << "USAGE: " << ProgramName << " [options]"; + if (GlobalParser->ProgramOverview) + outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n"; - // Print out the positional options. - Option *CAOpt = nullptr; // The cl::ConsumeAfter option, if it exists... - if (!PositionalOpts.empty() && - PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) - CAOpt = PositionalOpts[0]; + outs() << "USAGE: " << GlobalParser->ProgramName << " [options]"; - for (size_t i = CAOpt != nullptr, e = PositionalOpts.size(); i != e; ++i) { - if (PositionalOpts[i]->ArgStr[0]) - outs() << " --" << PositionalOpts[i]->ArgStr; - outs() << " " << PositionalOpts[i]->HelpStr; + for (auto Opt : GlobalParser->PositionalOpts) { + if (Opt->ArgStr[0]) + outs() << " --" << Opt->ArgStr; + outs() << " " << Opt->HelpStr; } // Print the consume after option info if it exists... - if (CAOpt) - outs() << " " << CAOpt->HelpStr; + if (GlobalParser->ConsumeAfterOpt) + outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr; outs() << "\n\n"; @@ -1536,11 +1541,9 @@ public: printOptions(Opts, MaxArgLen); // Print any extra help the user has declared. - for (std::vector<const char *>::iterator I = MoreHelp->begin(), - E = MoreHelp->end(); - I != E; ++I) - outs() << *I; - MoreHelp->clear(); + for (auto I : GlobalParser->MoreHelp) + outs() << I; + GlobalParser->MoreHelp.clear(); // Halt the program since help information was printed exit(0); @@ -1727,14 +1730,8 @@ void cl::PrintOptionValues() { if (!PrintOptions && !PrintAllOptions) return; - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; - SmallVector<Option *, 4> SinkOpts; - StringMap<Option *> OptMap; - GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - SmallVector<std::pair<const char *, Option *>, 128> Opts; - sortOpts(OptMap, Opts, /*ShowHidden*/ true); + sortOpts(GlobalParser->OptionsMap, Opts, /*ShowHidden*/ true); // Compute the maximum argument length... size_t MaxArgLen = 0; @@ -1842,19 +1839,12 @@ void cl::AddExtraVersionPrinter(void (*func)()) { ExtraVersionPrinters->push_back(func); } -void cl::getRegisteredOptions(StringMap<Option *> &Map) { - // Get all the options. - SmallVector<Option *, 4> PositionalOpts; // NOT USED - SmallVector<Option *, 4> SinkOpts; // NOT USED - assert(Map.size() == 0 && "StringMap must be empty"); - GetOptionInfo(PositionalOpts, SinkOpts, Map); - return; +StringMap<Option *> &cl::getRegisteredOptions() { + return GlobalParser->OptionsMap; } void cl::HideUnrelatedOptions(cl::OptionCategory &Category) { - StringMap<cl::Option *> Options; - cl::getRegisteredOptions(Options); - for (auto &I : Options) { + for (auto &I : GlobalParser->OptionsMap) { if (I.second->Category != &Category && I.second->Category != &GenericCategory) I.second->setHiddenFlag(cl::ReallyHidden); @@ -1864,9 +1854,7 @@ void cl::HideUnrelatedOptions(cl::OptionCategory &Category) { void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) { auto CategoriesBegin = Categories.begin(); auto CategoriesEnd = Categories.end(); - StringMap<cl::Option *> Options; - cl::getRegisteredOptions(Options); - for (auto &I : Options) { + for (auto &I : GlobalParser->OptionsMap) { if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) == CategoriesEnd && I.second->Category != &GenericCategory) |