diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 | 
| commit | 01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch) | |
| tree | 4def12e759965de927d963ac65840d663ef9d1ea /lib/Support/CommandLine.cpp | |
| parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) | |
Diffstat (limited to 'lib/Support/CommandLine.cpp')
| -rw-r--r-- | lib/Support/CommandLine.cpp | 545 | 
1 files changed, 422 insertions, 123 deletions
| diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index fdcdb03706de9..a5d2ba2d6a2de 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -19,6 +19,7 @@  #include "llvm/Support/CommandLine.h"  #include "llvm-c/Support.h"  #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/ADT/SmallPtrSet.h"  #include "llvm/ADT/SmallString.h" @@ -94,35 +95,56 @@ public:    // This collects additional help to be printed.    std::vector<const char *> MoreHelp; -  SmallVector<Option *, 4> PositionalOpts; -  SmallVector<Option *, 4> SinkOpts; -  StringMap<Option *> OptionsMap; - -  Option *ConsumeAfterOpt; // The ConsumeAfter option if it exists. -    // This collects the different option categories that have been registered.    SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; -  CommandLineParser() : ProgramOverview(nullptr), ConsumeAfterOpt(nullptr) {} +  // This collects the different subcommands that have been registered. +  SmallPtrSet<SubCommand *, 4> RegisteredSubCommands; -  void ParseCommandLineOptions(int argc, const char *const *argv, -                               const char *Overview); +  CommandLineParser() : ProgramOverview(nullptr), ActiveSubCommand(nullptr) { +    registerSubCommand(&*TopLevelSubCommand); +    registerSubCommand(&*AllSubCommands); +  } -  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 ResetAllOptionOccurrences(); + +  bool ParseCommandLineOptions(int argc, const char *const *argv, +                               const char *Overview, bool IgnoreErrors); + +  void addLiteralOption(Option &Opt, SubCommand *SC, const char *Name) { +    if (Opt.hasArgStr()) +      return; +    if (!SC->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"); +    } + +    // If we're adding this to all sub-commands, add it to the ones that have +    // already been registered. +    if (SC == &*AllSubCommands) { +      for (const auto &Sub : RegisteredSubCommands) { +        if (SC == Sub) +          continue; +        addLiteralOption(Opt, Sub, Name);        }      }    } -  void addOption(Option *O) { +  void addLiteralOption(Option &Opt, const char *Name) { +    if (Opt.Subs.empty()) +      addLiteralOption(Opt, &*TopLevelSubCommand, Name); +    else { +      for (auto SC : Opt.Subs) +        addLiteralOption(Opt, SC, Name); +    } +  } + +  void addOption(Option *O, SubCommand *SC) {      bool HadErrors = false;      if (O->hasArgStr()) {        // Add argument to the argument map! -      if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { +      if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) {          errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr                 << "' registered more than once!\n";          HadErrors = true; @@ -131,15 +153,15 @@ public:      // Remember information about positional options.      if (O->getFormattingFlag() == cl::Positional) -      PositionalOpts.push_back(O); +      SC->PositionalOpts.push_back(O);      else if (O->getMiscFlags() & cl::Sink) // Remember sink options -      SinkOpts.push_back(O); +      SC->SinkOpts.push_back(O);      else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { -      if (ConsumeAfterOpt) { +      if (SC->ConsumeAfterOpt) {          O->error("Cannot specify more than one option with cl::ConsumeAfter!");          HadErrors = true;        } -      ConsumeAfterOpt = O; +      SC->ConsumeAfterOpt = O;      }      // Fail hard if there were errors. These are strictly unrecoverable and @@ -148,64 +170,165 @@ public:      // linked LLVM distribution.      if (HadErrors)        report_fatal_error("inconsistency in registered CommandLine options"); + +    // If we're adding this to all sub-commands, add it to the ones that have +    // already been registered. +    if (SC == &*AllSubCommands) { +      for (const auto &Sub : RegisteredSubCommands) { +        if (SC == Sub) +          continue; +        addOption(O, Sub); +      } +    }    } -  void removeOption(Option *O) { +  void addOption(Option *O) { +    if (O->Subs.empty()) { +      addOption(O, &*TopLevelSubCommand); +    } else { +      for (auto SC : O->Subs) +        addOption(O, SC); +    } +  } + +  void removeOption(Option *O, SubCommand *SC) {      SmallVector<StringRef, 16> OptionNames;      O->getExtraOptionNames(OptionNames);      if (O->hasArgStr())        OptionNames.push_back(O->ArgStr); + +    SubCommand &Sub = *SC;      for (auto Name : OptionNames) -      OptionsMap.erase(Name); +      Sub.OptionsMap.erase(Name);      if (O->getFormattingFlag() == cl::Positional) -      for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end(); -           ++Opt) { +      for (auto Opt = Sub.PositionalOpts.begin(); +           Opt != Sub.PositionalOpts.end(); ++Opt) {          if (*Opt == O) { -          PositionalOpts.erase(Opt); +          Sub.PositionalOpts.erase(Opt);            break;          }        }      else if (O->getMiscFlags() & cl::Sink) -      for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) { +      for (auto Opt = Sub.SinkOpts.begin(); Opt != Sub.SinkOpts.end(); ++Opt) {          if (*Opt == O) { -          SinkOpts.erase(Opt); +          Sub.SinkOpts.erase(Opt);            break;          }        } -    else if (O == ConsumeAfterOpt) -      ConsumeAfterOpt = nullptr; +    else if (O == Sub.ConsumeAfterOpt) +      Sub.ConsumeAfterOpt = nullptr;    } -  bool hasOptions() { -    return (!OptionsMap.empty() || !PositionalOpts.empty() || -            nullptr != ConsumeAfterOpt); +  void removeOption(Option *O) { +    if (O->Subs.empty()) +      removeOption(O, &*TopLevelSubCommand); +    else { +      if (O->isInAllSubCommands()) { +        for (auto SC : RegisteredSubCommands) +          removeOption(O, SC); +      } else { +        for (auto SC : O->Subs) +          removeOption(O, SC); +      } +    }    } -  void updateArgStr(Option *O, StringRef NewName) { -    if (!OptionsMap.insert(std::make_pair(NewName, O)).second) { +  bool hasOptions(const SubCommand &Sub) const { +    return (!Sub.OptionsMap.empty() || !Sub.PositionalOpts.empty() || +            nullptr != Sub.ConsumeAfterOpt); +  } + +  bool hasOptions() const { +    for (const auto &S : RegisteredSubCommands) { +      if (hasOptions(*S)) +        return true; +    } +    return false; +  } + +  SubCommand *getActiveSubCommand() { return ActiveSubCommand; } + +  void updateArgStr(Option *O, StringRef NewName, SubCommand *SC) { +    SubCommand &Sub = *SC; +    if (!Sub.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(O->ArgStr); +    Sub.OptionsMap.erase(O->ArgStr); +  } + +  void updateArgStr(Option *O, StringRef NewName) { +    if (O->Subs.empty()) +      updateArgStr(O, NewName, &*TopLevelSubCommand); +    else { +      for (auto SC : O->Subs) +        updateArgStr(O, NewName, SC); +    }    }    void printOptionValues();    void registerCategory(OptionCategory *cat) { -    assert(std::count_if(RegisteredOptionCategories.begin(), -                         RegisteredOptionCategories.end(), -                         [cat](const OptionCategory *Category) { -                           return cat->getName() == Category->getName(); -                         }) == 0 && +    assert(count_if(RegisteredOptionCategories, +                    [cat](const OptionCategory *Category) { +             return cat->getName() == Category->getName(); +           }) == 0 &&             "Duplicate option categories");      RegisteredOptionCategories.insert(cat);    } +  void registerSubCommand(SubCommand *sub) { +    assert(count_if(RegisteredSubCommands, +                    [sub](const SubCommand *Sub) { +                      return (sub->getName() != nullptr) && +                             (Sub->getName() == sub->getName()); +                    }) == 0 && +           "Duplicate subcommands"); +    RegisteredSubCommands.insert(sub); + +    // For all options that have been registered for all subcommands, add the +    // option to this subcommand now. +    if (sub != &*AllSubCommands) { +      for (auto &E : AllSubCommands->OptionsMap) { +        Option *O = E.second; +        if ((O->isPositional() || O->isSink() || O->isConsumeAfter()) || +            O->hasArgStr()) +          addOption(O, sub); +        else +          addLiteralOption(*O, sub, E.first().str().c_str()); +      } +    } +  } + +  void unregisterSubCommand(SubCommand *sub) { +    RegisteredSubCommands.erase(sub); +  } + +  void reset() { +    ActiveSubCommand = nullptr; +    ProgramName.clear(); +    ProgramOverview = nullptr; + +    MoreHelp.clear(); +    RegisteredOptionCategories.clear(); + +    ResetAllOptionOccurrences(); +    RegisteredSubCommands.clear(); + +    TopLevelSubCommand->reset(); +    AllSubCommands->reset(); +    registerSubCommand(&*TopLevelSubCommand); +    registerSubCommand(&*AllSubCommands); +  } +  private: -  Option *LookupOption(StringRef &Arg, StringRef &Value); +  SubCommand *ActiveSubCommand; + +  Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); +  SubCommand *LookupSubCommand(const char *Name);  };  } // namespace @@ -240,6 +363,32 @@ void OptionCategory::registerCategory() {    GlobalParser->registerCategory(this);  } +// A special subcommand representing no subcommand +ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand; + +// A special subcommand that can be used to put an option into all subcommands. +ManagedStatic<SubCommand> llvm::cl::AllSubCommands; + +void SubCommand::registerSubCommand() { +  GlobalParser->registerSubCommand(this); +} + +void SubCommand::unregisterSubCommand() { +  GlobalParser->unregisterSubCommand(this); +} + +void SubCommand::reset() { +  PositionalOpts.clear(); +  SinkOpts.clear(); +  OptionsMap.clear(); + +  ConsumeAfterOpt = nullptr; +} + +SubCommand::operator bool() const { +  return (GlobalParser->getActiveSubCommand() == this); +} +  //===----------------------------------------------------------------------===//  // Basic, shared command line option processing machinery.  // @@ -247,25 +396,29 @@ void OptionCategory::registerCategory() {  /// 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. -Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef &Value) { +Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg, +                                        StringRef &Value) {    // Reject all dashes.    if (Arg.empty())      return nullptr; +  assert(&Sub != &*AllSubCommands);    size_t EqualPos = Arg.find('=');    // If we have an equals sign, remember the value.    if (EqualPos == StringRef::npos) {      // Look up the option. -    StringMap<Option *>::const_iterator I = OptionsMap.find(Arg); -    return I != OptionsMap.end() ? I->second : nullptr; +    auto I = Sub.OptionsMap.find(Arg); +    if (I == Sub.OptionsMap.end()) +      return nullptr; + +    return I != Sub.OptionsMap.end() ? I->second : nullptr;    }    // If the argument before the = is a valid option name, we match.  If not,    // return Arg unmolested. -  StringMap<Option *>::const_iterator I = -      OptionsMap.find(Arg.substr(0, EqualPos)); -  if (I == OptionsMap.end()) +  auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos)); +  if (I == Sub.OptionsMap.end())      return nullptr;    Value = Arg.substr(EqualPos + 1); @@ -273,6 +426,21 @@ Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef &Value) {    return I->second;  } +SubCommand *CommandLineParser::LookupSubCommand(const char *Name) { +  if (Name == nullptr) +    return &*TopLevelSubCommand; +  for (auto S : RegisteredSubCommands) { +    if (S == &*AllSubCommands) +      continue; +    if (S->getName() == nullptr) +      continue; + +    if (StringRef(S->getName()) == StringRef(Name)) +      return S; +  } +  return &*TopLevelSubCommand; +} +  /// LookupNearestOption - Lookup the closest match to 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 @@ -515,8 +683,6 @@ static bool isWhitespace(char C) { return strchr(" \t\n\r\f\v", C); }  static bool isQuote(char C) { return C == '\"' || C == '\''; } -static bool isGNUSpecial(char C) { return strchr("\\\"\' ", C); } -  void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver,                                  SmallVectorImpl<const char *> &NewArgv,                                  bool MarkEOLs) { @@ -534,9 +700,8 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver,          break;      } -    // Backslashes can escape backslashes, spaces, and other quotes.  Otherwise -    // they are literal.  This makes it much easier to read Windows file paths. -    if (I + 1 < E && Src[I] == '\\' && isGNUSpecial(Src[I + 1])) { +    // Backslash escapes the next character. +    if (I + 1 < E && Src[I] == '\\') {        ++I; // Skip the escape.        Token.push_back(Src[I]);        continue; @@ -546,8 +711,8 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver,      if (isQuote(Src[I])) {        char Quote = Src[I++];        while (I != E && Src[I] != Quote) { -        // Backslashes are literal, unless they escape a special character. -        if (Src[I] == '\\' && I + 1 != E && isGNUSpecial(Src[I + 1])) +        // Backslash escapes the next character. +        if (Src[I] == '\\' && I + 1 != E)            ++I;          Token.push_back(Src[I]);          ++I; @@ -787,9 +952,28 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,    assert(envVar && "Environment variable name missing");    // Get the environment variable they want us to parse options out of. +#ifdef _WIN32 +  std::wstring wenvVar; +  if (!llvm::ConvertUTF8toWide(envVar, wenvVar)) { +    assert(false && +           "Unicode conversion of environment variable name failed"); +    return; +  } +  const wchar_t *wenvValue = _wgetenv(wenvVar.c_str()); +  if (!wenvValue) +    return; +  std::string envValueBuffer; +  if (!llvm::convertWideToUTF8(wenvValue, envValueBuffer)) { +    assert(false && +           "Unicode conversion of environment variable value failed"); +    return; +  } +  const char *envValue = envValueBuffer.c_str(); +#else    const char *envValue = getenv(envVar);    if (!envValue)      return; +#endif    // Get program's "name", which we wouldn't know without the caller    // telling us. @@ -805,14 +989,25 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,    ParseCommandLineOptions(newArgc, &newArgv[0], Overview);  } -void cl::ParseCommandLineOptions(int argc, const char *const *argv, -                                 const char *Overview) { -  GlobalParser->ParseCommandLineOptions(argc, argv, Overview); +bool cl::ParseCommandLineOptions(int argc, const char *const *argv, +                                 const char *Overview, bool IgnoreErrors) { +  return GlobalParser->ParseCommandLineOptions(argc, argv, Overview, +                                               IgnoreErrors);  } -void CommandLineParser::ParseCommandLineOptions(int argc, +void CommandLineParser::ResetAllOptionOccurrences() { +  // So that we can parse different command lines multiple times in succession +  // we reset all option values to look like they have never been seen before. +  for (auto SC : RegisteredSubCommands) { +    for (auto &O : SC->OptionsMap) +      O.second->reset(); +  } +} + +bool CommandLineParser::ParseCommandLineOptions(int argc,                                                  const char *const *argv, -                                                const char *Overview) { +                                                const char *Overview, +                                                bool IgnoreErrors) {    assert(hasOptions() && "No options specified!");    // Expand response files. @@ -835,6 +1030,23 @@ void CommandLineParser::ParseCommandLineOptions(int argc,    // Determine whether or not there are an unlimited number of positionals    bool HasUnlimitedPositionals = false; +  int FirstArg = 1; +  SubCommand *ChosenSubCommand = &*TopLevelSubCommand; +  if (argc >= 2 && argv[FirstArg][0] != '-') { +    // If the first argument specifies a valid subcommand, start processing +    // options from the second argument. +    ChosenSubCommand = LookupSubCommand(argv[FirstArg]); +    if (ChosenSubCommand != &*TopLevelSubCommand) +      FirstArg = 2; +  } +  GlobalParser->ActiveSubCommand = ChosenSubCommand; + +  assert(ChosenSubCommand); +  auto &ConsumeAfterOpt = ChosenSubCommand->ConsumeAfterOpt; +  auto &PositionalOpts = ChosenSubCommand->PositionalOpts; +  auto &SinkOpts = ChosenSubCommand->SinkOpts; +  auto &OptionsMap = ChosenSubCommand->OptionsMap; +    if (ConsumeAfterOpt) {      assert(PositionalOpts.size() > 0 &&             "Cannot specify cl::ConsumeAfter without a positional argument!"); @@ -850,23 +1062,28 @@ void CommandLineParser::ParseCommandLineOptions(int argc,        else if (ConsumeAfterOpt) {          // ConsumeAfter cannot be combined with "optional" positional options          // unless there is only one positional argument... -        if (PositionalOpts.size() > 1) -          ErrorParsing |= Opt->error( -              "error - this positional option will never be matched, " -              "because it does not Require a value, and a " -              "cl::ConsumeAfter option is active!"); +        if (PositionalOpts.size() > 1) { +          if (!IgnoreErrors) +            Opt->error("error - this positional option will never be matched, " +                       "because it does not Require a value, and a " +                       "cl::ConsumeAfter option is active!"); +          ErrorParsing = true; +        }        } else if (UnboundedFound && !Opt->hasArgStr()) {          // This option does not "require" a value...  Make sure this option is          // not specified after an option that eats all extra arguments, or this          // one will never get any!          // -        ErrorParsing |= Opt->error("error - option can never match, because " -                                   "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(); +        if (!IgnoreErrors) { +          Opt->error("error - option can never match, because " +                     "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(); +        } +        ErrorParsing = true;        }        UnboundedFound |= EatsUnboundedNumberOfValues(Opt);      } @@ -885,7 +1102,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc,    // Loop over all of the arguments... processing them.    bool DashDashFound = false; // Have we read '--'? -  for (int i = 1; i < argc; ++i) { +  for (int i = FirstArg; i < argc; ++i) {      Option *Handler = nullptr;      Option *NearestHandler = nullptr;      std::string NearestHandlerString; @@ -932,7 +1149,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc,        while (!ArgName.empty() && ArgName[0] == '-')          ArgName = ArgName.substr(1); -      Handler = LookupOption(ArgName, Value); +      Handler = LookupOption(*ChosenSubCommand, ArgName, Value);        if (!Handler || Handler->getFormattingFlag() != cl::Positional) {          ProvidePositionalOption(ActivePositionalArg, argv[i], i);          continue; // We are done! @@ -944,7 +1161,7 @@ void CommandLineParser::ParseCommandLineOptions(int argc,        while (!ArgName.empty() && ArgName[0] == '-')          ArgName = ArgName.substr(1); -      Handler = LookupOption(ArgName, Value); +      Handler = LookupOption(*ChosenSubCommand, ArgName, Value);        // Check to see if this "option" is really a prefixed or grouped argument.        if (!Handler) @@ -960,13 +1177,15 @@ void CommandLineParser::ParseCommandLineOptions(int argc,      if (!Handler) {        if (SinkOpts.empty()) { -        errs() << ProgramName << ": Unknown command line argument '" << argv[i] -               << "'.  Try: '" << argv[0] << " -help'\n"; - -        if (NearestHandler) { -          // If we know a near match, report it as well. -          errs() << ProgramName << ": Did you mean '-" << NearestHandlerString -                 << "'?\n"; +        if (!IgnoreErrors) { +          errs() << ProgramName << ": Unknown command line argument '" +                 << argv[i] << "'.  Try: '" << argv[0] << " -help'\n"; + +          if (NearestHandler) { +            // If we know a near match, report it as well. +            errs() << ProgramName << ": Did you mean '-" << NearestHandlerString +                   << "'?\n"; +          }          }          ErrorParsing = true; @@ -989,17 +1208,21 @@ void CommandLineParser::ParseCommandLineOptions(int argc,    // Check and handle positional arguments now...    if (NumPositionalRequired > PositionalVals.size()) { -    errs() << ProgramName -           << ": Not enough positional command line arguments specified!\n" -           << "Must specify at least " << NumPositionalRequired -           << " positional arguments: See: " << argv[0] << " -help\n"; +    if (!IgnoreErrors) { +      errs() << ProgramName +             << ": Not enough positional command line arguments specified!\n" +             << "Must specify at least " << NumPositionalRequired +             << " positional arguments: See: " << argv[0] << " -help\n"; +    }      ErrorParsing = true;    } else if (!HasUnlimitedPositionals &&               PositionalVals.size() > PositionalOpts.size()) { -    errs() << ProgramName << ": Too many positional arguments specified!\n" -           << "Can specify at most " << PositionalOpts.size() -           << " positional arguments: See: " << argv[0] << " -help\n"; +    if (!IgnoreErrors) { +      errs() << ProgramName << ": Too many positional arguments specified!\n" +             << "Can specify at most " << PositionalOpts.size() +             << " positional arguments: See: " << argv[0] << " -help\n"; +    }      ErrorParsing = true;    } else if (!ConsumeAfterOpt) { @@ -1094,8 +1317,12 @@ void CommandLineParser::ParseCommandLineOptions(int argc,    MoreHelp.clear();    // If we had an error processing our arguments, don't let the program execute -  if (ErrorParsing) -    exit(1); +  if (ErrorParsing) { +    if (!IgnoreErrors) +      exit(1); +    return false; +  } +  return true;  }  //===----------------------------------------------------------------------===// @@ -1416,7 +1643,7 @@ PRINT_OPT_DIFF(float)  PRINT_OPT_DIFF(char)  void parser<std::string>::printOptionDiff(const Option &O, StringRef V, -                                          OptionValue<std::string> D, +                                          const OptionValue<std::string> &D,                                            size_t GlobalWidth) const {    printOptionName(O, GlobalWidth);    outs() << "= " << V; @@ -1445,11 +1672,16 @@ static int OptNameCompare(const std::pair<const char *, Option *> *LHS,    return strcmp(LHS->first, RHS->first);  } +static int SubNameCompare(const std::pair<const char *, SubCommand *> *LHS, +                          const std::pair<const char *, SubCommand *> *RHS) { +  return strcmp(LHS->first, RHS->first); +} +  // Copy Options into a vector so we can sort them as we like.  static void sortOpts(StringMap<Option *> &OptMap,                       SmallVectorImpl<std::pair<const char *, Option *>> &Opts,                       bool ShowHidden) { -  SmallPtrSet<Option *, 128> OptionSet; // Duplicate option detection. +  SmallPtrSet<Option *, 32> OptionSet; // Duplicate option detection.    for (StringMap<Option *>::iterator I = OptMap.begin(), E = OptMap.end();         I != E; ++I) { @@ -1473,6 +1705,17 @@ static void sortOpts(StringMap<Option *> &OptMap,    array_pod_sort(Opts.begin(), Opts.end(), OptNameCompare);  } +static void +sortSubCommands(const SmallPtrSetImpl<SubCommand *> &SubMap, +                SmallVectorImpl<std::pair<const char *, SubCommand *>> &Subs) { +  for (const auto &S : SubMap) { +    if (S->getName() == nullptr) +      continue; +    Subs.push_back(std::make_pair(S->getName(), S)); +  } +  array_pod_sort(Subs.begin(), Subs.end(), SubNameCompare); +} +  namespace {  class HelpPrinter { @@ -1480,12 +1723,25 @@ protected:    const bool ShowHidden;    typedef SmallVector<std::pair<const char *, Option *>, 128>        StrOptionPairVector; +  typedef SmallVector<std::pair<const char *, SubCommand *>, 128> +      StrSubCommandPairVector;    // Print the options. Opts is assumed to be alphabetically sorted.    virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) {      for (size_t i = 0, e = Opts.size(); i != e; ++i)        Opts[i].second->printOptionInfo(MaxArgLen);    } +  void printSubCommands(StrSubCommandPairVector &Subs, size_t MaxSubLen) { +    for (const auto &S : Subs) { +      outs() << "  " << S.first; +      if (S.second->getDescription()) { +        outs().indent(MaxSubLen - strlen(S.first)); +        outs() << " - " << S.second->getDescription(); +      } +      outs() << "\n"; +    } +  } +  public:    explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {}    virtual ~HelpPrinter() {} @@ -1495,23 +1751,56 @@ public:      if (!Value)        return; +    SubCommand *Sub = GlobalParser->getActiveSubCommand(); +    auto &OptionsMap = Sub->OptionsMap; +    auto &PositionalOpts = Sub->PositionalOpts; +    auto &ConsumeAfterOpt = Sub->ConsumeAfterOpt; +      StrOptionPairVector Opts; -    sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden); +    sortOpts(OptionsMap, Opts, ShowHidden); + +    StrSubCommandPairVector Subs; +    sortSubCommands(GlobalParser->RegisteredSubCommands, Subs);      if (GlobalParser->ProgramOverview)        outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n"; -    outs() << "USAGE: " << GlobalParser->ProgramName << " [options]"; +    if (Sub == &*TopLevelSubCommand) +      outs() << "USAGE: " << GlobalParser->ProgramName +             << " [subcommand] [options]"; +    else { +      if (Sub->getDescription() != nullptr) { +        outs() << "SUBCOMMAND '" << Sub->getName() +               << "': " << Sub->getDescription() << "\n\n"; +      } +      outs() << "USAGE: " << GlobalParser->ProgramName << " " << Sub->getName() +             << " [options]"; +    } -    for (auto Opt : GlobalParser->PositionalOpts) { +    for (auto Opt : PositionalOpts) {        if (Opt->hasArgStr())          outs() << " --" << Opt->ArgStr;        outs() << " " << Opt->HelpStr;      }      // Print the consume after option info if it exists... -    if (GlobalParser->ConsumeAfterOpt) -      outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr; +    if (ConsumeAfterOpt) +      outs() << " " << ConsumeAfterOpt->HelpStr; + +    if (Sub == &*TopLevelSubCommand && Subs.size() > 2) { +      // Compute the maximum subcommand length... +      size_t MaxSubLen = 0; +      for (size_t i = 0, e = Subs.size(); i != e; ++i) +        MaxSubLen = std::max(MaxSubLen, strlen(Subs[i].first)); + +      outs() << "\n\n"; +      outs() << "SUBCOMMANDS:\n\n"; +      printSubCommands(Subs, MaxSubLen); +      outs() << "\n"; +      outs() << "  Type \"" << GlobalParser->ProgramName +             << " <subcommand> -help\" to get more help on a specific " +                "subcommand"; +    }      outs() << "\n\n"; @@ -1589,7 +1878,8 @@ protected:               E = SortedCategories.end();           Category != E; ++Category) {        // Hide empty categories for -help, but show for -help-hidden. -      bool IsEmptyCategory = CategorizedOptions[*Category].size() == 0; +      const auto &CategoryOptions = CategorizedOptions[*Category]; +      bool IsEmptyCategory = CategoryOptions.empty();        if (!ShowHidden && IsEmptyCategory)          continue; @@ -1610,11 +1900,8 @@ protected:          continue;        }        // Loop over the options in the category and print. -      for (std::vector<Option *>::const_iterator -               Opt = CategorizedOptions[*Category].begin(), -               E = CategorizedOptions[*Category].end(); -           Opt != E; ++Opt) -        (*Opt)->printOptionInfo(MaxArgLen); +      for (const Option *Opt : CategoryOptions) +        Opt->printOptionInfo(MaxArgLen);      }    }  }; @@ -1662,12 +1949,13 @@ static cl::opt<HelpPrinter, true, parser<bool>> HLOp(      "help-list",      cl::desc("Display list of available options (-help-list-hidden for more)"),      cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed, -    cl::cat(GenericCategory)); +    cl::cat(GenericCategory), cl::sub(*AllSubCommands));  static cl::opt<HelpPrinter, true, parser<bool>>      HLHOp("help-list-hidden", cl::desc("Display list of all available options"),            cl::location(UncategorizedHiddenPrinter), cl::Hidden, -          cl::ValueDisallowed, cl::cat(GenericCategory)); +          cl::ValueDisallowed, cl::cat(GenericCategory), +          cl::sub(*AllSubCommands));  // Define uncategorized/categorized help printers. These printers change their  // behaviour at runtime depending on whether one or more Option categories have @@ -1675,22 +1963,23 @@ static cl::opt<HelpPrinter, true, parser<bool>>  static cl::opt<HelpPrinterWrapper, true, parser<bool>>      HOp("help", cl::desc("Display available options (-help-hidden for more)"),          cl::location(WrappedNormalPrinter), cl::ValueDisallowed, -        cl::cat(GenericCategory)); +        cl::cat(GenericCategory), cl::sub(*AllSubCommands));  static cl::opt<HelpPrinterWrapper, true, parser<bool>>      HHOp("help-hidden", cl::desc("Display all available options"),           cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed, -         cl::cat(GenericCategory)); +         cl::cat(GenericCategory), cl::sub(*AllSubCommands));  static cl::opt<bool> PrintOptions(      "print-options",      cl::desc("Print non-default options after command line parsing"), -    cl::Hidden, cl::init(false), cl::cat(GenericCategory)); +    cl::Hidden, cl::init(false), cl::cat(GenericCategory), +    cl::sub(*AllSubCommands));  static cl::opt<bool> PrintAllOptions(      "print-all-options",      cl::desc("Print all option values after command line parsing"), cl::Hidden, -    cl::init(false), cl::cat(GenericCategory)); +    cl::init(false), cl::cat(GenericCategory), cl::sub(*AllSubCommands));  void HelpPrinterWrapper::operator=(bool Value) {    if (!Value) @@ -1717,7 +2006,7 @@ void CommandLineParser::printOptionValues() {      return;    SmallVector<std::pair<const char *, Option *>, 128> Opts; -  sortOpts(OptionsMap, Opts, /*ShowHidden*/ true); +  sortOpts(ActiveSubCommand->OptionsMap, Opts, /*ShowHidden*/ true);    // Compute the maximum argument length...    size_t MaxArgLen = 0; @@ -1737,8 +2026,12 @@ class VersionPrinter {  public:    void print() {      raw_ostream &OS = outs(); -    OS << "LLVM (http://llvm.org/):\n" -       << "  " << PACKAGE_NAME << " version " << PACKAGE_VERSION; +#ifdef PACKAGE_VENDOR +    OS << PACKAGE_VENDOR << " "; +#else +    OS << "LLVM (http://llvm.org/):\n  "; +#endif +    OS << PACKAGE_NAME << " version " << PACKAGE_VERSION;  #ifdef LLVM_VERSION_INFO      OS << " " << LLVM_VERSION_INFO;  #endif @@ -1755,9 +2048,6 @@ public:      if (CPU == "generic")        CPU = "(unknown)";      OS << ".\n" -#if (ENABLE_TIMESTAMPS == 1) -       << "  Built " << __DATE__ << " (" << __TIME__ << ").\n" -#endif         << "  Default target: " << sys::getDefaultTargetTriple() << '\n'         << "  Host CPU: " << CPU << '\n';    } @@ -1825,22 +2115,26 @@ void cl::AddExtraVersionPrinter(void (*func)()) {    ExtraVersionPrinters->push_back(func);  } -StringMap<Option *> &cl::getRegisteredOptions() { -  return GlobalParser->OptionsMap; +StringMap<Option *> &cl::getRegisteredOptions(SubCommand &Sub) { +  auto &Subs = GlobalParser->RegisteredSubCommands; +  (void)Subs; +  assert(std::find(Subs.begin(), Subs.end(), &Sub) != Subs.end()); +  return Sub.OptionsMap;  } -void cl::HideUnrelatedOptions(cl::OptionCategory &Category) { -  for (auto &I : GlobalParser->OptionsMap) { +void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) { +  for (auto &I : Sub.OptionsMap) {      if (I.second->Category != &Category &&          I.second->Category != &GenericCategory)        I.second->setHiddenFlag(cl::ReallyHidden);    }  } -void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) { +void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, +                              SubCommand &Sub) {    auto CategoriesBegin = Categories.begin();    auto CategoriesEnd = Categories.end(); -  for (auto &I : GlobalParser->OptionsMap) { +  for (auto &I : Sub.OptionsMap) {      if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==              CategoriesEnd &&          I.second->Category != &GenericCategory) @@ -1848,7 +2142,12 @@ void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) {    }  } +void cl::ResetCommandLineParser() { GlobalParser->reset(); } +void cl::ResetAllOptionOccurrences() { +  GlobalParser->ResetAllOptionOccurrences(); +} +  void LLVMParseCommandLineOptions(int argc, const char *const *argv,                                   const char *Overview) { -  llvm::cl::ParseCommandLineOptions(argc, argv, Overview); +  llvm::cl::ParseCommandLineOptions(argc, argv, Overview, true);  } | 
