aboutsummaryrefslogtreecommitdiff
path: root/lib/Support/CommandLine.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Support/CommandLine.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
downloadsrc-e6d1592492a3a379186bfb02bd0f4eda0669c0d5.tar.gz
src-e6d1592492a3a379186bfb02bd0f4eda0669c0d5.zip
Vendor import of stripped llvm trunk r366426 (just before the release_90vendor/llvm/llvm-trunk-r366426
Notes
Notes: svn path=/vendor/llvm/dist/; revision=351278 svn path=/vendor/llvm/llvm-trunk-r366426/; revision=351279; tag=vendor/llvm/llvm-trunk-r366426
Diffstat (limited to 'lib/Support/CommandLine.cpp')
-rw-r--r--lib/Support/CommandLine.cpp445
1 files changed, 334 insertions, 111 deletions
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index f7290b54dcf3..25510fa58ff5 100644
--- a/lib/Support/CommandLine.cpp
+++ b/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);
+ }
}
}