X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FCommandLine.cpp;h=c2b739fa736004ca4872efa29c99aa65c4cec9c8;hb=a54609ed935ffb5bc83fad3b9839275f96b11d3f;hp=18d3db527bec4798d0c370060bc467a0e07bf844;hpb=61e01721978af4c2979c4b9153e56e72eb6389fb;p=oota-llvm.git diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 18d3db527be..c2b739fa736 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -17,12 +17,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CommandLine.h" -#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" @@ -30,13 +31,15 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include #include #include +#include using namespace llvm; using namespace cl; +#define DEBUG_TYPE "commandline" + //===----------------------------------------------------------------------===// // Template instantiations and anchors. // @@ -58,6 +61,7 @@ TEMPLATE_INSTANTIATION(class opt); TEMPLATE_INSTANTIATION(class opt); } } // end namespace llvm::cl +// Pin the vtables to this file. void GenericOptionValue::anchor() {} void OptionValue::anchor() {} void OptionValue::anchor() {} @@ -72,13 +76,14 @@ void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} +void StringSaver::anchor() {} //===----------------------------------------------------------------------===// // Globals for name and overview of program. Program name is not a string to // avoid static ctor/dtor issues. static char ProgramName[80] = ""; -static const char *ProgramOverview = 0; +static const char *ProgramOverview = nullptr; // This collects additional help to be printed. static ManagedStatic > MoreHelp; @@ -97,16 +102,23 @@ void cl::MarkOptionsChanged() { /// RegisteredOptionList - This is the list of the command line options that /// have statically constructed themselves. -static Option *RegisteredOptionList = 0; +static Option *RegisteredOptionList = nullptr; void Option::addArgument() { - assert(NextRegistered == 0 && "argument multiply registered!"); + assert(!NextRegistered && "argument multiply registered!"); NextRegistered = RegisteredOptionList; RegisteredOptionList = this; MarkOptionsChanged(); } +void Option::removeArgument() { + assert(NextRegistered && "argument never registered"); + assert(RegisteredOptionList == this && "argument is not the last registered"); + RegisteredOptionList = NextRegistered; + MarkOptionsChanged(); +} + // This collects the different option categories that have been registered. typedef SmallPtrSet OptionCatSet; static ManagedStatic RegisteredOptionCategories; @@ -114,8 +126,13 @@ static ManagedStatic RegisteredOptionCategories; // Initialise the general option category. OptionCategory llvm::cl::GeneralCategory("General options"); -void OptionCategory::registerCategory() -{ +void OptionCategory::registerCategory() { + assert(std::count_if(RegisteredOptionCategories->begin(), + RegisteredOptionCategories->end(), + [this](const OptionCategory *Category) { + return getName() == Category->getName(); + }) == 0 && "Duplicate option categories"); + RegisteredOptionCategories->insert(this); } @@ -128,8 +145,9 @@ void OptionCategory::registerCategory() static void GetOptionInfo(SmallVectorImpl &PositionalOpts, SmallVectorImpl &SinkOpts, StringMap &OptionsMap) { + bool HadErrors = false; SmallVector OptionNames; - Option *CAOpt = 0; // The ConsumeAfter option if it exists. + Option *CAOpt = nullptr; // The ConsumeAfter option if it exists. for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) { // If this option wants to handle multiple option names, get the full set. // This handles enum options like "-O1 -O2" etc. @@ -141,8 +159,9 @@ static void GetOptionInfo(SmallVectorImpl &PositionalOpts, for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { // Add argument to the argument map! if (OptionsMap.GetOrCreateValue(OptionNames[i], O).second != O) { - errs() << ProgramName << ": CommandLine Error: Argument '" - << OptionNames[i] << "' defined more than once!\n"; + errs() << ProgramName << ": CommandLine Error: Option '" + << OptionNames[i] << "' registered more than once!\n"; + HadErrors = true; } } @@ -154,8 +173,10 @@ static void GetOptionInfo(SmallVectorImpl &PositionalOpts, else if (O->getMiscFlags() & cl::Sink) // Remember sink options SinkOpts.push_back(O); else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { - if (CAOpt) + if (CAOpt) { O->error("Cannot specify more than one option with cl::ConsumeAfter!"); + HadErrors = true; + } CAOpt = O; } } @@ -165,6 +186,12 @@ static void GetOptionInfo(SmallVectorImpl &PositionalOpts, // Make sure that they are in order of registration not backwards. std::reverse(PositionalOpts.begin(), PositionalOpts.end()); + + // Fail hard if there were errors. These are strictly unrecoverable and + // indicate serious issues such as conflicting option names or an incorrectly + // linked LLVM distribution. + if (HadErrors) + report_fatal_error("inconsistency in registered CommandLine options"); } @@ -174,7 +201,7 @@ static void GetOptionInfo(SmallVectorImpl &PositionalOpts, static Option *LookupOption(StringRef &Arg, StringRef &Value, const StringMap &OptionsMap) { // Reject all dashes. - if (Arg.empty()) return 0; + if (Arg.empty()) return nullptr; size_t EqualPos = Arg.find('='); @@ -182,14 +209,14 @@ static Option *LookupOption(StringRef &Arg, StringRef &Value, if (EqualPos == StringRef::npos) { // Look up the option. StringMap::const_iterator I = OptionsMap.find(Arg); - return I != OptionsMap.end() ? I->second : 0; + return I != OptionsMap.end() ? I->second : nullptr; } // If the argument before the = is a valid option name, we match. If not, // return Arg unmolested. StringMap::const_iterator I = OptionsMap.find(Arg.substr(0, EqualPos)); - if (I == OptionsMap.end()) return 0; + if (I == OptionsMap.end()) return nullptr; Value = Arg.substr(EqualPos+1); Arg = Arg.substr(0, EqualPos); @@ -204,7 +231,7 @@ static Option *LookupNearestOption(StringRef Arg, const StringMap &OptionsMap, std::string &NearestString) { // Reject all dashes. - if (Arg.empty()) return 0; + if (Arg.empty()) return nullptr; // Split on any equal sign. std::pair SplitArg = Arg.split('='); @@ -212,7 +239,7 @@ static Option *LookupNearestOption(StringRef Arg, StringRef &RHS = SplitArg.second; // Find the closest match. - Option *Best = 0; + Option *Best = nullptr; unsigned BestDistance = 0; for (StringMap::const_iterator it = OptionsMap.begin(), ie = OptionsMap.end(); it != ie; ++it) { @@ -242,12 +269,11 @@ static Option *LookupNearestOption(StringRef Arg, return Best; } -/// CommaSeparateAndAddOccurence - A wrapper around Handler->addOccurence() that -/// does special handling of cl::CommaSeparated options. -static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, - StringRef ArgName, - StringRef Value, bool MultiArg = false) -{ +/// CommaSeparateAndAddOccurrence - A wrapper around Handler->addOccurrence() +/// that does special handling of cl::CommaSeparated options. +static bool CommaSeparateAndAddOccurrence(Option *Handler, unsigned pos, + StringRef ArgName, StringRef Value, + bool MultiArg = false) { // Check to see if this option accepts a comma separated list of values. If // it does, we have to split up the value into multiple values. if (Handler->getMiscFlags() & CommaSeparated) { @@ -286,7 +312,7 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, // Enforce value requirements switch (Handler->getValueExpectedFlag()) { case ValueRequired: - if (Value.data() == 0) { // No value specified? + if (!Value.data()) { // No value specified? if (i+1 >= argc) return Handler->error("requires a value!"); // Steal the next argument, like for '-o filename' @@ -308,13 +334,13 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, // If this isn't a multi-arg option, just run the handler. if (NumAdditionalVals == 0) - return CommaSeparateAndAddOccurence(Handler, i, ArgName, Value); + return CommaSeparateAndAddOccurrence(Handler, i, ArgName, Value); // If it is, run the handle several times. bool MultiArg = false; if (Value.data()) { - if (CommaSeparateAndAddOccurence(Handler, i, ArgName, Value, MultiArg)) + if (CommaSeparateAndAddOccurrence(Handler, i, ArgName, Value, MultiArg)) return true; --NumAdditionalVals; MultiArg = true; @@ -325,7 +351,7 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, return Handler->error("not enough values!"); Value = argv[++i]; - if (CommaSeparateAndAddOccurence(Handler, i, ArgName, Value, MultiArg)) + if (CommaSeparateAndAddOccurrence(Handler, i, ArgName, Value, MultiArg)) return true; MultiArg = true; --NumAdditionalVals; @@ -335,7 +361,7 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) { int Dummy = i; - return ProvideOption(Handler, Handler->ArgStr, Arg, 0, 0, Dummy); + return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy); } @@ -371,7 +397,7 @@ static Option *getOptionPred(StringRef Name, size_t &Length, Length = Name.size(); return OMI->second; // Found one! } - return 0; // No option found! + return nullptr; // No option found! } /// HandlePrefixedOrGroupedOption - The specified argument string (which started @@ -381,12 +407,12 @@ static Option *getOptionPred(StringRef Name, size_t &Length, static Option *HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value, bool &ErrorParsing, const StringMap &OptionsMap) { - if (Arg.size() == 1) return 0; + if (Arg.size() == 1) return nullptr; // Do the lookup! size_t Length = 0; Option *PGOpt = getOptionPred(Arg, Length, isPrefixedOrGrouping, OptionsMap); - if (PGOpt == 0) return 0; + 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 @@ -413,7 +439,7 @@ static Option *HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value, "Option can not be cl::Grouping AND cl::ValueRequired!"); int Dummy = 0; ErrorParsing |= ProvideOption(PGOpt, OneArgName, - StringRef(), 0, 0, Dummy); + StringRef(), 0, nullptr, Dummy); // Get the next grouping option. PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap); @@ -435,39 +461,251 @@ static bool EatsUnboundedNumberOfValues(const Option *O) { O->getNumOccurrencesFlag() == cl::OneOrMore; } -/// ParseCStringVector - Break INPUT up wherever one or more -/// whitespace characters are found, and store the resulting tokens in -/// OUTPUT. The tokens stored in OUTPUT are dynamically allocated -/// using strdup(), so it is the caller's responsibility to free() -/// them later. +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 &NewArgv) { + SmallString<128> Token; + for (size_t I = 0, E = Src.size(); I != E; ++I) { + // Consume runs of whitespace. + if (Token.empty()) { + while (I != E && isWhitespace(Src[I])) + ++I; + if (I == E) 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])) { + ++I; // Skip the escape. + Token.push_back(Src[I]); + continue; + } + + // Consume a quoted string. + 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])) + ++I; + Token.push_back(Src[I]); + ++I; + } + if (I == E) break; + continue; + } + + // End the token if this is whitespace. + if (isWhitespace(Src[I])) { + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); + Token.clear(); + continue; + } + + // This is a normal character. Append it. + Token.push_back(Src[I]); + } + + // Append the last token after hitting EOF with no whitespace. + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); +} + +/// Backslashes are interpreted in a rather complicated way in the Windows-style +/// command line, because backslashes are used both to separate path and to +/// escape double quote. This method consumes runs of backslashes as well as the +/// following double quote if it's escaped. +/// +/// * If an even number of backslashes is followed by a double quote, one +/// backslash is output for every pair of backslashes, and the last double +/// quote remains unconsumed. The double quote will later be interpreted as +/// the start or end of a quoted string in the main loop outside of this +/// function. +/// +/// * If an odd number of backslashes is followed by a double quote, one +/// backslash is output for every pair of backslashes, and a double quote is +/// output for the last pair of backslash-double quote. The double quote is +/// consumed in this case. /// -static void ParseCStringVector(std::vector &OutputVector, - const char *Input) { - // Characters which will be treated as token separators: - StringRef Delims = " \v\f\t\r\n"; - - StringRef WorkStr(Input); - while (!WorkStr.empty()) { - // If the first character is a delimiter, strip them off. - if (Delims.find(WorkStr[0]) != StringRef::npos) { - size_t Pos = WorkStr.find_first_not_of(Delims); - if (Pos == StringRef::npos) Pos = WorkStr.size(); - WorkStr = WorkStr.substr(Pos); +/// * Otherwise, backslashes are interpreted literally. +static size_t parseBackslash(StringRef Src, size_t I, SmallString<128> &Token) { + size_t E = Src.size(); + int BackslashCount = 0; + // Skip the backslashes. + do { + ++I; + ++BackslashCount; + } while (I != E && Src[I] == '\\'); + + bool FollowedByDoubleQuote = (I != E && Src[I] == '"'); + if (FollowedByDoubleQuote) { + Token.append(BackslashCount / 2, '\\'); + if (BackslashCount % 2 == 0) + return I - 1; + Token.push_back('"'); + return I; + } + Token.append(BackslashCount, '\\'); + return I - 1; +} + +void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, + SmallVectorImpl &NewArgv) { + SmallString<128> Token; + + // This is a small state machine to consume characters until it reaches the + // end of the source string. + enum { INIT, UNQUOTED, QUOTED } State = INIT; + for (size_t I = 0, E = Src.size(); I != E; ++I) { + // INIT state indicates that the current input index is at the start of + // the string or between tokens. + if (State == INIT) { + if (isWhitespace(Src[I])) + continue; + if (Src[I] == '"') { + State = QUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + State = UNQUOTED; + continue; + } + Token.push_back(Src[I]); + State = UNQUOTED; continue; } - // Find position of first delimiter. - size_t Pos = WorkStr.find_first_of(Delims); - if (Pos == StringRef::npos) Pos = WorkStr.size(); + // UNQUOTED state means that it's reading a token not quoted by double + // quotes. + if (State == UNQUOTED) { + // Whitespace means the end of the token. + if (isWhitespace(Src[I])) { + NewArgv.push_back(Saver.SaveString(Token.c_str())); + Token.clear(); + State = INIT; + continue; + } + if (Src[I] == '"') { + State = QUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + continue; + } + Token.push_back(Src[I]); + continue; + } + + // QUOTED state means that it's reading a token quoted by double quotes. + if (State == QUOTED) { + if (Src[I] == '"') { + State = UNQUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + continue; + } + Token.push_back(Src[I]); + } + } + // Append the last token after hitting EOF with no whitespace. + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); +} + +static bool ExpandResponseFile(const char *FName, StringSaver &Saver, + TokenizerCallback Tokenizer, + SmallVectorImpl &NewArgv) { + std::unique_ptr MemBuf; + if (MemoryBuffer::getFile(FName, MemBuf)) + return false; + StringRef Str(MemBuf->getBufferStart(), MemBuf->getBufferSize()); + + // If we have a UTF-16 byte order mark, convert to UTF-8 for parsing. + ArrayRef BufRef(MemBuf->getBufferStart(), MemBuf->getBufferEnd()); + std::string UTF8Buf; + if (hasUTF16ByteOrderMark(BufRef)) { + if (!convertUTF16ToUTF8String(BufRef, UTF8Buf)) + return false; + Str = StringRef(UTF8Buf); + } + + // Tokenize the contents into NewArgv. + Tokenizer(Str, Saver, NewArgv); + + return true; +} - // Everything from 0 to Pos is the next word to copy. - char *NewStr = (char*)malloc(Pos+1); - memcpy(NewStr, WorkStr.data(), Pos); - NewStr[Pos] = 0; - OutputVector.push_back(NewStr); +/// \brief Expand response files on a command line recursively using the given +/// StringSaver and tokenization strategy. +bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl &Argv) { + unsigned RspFiles = 0; + bool AllExpanded = true; + + // Don't cache Argv.size() because it can change. + for (unsigned I = 0; I != Argv.size(); ) { + const char *Arg = Argv[I]; + if (Arg[0] != '@') { + ++I; + continue; + } - WorkStr = WorkStr.substr(Pos); + // If we have too many response files, leave some unexpanded. This avoids + // crashing on self-referential response files. + if (RspFiles++ > 20) + return false; + + // Replace this response file argument with the tokenization of its + // contents. Nested response files are expanded in subsequent iterations. + // FIXME: If a nested response file uses a relative path, is it relative to + // the cwd of the process or the response file? + SmallVector ExpandedArgv; + if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv)) { + // We couldn't read this file, so we leave it in the argument stream and + // move on. + AllExpanded = false; + ++I; + continue; + } + Argv.erase(Argv.begin() + I); + Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end()); } + return AllExpanded; +} + +namespace { + class StrDupSaver : public StringSaver { + std::vector Dups; + public: + ~StrDupSaver() { + for (std::vector::iterator I = Dups.begin(), E = Dups.end(); + I != E; ++I) { + char *Dup = *I; + free(Dup); + } + } + const char *SaveString(const char *Str) override { + char *Dup = strdup(Str); + Dups.push_back(Dup); + return Dup; + } + }; } /// ParseEnvironmentOptions - An alternative entry point to the @@ -488,56 +726,15 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, // Get program's "name", which we wouldn't know without the caller // telling us. - std::vector newArgv; - newArgv.push_back(strdup(progName)); + SmallVector newArgv; + StrDupSaver Saver; + newArgv.push_back(Saver.SaveString(progName)); // Parse the value of the environment variable into a "command line" // and hand it off to ParseCommandLineOptions(). - ParseCStringVector(newArgv, envValue); + TokenizeGNUCommandLine(envValue, Saver, newArgv); int newArgc = static_cast(newArgv.size()); ParseCommandLineOptions(newArgc, &newArgv[0], Overview); - - // Free all the strdup()ed strings. - for (std::vector::iterator i = newArgv.begin(), e = newArgv.end(); - i != e; ++i) - free(*i); -} - - -/// ExpandResponseFiles - Copy the contents of argv into newArgv, -/// substituting the contents of the response files for the arguments -/// of type @file. -static void ExpandResponseFiles(unsigned argc, const char*const* argv, - std::vector& newArgv) { - for (unsigned i = 1; i != argc; ++i) { - const char *arg = argv[i]; - - if (arg[0] == '@') { - sys::PathWithStatus respFile(++arg); - - // Check that the response file is not empty (mmap'ing empty - // files can be problematic). - const sys::FileStatus *FileStat = respFile.getFileStatus(); - if (FileStat && FileStat->getSize() != 0) { - - // If we could open the file, parse its contents, otherwise - // pass the @file option verbatim. - - // TODO: we should also support recursive loading of response files, - // since this is how gcc behaves. (From their man page: "The file may - // itself contain additional @file options; any such options will be - // processed recursively.") - - // Mmap the response file into memory. - OwningPtr respFilePtr; - if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) { - ParseCStringVector(newArgv, respFilePtr->getBufferStart()); - continue; - } - } - } - newArgv.push_back(strdup(arg)); - } } void cl::ParseCommandLineOptions(int argc, const char * const *argv, @@ -552,14 +749,16 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, "No options specified!"); // Expand response files. - std::vector newArgv; - newArgv.push_back(strdup(argv[0])); - ExpandResponseFiles(argc, argv, newArgv); + SmallVector newArgv; + for (int i = 0; i != argc; ++i) + newArgv.push_back(argv[i]); + StrDupSaver Saver; + ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv); argv = &newArgv[0]; argc = static_cast(newArgv.size()); // Copy the program name into ProgName, making sure not to overflow it. - std::string ProgName = sys::path::filename(argv[0]); + StringRef ProgName = sys::path::filename(argv[0]); size_t Len = std::min(ProgName.size(), size_t(79)); memcpy(ProgramName, ProgName.data(), Len); ProgramName[Len] = '\0'; @@ -573,7 +772,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, // Determine whether or not there are an unlimited number of positionals bool HasUnlimitedPositionals = false; - Option *ConsumeAfterOpt = 0; + Option *ConsumeAfterOpt = nullptr; if (!PositionalOpts.empty()) { if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) { assert(PositionalOpts.size() > 1 && @@ -583,7 +782,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, // Calculate how many positional values are _required_. bool UnboundedFound = false; - for (size_t i = ConsumeAfterOpt != 0, e = PositionalOpts.size(); + for (size_t i = ConsumeAfterOpt ? 1 : 0, e = PositionalOpts.size(); i != e; ++i) { Option *Opt = PositionalOpts[i]; if (RequiresValue(Opt)) @@ -619,13 +818,13 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, // If the program has named positional arguments, and the name has been run // across, keep track of which positional argument was named. Otherwise put // the positional args into the PositionalVals list... - Option *ActivePositionalArg = 0; + Option *ActivePositionalArg = nullptr; // Loop over all of the arguments... processing them. bool DashDashFound = false; // Have we read '--'? for (int i = 1; i < argc; ++i) { - Option *Handler = 0; - Option *NearestHandler = 0; + Option *Handler = nullptr; + Option *NearestHandler = nullptr; std::string NearestHandlerString; StringRef Value; StringRef ArgName = ""; @@ -658,8 +857,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, // All of the positional arguments have been fulfulled, give the rest to // the consume after option... if it's specified... // - if (PositionalVals.size() >= NumPositionalRequired && - ConsumeAfterOpt != 0) { + if (PositionalVals.size() >= NumPositionalRequired && ConsumeAfterOpt) { for (++i; i < argc; ++i) PositionalVals.push_back(std::make_pair(argv[i],i)); break; // Handle outside of the argument processing loop... @@ -697,18 +895,18 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, Handler = LookupOption(ArgName, Value, Opts); // Check to see if this "option" is really a prefixed or grouped argument. - if (Handler == 0) + if (!Handler) Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, Opts); // Otherwise, look for the closest available option to report to the user // in the upcoming error. - if (Handler == 0 && SinkOpts.empty()) + if (!Handler && SinkOpts.empty()) NearestHandler = LookupNearestOption(ArgName, Opts, NearestHandlerString); } - if (Handler == 0) { + if (!Handler) { if (SinkOpts.empty()) { errs() << ProgramName << ": Unknown command line argument '" << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; @@ -752,7 +950,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, << " positional arguments: See: " << argv[0] << " -help\n"; ErrorParsing = true; - } else if (ConsumeAfterOpt == 0) { + } else if (!ConsumeAfterOpt) { // Positional args have already been handled if ConsumeAfter is specified. unsigned ValNo = 0, NumVals = static_cast(PositionalVals.size()); for (size_t i = 0, e = PositionalOpts.size(); i != e; ++i) { @@ -848,12 +1046,6 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, PositionalOpts.clear(); MoreHelp->clear(); - // Free the memory allocated by ExpandResponseFiles. - // Free all the strdup()ed strings. - for (std::vector::iterator i = newArgv.begin(), e = newArgv.end(); - i != e; ++i) - free(*i); - // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) exit(1); } @@ -863,7 +1055,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, // bool Option::error(const Twine &Message, StringRef ArgName) { - if (ArgName.data() == 0) ArgName = ArgStr; + if (!ArgName.data()) ArgName = ArgStr; if (ArgName.empty()) errs() << HelpStr; // Be nice for positional arguments else @@ -913,11 +1105,20 @@ size_t alias::getOptionWidth() const { return std::strlen(ArgStr)+6; } +static void printHelpStr(StringRef HelpStr, size_t Indent, + size_t FirstLineIndentedBy) { + std::pair Split = HelpStr.split('\n'); + outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; + while (!Split.second.empty()) { + Split = Split.second.split('\n'); + outs().indent(Indent) << Split.first << "\n"; + } +} + // Print out the option for the alias. void alias::printOptionInfo(size_t GlobalWidth) const { - size_t L = std::strlen(ArgStr); outs() << " -" << ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n"; + printHelpStr(HelpStr, GlobalWidth, std::strlen(ArgStr) + 6); } //===----------------------------------------------------------------------===// @@ -946,7 +1147,7 @@ void basic_parser_impl::printOptionInfo(const Option &O, if (const char *ValName = getValueName()) outs() << "=<" << getValueStr(O, ValName) << '>'; - outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); } void basic_parser_impl::printOptionName(const Option &O, @@ -1087,9 +1288,8 @@ 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()) { - size_t L = std::strlen(O.ArgStr); outs() << " -" << O.ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, std::strlen(O.ArgStr) + 6); for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { size_t NumSpaces = GlobalWidth-strlen(getOption(i))-8; @@ -1100,9 +1300,9 @@ void generic_parser_base::printOptionInfo(const Option &O, if (O.HelpStr[0]) outs() << " " << O.HelpStr << '\n'; for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - size_t L = std::strlen(getOption(i)); - outs() << " -" << getOption(i); - outs().indent(GlobalWidth-L-8) << " - " << getDescription(i) << '\n'; + const char *Option = getOption(i); + outs() << " -" << Option; + printHelpStr(getDescription(i), GlobalWidth, std::strlen(Option) + 8); } } } @@ -1266,12 +1466,12 @@ public: outs() << "USAGE: " << ProgramName << " [options]"; // Print out the positional options. - Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists... + Option *CAOpt = nullptr; // The cl::ConsumeAfter option, if it exists... if (!PositionalOpts.empty() && PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter) CAOpt = PositionalOpts[0]; - for (size_t i = CAOpt != 0, e = PositionalOpts.size(); i != e; ++i) { + for (size_t i = CAOpt != nullptr, e = PositionalOpts.size(); i != e; ++i) { if (PositionalOpts[i]->ArgStr[0]) outs() << " --" << PositionalOpts[i]->ArgStr; outs() << " " << PositionalOpts[i]->HelpStr; @@ -1298,7 +1498,7 @@ public: MoreHelp->clear(); // Halt the program since help information was printed - exit(1); + exit(0); } }; @@ -1310,25 +1510,24 @@ public: // It shall return true if A's name should be lexographically // ordered before B's name. It returns false otherwise. static bool OptionCategoryCompare(OptionCategory *A, OptionCategory *B) { - int Length = strcmp(A->getName(), B->getName()); - assert(Length != 0 && "Duplicate option categories"); - return Length < 0; + return strcmp(A->getName(), B->getName()) < 0; } // Make sure we inherit our base class's operator=() using HelpPrinter::operator= ; protected: - virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) override { std::vector SortedCategories; std::map > CategorizedOptions; - // Collect registered option categories into vector in preperation for + // Collect registered option categories into vector in preparation for // sorting. for (OptionCatSet::const_iterator I = RegisteredOptionCategories->begin(), E = RegisteredOptionCategories->end(); - I != E; ++I) + I != E; ++I) { SortedCategories.push_back(*I); + } // Sort the different option categories alphabetically. assert(SortedCategories.size() > 0 && "No option categories registered!"); @@ -1367,7 +1566,7 @@ protected: outs() << (*Category)->getName() << ":\n"; // Check if description is set. - if ((*Category)->getDescription() != 0) + if ((*Category)->getDescription() != nullptr) outs() << (*Category)->getDescription() << "\n\n"; else outs() << "\n"; @@ -1498,9 +1697,9 @@ void cl::PrintOptionValues() { Opts[i].second->printOptionValue(MaxArgLen, PrintAllOptions); } -static void (*OverrideVersionPrinter)() = 0; +static void (*OverrideVersionPrinter)() = nullptr; -static std::vector* ExtraVersionPrinters = 0; +static std::vector* ExtraVersionPrinters = nullptr; namespace { class VersionPrinter { @@ -1510,7 +1709,7 @@ public: OS << "LLVM (http://llvm.org/):\n" << " " << PACKAGE_NAME << " version " << PACKAGE_VERSION; #ifdef LLVM_VERSION_INFO - OS << LLVM_VERSION_INFO; + OS << " " << LLVM_VERSION_INFO; #endif OS << "\n "; #ifndef __OPTIMIZE__ @@ -1533,15 +1732,15 @@ public: void operator=(bool OptionWasSpecified) { if (!OptionWasSpecified) return; - if (OverrideVersionPrinter != 0) { + if (OverrideVersionPrinter != nullptr) { (*OverrideVersionPrinter)(); - exit(1); + exit(0); } print(); // Iterate over any registered extra printers and call them to add further // information. - if (ExtraVersionPrinters != 0) { + if (ExtraVersionPrinters != nullptr) { outs() << '\n'; for (std::vector::iterator I = ExtraVersionPrinters->begin(), E = ExtraVersionPrinters->end(); @@ -1549,7 +1748,7 @@ public: (*I)(); } - exit(1); + exit(0); } }; } // End anonymous namespace @@ -1591,7 +1790,7 @@ void cl::SetVersionPrinter(void (*func)()) { } void cl::AddExtraVersionPrinter(void (*func)()) { - if (ExtraVersionPrinters == 0) + if (!ExtraVersionPrinters) ExtraVersionPrinters = new std::vector; ExtraVersionPrinters->push_back(func);