diff options
Diffstat (limited to 'contrib/llvm/lib/Support/CommandLine.cpp')
| -rw-r--r-- | contrib/llvm/lib/Support/CommandLine.cpp | 445 | 
1 files changed, 334 insertions, 111 deletions
diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index f7290b54dcf3..25510fa58ff5 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -1,9 +1,8 @@  //===-- CommandLine.cpp - Command line parser implementation --------------===//  // -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception  //  //===----------------------------------------------------------------------===//  // @@ -55,6 +54,7 @@ template class basic_parser<bool>;  template class basic_parser<boolOrDefault>;  template class basic_parser<int>;  template class basic_parser<unsigned>; +template class basic_parser<unsigned long>;  template class basic_parser<unsigned long long>;  template class basic_parser<double>;  template class basic_parser<float>; @@ -79,6 +79,7 @@ void parser<bool>::anchor() {}  void parser<boolOrDefault>::anchor() {}  void parser<int>::anchor() {}  void parser<unsigned>::anchor() {} +void parser<unsigned long>::anchor() {}  void parser<unsigned long long>::anchor() {}  void parser<double>::anchor() {}  void parser<float>::anchor() {} @@ -87,8 +88,47 @@ void parser<char>::anchor() {}  //===----------------------------------------------------------------------===// +static StringRef ArgPrefix = "  -"; +static StringRef ArgPrefixLong = "  --"; +static StringRef ArgHelpPrefix = " - "; + +static size_t argPlusPrefixesSize(StringRef ArgName) { +  size_t Len = ArgName.size(); +  if (Len == 1) +    return Len + ArgPrefix.size() + ArgHelpPrefix.size(); +  return Len + ArgPrefixLong.size() + ArgHelpPrefix.size(); +} + +static StringRef argPrefix(StringRef ArgName) { +  if (ArgName.size() == 1) +    return ArgPrefix; +  return ArgPrefixLong; +} + +// Option predicates... +static inline bool isGrouping(const Option *O) { +  return O->getMiscFlags() & cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { +  return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || +         O->getFormattingFlag() == cl::AlwaysPrefix; +} + +  namespace { +class PrintArg { +  StringRef ArgName; +public: +  PrintArg(StringRef ArgName) : ArgName(ArgName) {} +  friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&); +}; + +raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) { +  OS << argPrefix(Arg.ArgName) << Arg.ArgName; +  return OS; +} +  class CommandLineParser {  public:    // Globals for name and overview of program.  Program name is not a string to @@ -99,6 +139,11 @@ public:    // This collects additional help to be printed.    std::vector<StringRef> MoreHelp; +  // This collects Options added with the cl::DefaultOption flag. Since they can +  // be overridden, they are not added to the appropriate SubCommands until +  // ParseCommandLineOptions actually runs. +  SmallVector<Option*, 4> DefaultOptions; +    // This collects the different option categories that have been registered.    SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; @@ -113,7 +158,8 @@ public:    void ResetAllOptionOccurrences();    bool ParseCommandLineOptions(int argc, const char *const *argv, -                               StringRef Overview, raw_ostream *Errs = nullptr); +                               StringRef Overview, raw_ostream *Errs = nullptr, +                               bool LongOptionsUseDoubleDash = false);    void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) {      if (Opt.hasArgStr()) @@ -147,6 +193,11 @@ public:    void addOption(Option *O, SubCommand *SC) {      bool HadErrors = false;      if (O->hasArgStr()) { +      // If it's a DefaultOption, check to make sure it isn't already there. +      if (O->isDefaultOption() && +          SC->OptionsMap.find(O->ArgStr) != SC->OptionsMap.end()) +        return; +        // Add argument to the argument map!        if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) {          errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr @@ -186,7 +237,12 @@ public:      }    } -  void addOption(Option *O) { +  void addOption(Option *O, bool ProcessDefaultOption = false) { +    if (!ProcessDefaultOption && O->isDefaultOption()) { +      DefaultOptions.push_back(O); +      return; +    } +      if (O->Subs.empty()) {        addOption(O, &*TopLevelSubCommand);      } else { @@ -202,8 +258,12 @@ public:        OptionNames.push_back(O->ArgStr);      SubCommand &Sub = *SC; -    for (auto Name : OptionNames) -      Sub.OptionsMap.erase(Name); +    auto End = Sub.OptionsMap.end(); +    for (auto Name : OptionNames) { +      auto I = Sub.OptionsMap.find(Name); +      if (I != End && I->getValue() == O) +        Sub.OptionsMap.erase(I); +      }      if (O->getFormattingFlag() == cl::Positional)        for (auto Opt = Sub.PositionalOpts.begin(); @@ -267,8 +327,13 @@ public:      if (O->Subs.empty())        updateArgStr(O, NewName, &*TopLevelSubCommand);      else { -      for (auto SC : O->Subs) -        updateArgStr(O, NewName, SC); +      if (O->isInAllSubCommands()) { +        for (auto SC : RegisteredSubCommands) +          updateArgStr(O, NewName, SC); +      } else { +        for (auto SC : O->Subs) +          updateArgStr(O, NewName, SC); +      }      }    } @@ -332,12 +397,21 @@ public:      AllSubCommands->reset();      registerSubCommand(&*TopLevelSubCommand);      registerSubCommand(&*AllSubCommands); + +    DefaultOptions.clear();    }  private:    SubCommand *ActiveSubCommand;    Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); +  Option *LookupLongOption(SubCommand &Sub, StringRef &Arg, StringRef &Value, +                           bool LongOptionsUseDoubleDash, bool HaveDoubleDash) { +    Option *Opt = LookupOption(Sub, Arg, Value); +    if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash && !isGrouping(Opt)) +      return nullptr; +    return Opt; +  }    SubCommand *LookupSubCommand(StringRef Name);  }; @@ -365,6 +439,26 @@ void Option::setArgStr(StringRef S) {      GlobalParser->updateArgStr(this, S);    assert((S.empty() || S[0] != '-') && "Option can't start with '-");    ArgStr = S; +  if (ArgStr.size() == 1) +    setMiscFlag(Grouping); +} + +void Option::addCategory(OptionCategory &C) { +  assert(!Categories.empty() && "Categories cannot be empty."); +  // Maintain backward compatibility by replacing the default GeneralCategory +  // if it's still set.  Otherwise, just add the new one.  The GeneralCategory +  // must be explicitly added if you want multiple categories that include it. +  if (&C != &GeneralCategory && Categories[0] == &GeneralCategory) +    Categories[0] = &C; +  else if (find(Categories, &C) == Categories.end()) +    Categories.push_back(&C); +} + +void Option::reset() { +  NumOccurrences = 0; +  setDefault(); +  if (isDefaultOption()) +    removeArgument();  }  // Initialise the general option category. @@ -374,7 +468,11 @@ void OptionCategory::registerCategory() {    GlobalParser->registerCategory(this);  } -// A special subcommand representing no subcommand +// A special subcommand representing no subcommand. It is particularly important +// that this ManagedStatic uses constant initailization and not dynamic +// initialization because it is referenced from cl::opt constructors, which run +// dynamically in an arbitrary order. +LLVM_REQUIRE_CONSTANT_INITIALIZATION  ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand;  // A special subcommand that can be used to put an option into all subcommands. @@ -599,15 +697,6 @@ static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) {    return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy);  } -// Option predicates... -static inline bool isGrouping(const Option *O) { -  return O->getFormattingFlag() == cl::Grouping; -} -static inline bool isPrefixedOrGrouping(const Option *O) { -  return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || -         O->getFormattingFlag() == cl::AlwaysPrefix; -} -  // getOptionPred - Check to see if there are any options that satisfy the  // specified predicate with names that are the prefixes in Name.  This is  // checked by progressively stripping characters off of the name, checking to @@ -617,8 +706,9 @@ static inline bool isPrefixedOrGrouping(const Option *O) {  static Option *getOptionPred(StringRef Name, size_t &Length,                               bool (*Pred)(const Option *),                               const StringMap<Option *> &OptionsMap) { -    StringMap<Option *>::const_iterator OMI = OptionsMap.find(Name); +  if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) +    OMI = OptionsMap.end();    // 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 @@ -626,6 +716,8 @@ static Option *getOptionPred(StringRef Name, size_t &Length,    while (OMI == OptionsMap.end() && Name.size() > 1) {      Name = Name.substr(0, Name.size() - 1); // Chop off the last character.      OMI = OptionsMap.find(Name); +    if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) +      OMI = OptionsMap.end();    }    if (OMI != OptionsMap.end() && Pred(OMI->second)) { @@ -652,40 +744,46 @@ HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value,    if (!PGOpt)      return nullptr; -  // If the option is a prefixed option, then the value is simply the -  // rest of the name...  so fall through to later processing, by -  // setting up the argument name flags and value fields. -  if (PGOpt->getFormattingFlag() == cl::Prefix || -      PGOpt->getFormattingFlag() == cl::AlwaysPrefix) { -    Value = Arg.substr(Length); +  do { +    StringRef MaybeValue = +        (Length < Arg.size()) ? Arg.substr(Length) : StringRef();      Arg = Arg.substr(0, Length);      assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt); -    return PGOpt; -  } -  // This must be a grouped option... handle them now.  Grouping options can't -  // have values. -  assert(isGrouping(PGOpt) && "Broken getOptionPred!"); +    // cl::Prefix options do not preserve '=' when used separately. +    // The behavior for them with grouped options should be the same. +    if (MaybeValue.empty() || PGOpt->getFormattingFlag() == cl::AlwaysPrefix || +        (PGOpt->getFormattingFlag() == cl::Prefix && MaybeValue[0] != '=')) { +      Value = MaybeValue; +      return PGOpt; +    } -  do { -    // Move current arg name out of Arg into OneArgName. -    StringRef OneArgName = Arg.substr(0, Length); -    Arg = Arg.substr(Length); - -    // Because ValueRequired is an invalid flag for grouped arguments, -    // we don't need to pass argc/argv in. -    assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired && -           "Option can not be cl::Grouping AND cl::ValueRequired!"); +    if (MaybeValue[0] == '=') { +      Value = MaybeValue.substr(1); +      return PGOpt; +    } + +    // This must be a grouped option. +    assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + +    // Grouping options inside a group can't have values. +    if (PGOpt->getValueExpectedFlag() == cl::ValueRequired) { +      ErrorParsing |= PGOpt->error("may not occur within a group!"); +      return nullptr; +    } + +    // Because the value for the option is not required, we don't need to pass +    // argc/argv in.      int Dummy = 0; -    ErrorParsing |= -        ProvideOption(PGOpt, OneArgName, StringRef(), 0, nullptr, Dummy); +    ErrorParsing |= ProvideOption(PGOpt, Arg, StringRef(), 0, nullptr, Dummy);      // Get the next grouping option. +    Arg = MaybeValue;      PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap); -  } while (PGOpt && Length != Arg.size()); +  } while (PGOpt); -  // Return the last option with Arg cut down to just the last one. -  return PGOpt; +  // We could not find a grouping option in the remainder of Arg. +  return nullptr;  }  static bool RequiresValue(const Option *O) { @@ -869,6 +967,13 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver,      // QUOTED state means that it's reading a token quoted by double quotes.      if (State == QUOTED) {        if (C == '"') { +        if (I < (E - 1) && Src[I + 1] == '"') { +          // Consecutive double-quotes inside a quoted string implies one +          // double-quote. +          Token.push_back('"'); +          I = I + 1; +          continue; +        }          State = UNQUOTED;          continue;        } @@ -992,41 +1097,84 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver,  bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,                               SmallVectorImpl<const char *> &Argv,                               bool MarkEOLs, bool RelativeNames) { -  unsigned RspFiles = 0;    bool AllExpanded = true; +  struct ResponseFileRecord { +    const char *File; +    size_t End; +  }; + +  // To detect recursive response files, we maintain a stack of files and the +  // position of the last argument in the file. This position is updated +  // dynamically as we recursively expand files. +  SmallVector<ResponseFileRecord, 3> FileStack; + +  // Push a dummy entry that represents the initial command line, removing +  // the need to check for an empty list. +  FileStack.push_back({"", Argv.size()});    // Don't cache Argv.size() because it can change.    for (unsigned I = 0; I != Argv.size();) { +    while (I == FileStack.back().End) { +      // Passing the end of a file's argument list, so we can remove it from the +      // stack. +      FileStack.pop_back(); +    } +      const char *Arg = Argv[I];      // Check if it is an EOL marker      if (Arg == nullptr) {        ++I;        continue;      } +      if (Arg[0] != '@') {        ++I;        continue;      } -    // If we have too many response files, leave some unexpanded.  This avoids -    // crashing on self-referential response files. -    if (RspFiles++ > 20) -      return false; +    const char *FName = Arg + 1; +    auto IsEquivalent = [FName](const ResponseFileRecord &RFile) { +      return sys::fs::equivalent(RFile.File, FName); +    }; + +    // Check for recursive response files. +    if (std::any_of(FileStack.begin() + 1, FileStack.end(), IsEquivalent)) { +      // This file is recursive, so we leave it in the argument stream and +      // move on. +      AllExpanded = false; +      ++I; +      continue; +    }      // Replace this response file argument with the tokenization of its      // contents.  Nested response files are expanded in subsequent iterations.      SmallVector<const char *, 0> ExpandedArgv; -    if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv, -                            MarkEOLs, RelativeNames)) { +    if (!ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs, +                            RelativeNames)) {        // We couldn't read this file, so we leave it in the argument stream and        // move on.        AllExpanded = false;        ++I;        continue;      } + +    for (ResponseFileRecord &Record : FileStack) { +      // Increase the end of all active records by the number of newly expanded +      // arguments, minus the response file itself. +      Record.End += ExpandedArgv.size() - 1; +    } + +    FileStack.push_back({FName, I + ExpandedArgv.size()});      Argv.erase(Argv.begin() + I);      Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end());    } + +  // If successful, the top of the file stack will mark the end of the Argv +  // stream. A failure here indicates a bug in the stack popping logic above. +  // Note that FileStack may have more than one element at this point because we +  // don't have a chance to pop the stack when encountering recursive files at +  // the end of the stream, so seeing that doesn't indicate a bug. +  assert(FileStack.size() > 0 && Argv.size() == FileStack.back().End);    return AllExpanded;  } @@ -1071,7 +1219,8 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,  bool cl::ParseCommandLineOptions(int argc, const char *const *argv,                                   StringRef Overview, raw_ostream *Errs, -                                 const char *EnvVar) { +                                 const char *EnvVar, +                                 bool LongOptionsUseDoubleDash) {    SmallVector<const char *, 20> NewArgv;    BumpPtrAllocator A;    StringSaver Saver(A); @@ -1091,7 +1240,7 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv,    // Parse all options.    return GlobalParser->ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview, -                                               Errs); +                                               Errs, LongOptionsUseDoubleDash);  }  void CommandLineParser::ResetAllOptionOccurrences() { @@ -1106,7 +1255,8 @@ void CommandLineParser::ResetAllOptionOccurrences() {  bool CommandLineParser::ParseCommandLineOptions(int argc,                                                  const char *const *argv,                                                  StringRef Overview, -                                                raw_ostream *Errs) { +                                                raw_ostream *Errs, +                                                bool LongOptionsUseDoubleDash) {    assert(hasOptions() && "No options specified!");    // Expand response files. @@ -1152,6 +1302,10 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,    auto &SinkOpts = ChosenSubCommand->SinkOpts;    auto &OptionsMap = ChosenSubCommand->OptionsMap; +  for (auto O: DefaultOptions) { +    addOption(O, true); +  } +    if (ConsumeAfterOpt) {      assert(PositionalOpts.size() > 0 &&             "Cannot specify cl::ConsumeAfter without a positional argument!"); @@ -1212,6 +1366,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,      std::string NearestHandlerString;      StringRef Value;      StringRef ArgName = ""; +    bool HaveDoubleDash = 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 "-" @@ -1249,26 +1404,31 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,        // option is another positional argument.  If so, treat it as an argument,        // otherwise feed it to the eating positional.        ArgName = StringRef(argv[i] + 1); -      // Eat leading dashes. -      while (!ArgName.empty() && ArgName[0] == '-') +      // Eat second dash. +      if (!ArgName.empty() && ArgName[0] == '-') { +        HaveDoubleDash = true;          ArgName = ArgName.substr(1); +      } -      Handler = LookupOption(*ChosenSubCommand, ArgName, Value); +      Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, +                                 LongOptionsUseDoubleDash, HaveDoubleDash);        if (!Handler || Handler->getFormattingFlag() != cl::Positional) {          ProvidePositionalOption(ActivePositionalArg, StringRef(argv[i]), i);          continue; // We are done!        } -      } else { // We start with a '-', must be an argument.        ArgName = StringRef(argv[i] + 1); -      // Eat leading dashes. -      while (!ArgName.empty() && ArgName[0] == '-') +      // Eat second dash. +      if (!ArgName.empty() && ArgName[0] == '-') { +        HaveDoubleDash = true;          ArgName = ArgName.substr(1); +      } -      Handler = LookupOption(*ChosenSubCommand, ArgName, Value); +      Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, +                                 LongOptionsUseDoubleDash, HaveDoubleDash);        // Check to see if this "option" is really a prefixed or grouped argument. -      if (!Handler) +      if (!Handler && !(LongOptionsUseDoubleDash && HaveDoubleDash))          Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing,                                                  OptionsMap); @@ -1282,12 +1442,12 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,      if (!Handler) {        if (SinkOpts.empty()) {          *Errs << ProgramName << ": Unknown command line argument '" << argv[i] -              << "'.  Try: '" << argv[0] << " -help'\n"; +              << "'.  Try: '" << argv[0] << " --help'\n";          if (NearestHandler) {            // If we know a near match, report it as well. -          *Errs << ProgramName << ": Did you mean '-" << NearestHandlerString -                 << "'?\n"; +          *Errs << ProgramName << ": Did you mean '" +                << PrintArg(NearestHandlerString) << "'?\n";          }          ErrorParsing = true; @@ -1321,14 +1481,14 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,               << ": Not enough positional command line arguments specified!\n"               << "Must specify at least " << NumPositionalRequired               << " positional argument" << (NumPositionalRequired > 1 ? "s" : "") -             << ": See: " << argv[0] << " -help\n"; +             << ": 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"; +          << " positional arguments: See: " << argv[0] << " --help\n";      ErrorParsing = true;    } else if (!ConsumeAfterOpt) { @@ -1441,7 +1601,7 @@ bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) {    if (ArgName.empty())      Errs << HelpStr; // Be nice for positional arguments    else -    Errs << GlobalParser->ProgramName << ": for the -" << ArgName; +    Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName);    Errs << " option: " << Message << "\n";    return true; @@ -1484,12 +1644,16 @@ static StringRef getValueStr(const Option &O, StringRef DefaultMsg) {  //  // Return the width of the option tag for printing... -size_t alias::getOptionWidth() const { return ArgStr.size() + 6; } +size_t alias::getOptionWidth() const { +  return argPlusPrefixesSize(ArgStr); +}  void Option::printHelpStr(StringRef HelpStr, size_t Indent, -                                 size_t FirstLineIndentedBy) { +                          size_t FirstLineIndentedBy) { +  assert(Indent >= FirstLineIndentedBy);    std::pair<StringRef, StringRef> Split = HelpStr.split('\n'); -  outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; +  outs().indent(Indent - FirstLineIndentedBy) +      << ArgHelpPrefix << Split.first << "\n";    while (!Split.second.empty()) {      Split = Split.second.split('\n');      outs().indent(Indent) << Split.first << "\n"; @@ -1498,8 +1662,8 @@ void Option::printHelpStr(StringRef HelpStr, size_t Indent,  // Print out the option for the alias.  void alias::printOptionInfo(size_t GlobalWidth) const { -  outs() << "  -" << ArgStr; -  printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6); +  outs() << PrintArg(ArgStr); +  printHelpStr(HelpStr, GlobalWidth, argPlusPrefixesSize(ArgStr));  }  //===----------------------------------------------------------------------===// @@ -1511,7 +1675,7 @@ void alias::printOptionInfo(size_t GlobalWidth) const {  // Return the width of the option tag for printing...  size_t basic_parser_impl::getOptionWidth(const Option &O) const { -  size_t Len = O.ArgStr.size(); +  size_t Len = argPlusPrefixesSize(O.ArgStr);    auto ValName = getValueName();    if (!ValName.empty()) {      size_t FormattingLen = 3; @@ -1520,7 +1684,7 @@ size_t basic_parser_impl::getOptionWidth(const Option &O) const {      Len += getValueStr(O, ValName).size() + FormattingLen;    } -  return Len + 6; +  return Len;  }  // printOptionInfo - Print out information about this option.  The @@ -1528,7 +1692,7 @@ size_t basic_parser_impl::getOptionWidth(const Option &O) const {  //  void basic_parser_impl::printOptionInfo(const Option &O,                                          size_t GlobalWidth) const { -  outs() << "  -" << O.ArgStr; +  outs() << PrintArg(O.ArgStr);    auto ValName = getValueName();    if (!ValName.empty()) { @@ -1544,7 +1708,7 @@ void basic_parser_impl::printOptionInfo(const Option &O,  void basic_parser_impl::printOptionName(const Option &O,                                          size_t GlobalWidth) const { -  outs() << "  -" << O.ArgStr; +  outs() << PrintArg(O.ArgStr);    outs().indent(GlobalWidth - O.ArgStr.size());  } @@ -1603,6 +1767,16 @@ bool parser<unsigned>::parse(Option &O, StringRef ArgName, StringRef Arg,    return false;  } +// parser<unsigned long> implementation +// +bool parser<unsigned long>::parse(Option &O, StringRef ArgName, StringRef Arg, +                                  unsigned long &Value) { + +  if (Arg.getAsInteger(0, Value)) +    return O.error("'" + Arg + "' value invalid for ulong argument!"); +  return false; +} +  // parser<unsigned long long> implementation  //  bool parser<unsigned long long>::parse(Option &O, StringRef ArgName, @@ -1610,7 +1784,7 @@ bool parser<unsigned long long>::parse(Option &O, StringRef ArgName,                                         unsigned long long &Value) {    if (Arg.getAsInteger(0, Value)) -    return O.error("'" + Arg + "' value invalid for uint argument!"); +    return O.error("'" + Arg + "' value invalid for ullong argument!");    return false;  } @@ -1652,12 +1826,29 @@ unsigned generic_parser_base::findOption(StringRef Name) {    return e;  } +static StringRef EqValue = "=<value>"; +static StringRef EmptyOption = "<empty>"; +static StringRef OptionPrefix = "    ="; +static size_t OptionPrefixesSize = OptionPrefix.size() + ArgHelpPrefix.size(); + +static bool shouldPrintOption(StringRef Name, StringRef Description, +                              const Option &O) { +  return O.getValueExpectedFlag() != ValueOptional || !Name.empty() || +         !Description.empty(); +} +  // Return the width of the option tag for printing...  size_t generic_parser_base::getOptionWidth(const Option &O) const {    if (O.hasArgStr()) { -    size_t Size = O.ArgStr.size() + 6; -    for (unsigned i = 0, e = getNumOptions(); i != e; ++i) -      Size = std::max(Size, getOption(i).size() + 8); +    size_t Size = +        argPlusPrefixesSize(O.ArgStr) + EqValue.size(); +    for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { +      StringRef Name = getOption(i); +      if (!shouldPrintOption(Name, getDescription(i), O)) +        continue; +      size_t NameSize = Name.empty() ? EmptyOption.size() : Name.size(); +      Size = std::max(Size, NameSize + OptionPrefixesSize); +    }      return Size;    } else {      size_t BaseSize = 0; @@ -1673,20 +1864,46 @@ size_t generic_parser_base::getOptionWidth(const Option &O) const {  void generic_parser_base::printOptionInfo(const Option &O,                                            size_t GlobalWidth) const {    if (O.hasArgStr()) { -    outs() << "  -" << O.ArgStr; -    Option::printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6); +    // When the value is optional, first print a line just describing the +    // option without values. +    if (O.getValueExpectedFlag() == ValueOptional) { +      for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { +        if (getOption(i).empty()) { +          outs() << PrintArg(O.ArgStr); +          Option::printHelpStr(O.HelpStr, GlobalWidth, +                               argPlusPrefixesSize(O.ArgStr)); +          break; +        } +      } +    } +    outs() << PrintArg(O.ArgStr) << EqValue; +    Option::printHelpStr(O.HelpStr, GlobalWidth, +                         EqValue.size() + +                             argPlusPrefixesSize(O.ArgStr));      for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { -      size_t NumSpaces = GlobalWidth - getOption(i).size() - 8; -      outs() << "    =" << getOption(i); -      outs().indent(NumSpaces) << " -   " << getDescription(i) << '\n'; +      StringRef OptionName = getOption(i); +      StringRef Description = getDescription(i); +      if (!shouldPrintOption(OptionName, Description, O)) +        continue; +      assert(GlobalWidth >= OptionName.size() + OptionPrefixesSize); +      size_t NumSpaces = GlobalWidth - OptionName.size() - OptionPrefixesSize; +      outs() << OptionPrefix << OptionName; +      if (OptionName.empty()) { +        outs() << EmptyOption; +        assert(NumSpaces >= EmptyOption.size()); +        NumSpaces -= EmptyOption.size(); +      } +      if (!Description.empty()) +        outs().indent(NumSpaces) << ArgHelpPrefix << "  " << Description; +      outs() << '\n';      }    } else {      if (!O.HelpStr.empty())        outs() << "  " << O.HelpStr << '\n';      for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { -      auto Option = getOption(i); -      outs() << "    -" << Option; +      StringRef Option = getOption(i); +      outs() << "    " << PrintArg(Option);        Option::printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8);      }    } @@ -1700,7 +1917,7 @@ static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff  void generic_parser_base::printGenericOptionDiff(      const Option &O, const GenericOptionValue &Value,      const GenericOptionValue &Default, size_t GlobalWidth) const { -  outs() << "  -" << O.ArgStr; +  outs() << "  " << PrintArg(O.ArgStr);    outs().indent(GlobalWidth - O.ArgStr.size());    unsigned NumOpts = getNumOptions(); @@ -1750,6 +1967,7 @@ PRINT_OPT_DIFF(bool)  PRINT_OPT_DIFF(boolOrDefault)  PRINT_OPT_DIFF(int)  PRINT_OPT_DIFF(unsigned) +PRINT_OPT_DIFF(unsigned long)  PRINT_OPT_DIFF(unsigned long long)  PRINT_OPT_DIFF(double)  PRINT_OPT_DIFF(float) @@ -1919,7 +2137,7 @@ public:        printSubCommands(Subs, MaxSubLen);        outs() << "\n";        outs() << "  Type \"" << GlobalParser->ProgramName -             << " <subcommand> -help\" to get more help on a specific " +             << " <subcommand> --help\" to get more help on a specific "                  "subcommand";      } @@ -1986,9 +2204,11 @@ protected:      // options within categories will also be alphabetically sorted.      for (size_t I = 0, E = Opts.size(); I != E; ++I) {        Option *Opt = Opts[I].second; -      assert(CategorizedOptions.count(Opt->Category) > 0 && -             "Option has an unregistered category"); -      CategorizedOptions[Opt->Category].push_back(Opt); +      for (auto &Cat : Opt->Categories) { +        assert(CategorizedOptions.count(Cat) > 0 && +               "Option has an unregistered category"); +        CategorizedOptions[Cat].push_back(Opt); +      }      }      // Now do printing. @@ -1996,7 +2216,7 @@ protected:               Category = SortedCategories.begin(),               E = SortedCategories.end();           Category != E; ++Category) { -      // Hide empty categories for -help, but show for -help-hidden. +      // Hide empty categories for --help, but show for --help-hidden.        const auto &CategoryOptions = CategorizedOptions[*Category];        bool IsEmptyCategory = CategoryOptions.empty();        if (!ShowHidden && IsEmptyCategory) @@ -2012,7 +2232,7 @@ protected:        else          outs() << "\n"; -      // When using -help-hidden explicitly state if the category has no +      // When using --help-hidden explicitly state if the category has no        // options associated with it.        if (IsEmptyCategory) {          outs() << "  This option category has no options.\n"; @@ -2062,11 +2282,11 @@ static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter,  static cl::OptionCategory GenericCategory("Generic Options");  // Define uncategorized help printers. -// -help-list is hidden by default because if Option categories are being used -// then -help behaves the same as -help-list. +// --help-list is hidden by default because if Option categories are being used +// then --help behaves the same as --help-list.  static cl::opt<HelpPrinter, true, parser<bool>> HLOp(      "help-list", -    cl::desc("Display list of available options (-help-list-hidden for more)"), +    cl::desc("Display list of available options (--help-list-hidden for more)"),      cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed,      cl::cat(GenericCategory), cl::sub(*AllSubCommands)); @@ -2080,10 +2300,13 @@ static cl::opt<HelpPrinter, true, parser<bool>>  // behaviour at runtime depending on whether one or more Option categories have  // been declared.  static cl::opt<HelpPrinterWrapper, true, parser<bool>> -    HOp("help", cl::desc("Display available options (-help-hidden for more)"), +    HOp("help", cl::desc("Display available options (--help-hidden for more)"),          cl::location(WrappedNormalPrinter), cl::ValueDisallowed,          cl::cat(GenericCategory), cl::sub(*AllSubCommands)); +static cl::alias HOpA("h", cl::desc("Alias for --help"), cl::aliasopt(HOp), +                      cl::DefaultOption); +  static cl::opt<HelpPrinterWrapper, true, parser<bool>>      HHOp("help-hidden", cl::desc("Display all available options"),           cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed, @@ -2108,7 +2331,7 @@ void HelpPrinterWrapper::operator=(bool Value) {    // registered then it is useful to show the categorized help instead of    // uncategorized help.    if (GlobalParser->RegisteredOptionCategories.size() > 1) { -    // unhide -help-list option so user can have uncategorized output if they +    // unhide --help-list option so user can have uncategorized output if they      // want it.      HLOp.setHiddenFlag(NotHidden); @@ -2242,21 +2465,21 @@ cl::getRegisteredSubcommands() {  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); +    for (auto &Cat : I.second->Categories) { +      if (Cat != &Category && +          Cat != &GenericCategory) +        I.second->setHiddenFlag(cl::ReallyHidden); +    }    }  }  void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories,                                SubCommand &Sub) { -  auto CategoriesBegin = Categories.begin(); -  auto CategoriesEnd = Categories.end();    for (auto &I : Sub.OptionsMap) { -    if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) == -            CategoriesEnd && -        I.second->Category != &GenericCategory) -      I.second->setHiddenFlag(cl::ReallyHidden); +    for (auto &Cat : I.second->Categories) { +      if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory) +        I.second->setHiddenFlag(cl::ReallyHidden); +    }    }  }  | 
