X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FCommandLine.cpp;h=6ab03dc675d8327549a36460ec81c6c3a5276594;hb=460e75a453c256828caaf454c0bbae3eab79f440;hp=e856509d4f382a09d5a232c9e88d55e0639dc1a2;hpb=333fb04506233255f10d8095c9e2de5e5f0fdc6f;p=oota-llvm.git diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index e856509d4f3..6ab03dc675d 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -17,23 +17,23 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Path.h" #include "llvm/ADT/OwningPtr.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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#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 using namespace llvm; using namespace cl; @@ -45,6 +45,7 @@ TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); +TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); TEMPLATE_INSTANTIATION(class basic_parser); @@ -57,12 +58,15 @@ TEMPLATE_INSTANTIATION(class opt); TEMPLATE_INSTANTIATION(class opt); } } // end namespace llvm::cl +void OptionValue::anchor() {} +void OptionValue::anchor() {} void Option::anchor() {} void basic_parser_impl::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} +void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} @@ -102,6 +106,17 @@ void Option::addArgument() { MarkOptionsChanged(); } +// This collects the different option categories that have been registered. +typedef SmallPtrSet OptionCatSet; +static ManagedStatic RegisteredOptionCategories; + +// Initialise the general option category. +OptionCategory llvm::cl::GeneralCategory("General options"); + +void OptionCategory::registerCategory() +{ + RegisteredOptionCategories->insert(this); +} //===----------------------------------------------------------------------===// // Basic, shared command line option processing machinery. @@ -180,6 +195,52 @@ static Option *LookupOption(StringRef &Arg, StringRef &Value, return I->second; } +/// LookupNearestOption - Lookup the closest match to the option specified by +/// the specified option on the command line. If there is a value specified +/// (after an equal sign) return that as well. This assumes that leading dashes +/// have already been stripped. +static Option *LookupNearestOption(StringRef Arg, + const StringMap &OptionsMap, + std::string &NearestString) { + // Reject all dashes. + if (Arg.empty()) return 0; + + // Split on any equal sign. + std::pair SplitArg = Arg.split('='); + StringRef &LHS = SplitArg.first; // LHS == Arg when no '=' is present. + StringRef &RHS = SplitArg.second; + + // Find the closest match. + Option *Best = 0; + unsigned BestDistance = 0; + for (StringMap::const_iterator it = OptionsMap.begin(), + ie = OptionsMap.end(); it != ie; ++it) { + Option *O = it->second; + SmallVector OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + + bool PermitValue = O->getValueExpectedFlag() != cl::ValueDisallowed; + StringRef Flag = PermitValue ? LHS : Arg; + for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { + StringRef Name = OptionNames[i]; + unsigned Distance = StringRef(Name).edit_distance( + Flag, /*AllowReplacements=*/true, /*MaxEditDistance=*/BestDistance); + if (!Best || Distance < BestDistance) { + Best = O; + BestDistance = Distance; + if (RHS.empty() || !PermitValue) + NearestString = OptionNames[i]; + else + NearestString = std::string(OptionNames[i]) + "=" + RHS.str(); + } + } + } + + return Best; +} + /// CommaSeparateAndAddOccurence - A wrapper around Handler->addOccurence() that /// does special handling of cl::CommaSeparated options. static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, @@ -216,8 +277,8 @@ static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, /// and a null value (StringRef()). The later is accepted for arguments that /// don't allow a value (-foo) the former is rejected (-foo=). static inline bool ProvideOption(Option *Handler, StringRef ArgName, - StringRef Value, int argc, char **argv, - int &i) { + StringRef Value, int argc, + const char *const *argv, int &i) { // Is this a multi-argument option? unsigned NumAdditionalVals = Handler->getNumAdditionalVals(); @@ -242,12 +303,6 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName, break; case ValueOptional: break; - - default: - errs() << ProgramName - << ": Bad ValueMask flag! CommandLine usage error:" - << Handler->getValueExpectedFlag() << "\n"; - llvm_unreachable(0); } // If this isn't a multi-arg option, just run the handler. @@ -420,7 +475,7 @@ static void ParseCStringVector(std::vector &OutputVector, /// an environment variable (whose name is given in ENVVAR). /// void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, - const char *Overview, bool ReadResponseFiles) { + const char *Overview) { // Check args. assert(progName && "Program name not specified"); assert(envVar && "Environment variable name missing"); @@ -439,7 +494,7 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, // and hand it off to ParseCommandLineOptions(). ParseCStringVector(newArgv, envValue); int newArgc = static_cast(newArgv.size()); - ParseCommandLineOptions(newArgc, &newArgv[0], Overview, ReadResponseFiles); + ParseCommandLineOptions(newArgc, &newArgv[0], Overview); // Free all the strdup()ed strings. for (std::vector::iterator i = newArgv.begin(), e = newArgv.end(); @@ -451,44 +506,30 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, /// 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, char** argv, +static void ExpandResponseFiles(unsigned argc, const char*const* argv, std::vector& newArgv) { for (unsigned i = 1; i != argc; ++i) { - char *arg = argv[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) { - - // Mmap the response file into memory. - error_code ec; - OwningPtr - respFilePtr(MemoryBuffer::getFile(respFile.c_str(), ec)); - - // 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.") - - if (respFilePtr != 0) { - ParseCStringVector(newArgv, respFilePtr->getBufferStart()); - continue; - } + // 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(arg + 1, respFilePtr)) { + ParseCStringVector(newArgv, respFilePtr->getBufferStart()); + continue; } } newArgv.push_back(strdup(arg)); } } -void cl::ParseCommandLineOptions(int argc, char **argv, - const char *Overview, bool ReadResponseFiles) { +void cl::ParseCommandLineOptions(int argc, const char * const *argv, + const char *Overview) { // Process all registered options. SmallVector PositionalOpts; SmallVector SinkOpts; @@ -500,15 +541,13 @@ void cl::ParseCommandLineOptions(int argc, char **argv, // Expand response files. std::vector newArgv; - if (ReadResponseFiles) { - newArgv.push_back(strdup(argv[0])); - ExpandResponseFiles(argc, argv, newArgv); - argv = &newArgv[0]; - argc = static_cast(newArgv.size()); - } + newArgv.push_back(strdup(argv[0])); + ExpandResponseFiles(argc, argv, 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(argv[0]).getLast(); + std::string ProgName = sys::path::filename(argv[0]); size_t Len = std::min(ProgName.size(), size_t(79)); memcpy(ProgramName, ProgName.data(), Len); ProgramName[Len] = '\0'; @@ -574,6 +613,8 @@ void cl::ParseCommandLineOptions(int argc, char **argv, bool DashDashFound = false; // Have we read '--'? for (int i = 1; i < argc; ++i) { Option *Handler = 0; + Option *NearestHandler = 0; + std::string NearestHandlerString; StringRef Value; StringRef ArgName = ""; @@ -647,12 +688,25 @@ void cl::ParseCommandLineOptions(int argc, char **argv, if (Handler == 0) 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()) + NearestHandler = LookupNearestOption(ArgName, Opts, + NearestHandlerString); } if (Handler == 0) { if (SinkOpts.empty()) { errs() << ProgramName << ": Unknown command line argument '" << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; + + if (NearestHandler) { + // If we know a near match, report it as well. + errs() << ProgramName << ": Did you mean '-" + << NearestHandlerString << "'?\n"; + } + ErrorParsing = true; } else { for (SmallVectorImpl::iterator I = SinkOpts.begin(), @@ -783,12 +837,10 @@ void cl::ParseCommandLineOptions(int argc, char **argv, MoreHelp->clear(); // Free the memory allocated by ExpandResponseFiles. - if (ReadResponseFiles) { - // Free all the strdup()ed strings. - for (std::vector::iterator i = newArgv.begin(), e = newArgv.end(); - i != e; ++i) - free(*i); - } + // 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); @@ -826,7 +878,6 @@ bool Option::addOccurrence(unsigned pos, StringRef ArgName, case OneOrMore: case ZeroOrMore: case ConsumeAfter: break; - default: return error("bad num occurrences flag value!"); } return handleOccurrence(pos, ArgName, Value); @@ -850,15 +901,22 @@ 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); - errs() << " -" << ArgStr; - errs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n"; + outs() << " -" << ArgStr; + printHelpStr(HelpStr, GlobalWidth, std::strlen(ArgStr) + 6); } - - //===----------------------------------------------------------------------===// // Parser Implementation code... // @@ -885,10 +943,14 @@ 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, + size_t GlobalWidth) const { + outs() << " -" << O.ArgStr; + outs().indent(GlobalWidth-std::strlen(O.ArgStr)); +} // parser implementation @@ -946,6 +1008,16 @@ bool parser::parse(Option &O, StringRef ArgName, return false; } +// parser implementation +// +bool parser::parse(Option &O, StringRef ArgName, + StringRef Arg, unsigned long long &Value){ + + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for uint argument!"); + return false; +} + // parser/parser implementation // static bool parseDouble(Option &O, StringRef Arg, double &Value) { @@ -1012,9 +1084,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; @@ -1025,13 +1096,97 @@ 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); } } } +static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff + +// printGenericOptionDiff - Print the value of this option and it's default. +// +// "Generic" options have each value mapped to a name. +void generic_parser_base:: +printGenericOptionDiff(const Option &O, const GenericOptionValue &Value, + const GenericOptionValue &Default, + size_t GlobalWidth) const { + outs() << " -" << O.ArgStr; + outs().indent(GlobalWidth-std::strlen(O.ArgStr)); + + unsigned NumOpts = getNumOptions(); + for (unsigned i = 0; i != NumOpts; ++i) { + if (Value.compare(getOptionValue(i))) + continue; + + outs() << "= " << getOption(i); + size_t L = std::strlen(getOption(i)); + size_t NumSpaces = MaxOptWidth > L ? MaxOptWidth - L : 0; + outs().indent(NumSpaces) << " (default: "; + for (unsigned j = 0; j != NumOpts; ++j) { + if (Default.compare(getOptionValue(j))) + continue; + outs() << getOption(j); + break; + } + outs() << ")\n"; + return; + } + outs() << "= *unknown option value*\n"; +} + +// printOptionDiff - Specializations for printing basic value types. +// +#define PRINT_OPT_DIFF(T) \ + void parser:: \ + printOptionDiff(const Option &O, T V, OptionValue D, \ + size_t GlobalWidth) const { \ + printOptionName(O, GlobalWidth); \ + std::string Str; \ + { \ + raw_string_ostream SS(Str); \ + SS << V; \ + } \ + outs() << "= " << Str; \ + size_t NumSpaces = MaxOptWidth > Str.size() ? MaxOptWidth - Str.size() : 0;\ + outs().indent(NumSpaces) << " (default: "; \ + if (D.hasValue()) \ + outs() << D.getValue(); \ + else \ + outs() << "*no default*"; \ + outs() << ")\n"; \ + } \ + +PRINT_OPT_DIFF(bool) +PRINT_OPT_DIFF(boolOrDefault) +PRINT_OPT_DIFF(int) +PRINT_OPT_DIFF(unsigned) +PRINT_OPT_DIFF(unsigned long long) +PRINT_OPT_DIFF(double) +PRINT_OPT_DIFF(float) +PRINT_OPT_DIFF(char) + +void parser:: +printOptionDiff(const Option &O, StringRef V, OptionValue D, + size_t GlobalWidth) const { + printOptionName(O, GlobalWidth); + outs() << "= " << V; + size_t NumSpaces = MaxOptWidth > V.size() ? MaxOptWidth - V.size() : 0; + outs().indent(NumSpaces) << " (default: "; + if (D.hasValue()) + outs() << D.getValue(); + else + outs() << "*no default*"; + outs() << ")\n"; +} + +// Print a placeholder for options that don't yet support printOptionDiff(). +void basic_parser_impl:: +printOptionNoValue(const Option &O, size_t GlobalWidth) const { + printOptionName(O, GlobalWidth); + outs() << "= *cannot print option value*\n"; +} //===----------------------------------------------------------------------===// // -help and -help-hidden option implementation @@ -1040,21 +1195,55 @@ void generic_parser_base::printOptionInfo(const Option &O, static int OptNameCompare(const void *LHS, const void *RHS) { typedef std::pair pair_ty; - return strcmp(((pair_ty*)LHS)->first, ((pair_ty*)RHS)->first); + return strcmp(((const pair_ty*)LHS)->first, ((const pair_ty*)RHS)->first); +} + +// Copy Options into a vector so we can sort them as we like. +static void +sortOpts(StringMap &OptMap, + SmallVectorImpl< std::pair > &Opts, + bool ShowHidden) { + SmallPtrSet OptionSet; // Duplicate option detection. + + for (StringMap::iterator I = OptMap.begin(), E = OptMap.end(); + I != E; ++I) { + // Ignore really-hidden options. + if (I->second->getOptionHiddenFlag() == ReallyHidden) + continue; + + // Unless showhidden is set, ignore hidden flags. + if (I->second->getOptionHiddenFlag() == Hidden && !ShowHidden) + continue; + + // If we've already seen this option, don't add it to the list again. + if (!OptionSet.insert(I->second)) + continue; + + Opts.push_back(std::pair(I->getKey().data(), + I->second)); + } + + // Sort the options list alphabetically. + qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare); } namespace { class HelpPrinter { - size_t MaxArgLen; - const Option *EmptyArg; +protected: const bool ShowHidden; + typedef SmallVector,128> StrOptionPairVector; + // Print the options. Opts is assumed to be alphabetically sorted. + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + for (size_t i = 0, e = Opts.size(); i != e; ++i) + Opts[i].second->printOptionInfo(MaxArgLen); + } public: - explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) { - EmptyArg = 0; - } + explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {} + virtual ~HelpPrinter() {} + // Invoke the printer. void operator=(bool Value) { if (Value == false) return; @@ -1064,30 +1253,8 @@ public: StringMap OptMap; GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - // Copy Options into a vector so we can sort them as we like. - SmallVector, 128> Opts; - SmallPtrSet OptionSet; // Duplicate option detection. - - for (StringMap::iterator I = OptMap.begin(), E = OptMap.end(); - I != E; ++I) { - // Ignore really-hidden options. - if (I->second->getOptionHiddenFlag() == ReallyHidden) - continue; - - // Unless showhidden is set, ignore hidden flags. - if (I->second->getOptionHiddenFlag() == Hidden && !ShowHidden) - continue; - - // If we've already seen this option, don't add it to the list again. - if (!OptionSet.insert(I->second)) - continue; - - Opts.push_back(std::pair(I->getKey().data(), - I->second)); - } - - // Sort the options list alphabetically. - qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare); + StrOptionPairVector Opts; + sortOpts(OptMap, Opts, ShowHidden); if (ProgramOverview) outs() << "OVERVIEW: " << ProgramOverview << "\n"; @@ -1112,17 +1279,17 @@ public: outs() << "\n\n"; // Compute the maximum argument length... - MaxArgLen = 0; + size_t MaxArgLen = 0; for (size_t i = 0, e = Opts.size(); i != e; ++i) MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); outs() << "OPTIONS:\n"; - for (size_t i = 0, e = Opts.size(); i != e; ++i) - Opts[i].second->printOptionInfo(MaxArgLen); + printOptions(Opts, MaxArgLen); // Print any extra help the user has declared. for (std::vector::iterator I = MoreHelp->begin(), - E = MoreHelp->end(); I != E; ++I) + E = MoreHelp->end(); + I != E; ++I) outs() << *I; MoreHelp->clear(); @@ -1130,35 +1297,213 @@ public: exit(1); } }; + +class CategorizedHelpPrinter : public HelpPrinter { +public: + explicit CategorizedHelpPrinter(bool showHidden) : HelpPrinter(showHidden) {} + + // Helper function for printOptions(). + // 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; + } + + // Make sure we inherit our base class's operator=() + using HelpPrinter::operator= ; + +protected: + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + std::vector SortedCategories; + std::map > CategorizedOptions; + + // Collect registered option categories into vector in preperation for + // sorting. + for (OptionCatSet::const_iterator I = RegisteredOptionCategories->begin(), + E = RegisteredOptionCategories->end(); + I != E; ++I) + SortedCategories.push_back(*I); + + // Sort the different option categories alphabetically. + assert(SortedCategories.size() > 0 && "No option categories registered!"); + std::sort(SortedCategories.begin(), SortedCategories.end(), + OptionCategoryCompare); + + // Create map to empty vectors. + for (std::vector::const_iterator + I = SortedCategories.begin(), + E = SortedCategories.end(); + I != E; ++I) + CategorizedOptions[*I] = std::vector