diff options
-rw-r--r-- | include/clang/Driver/OptTable.h | 12 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 2 | ||||
-rw-r--r-- | lib/Driver/OptTable.cpp | 75 |
3 files changed, 89 insertions, 0 deletions
diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h index faaeba69e2..ff2e108609 100644 --- a/include/clang/Driver/OptTable.h +++ b/include/clang/Driver/OptTable.h @@ -13,6 +13,10 @@ #include "clang/Driver/OptSpecifier.h" #include <cassert> +namespace llvm { + class raw_ostream; +} + namespace clang { namespace driver { namespace options { @@ -156,6 +160,14 @@ namespace options { const char **ArgEnd, unsigned &MissingArgIndex, unsigned &MissingArgCount) const; + + /// PrintHelp - Render the help text for an option table. + /// + /// \param OS - The stream to write the help text to. + /// \param Name - The name to use in the usage line. + /// \param Title - The title to use in the usage line. + void PrintHelp(llvm::raw_ostream &OS, const char *Name, + const char *Title) const; }; } } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 87357cf08a..7c21594e6f 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -312,6 +312,8 @@ static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) { return Name; } +// FIXME: Move -ccc options to real options in the .td file (or eliminate), and +// then move to using OptTable::PrintHelp. void Driver::PrintHelp(bool ShowHidden) const { llvm::raw_ostream &OS = llvm::outs(); diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index f68a1d8db7..fc89cef14a 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -255,3 +256,77 @@ InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd, return Args; } + +static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { + std::string Name = Opts.getOptionName(Id); + + // Add metavar, if used. + switch (Opts.getOptionKind(Id)) { + case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: + assert(0 && "Invalid option with help text."); + + case Option::MultiArgClass: case Option::JoinedAndSeparateClass: + assert(0 && "Cannot print metavar for this kind of option."); + + case Option::FlagClass: + break; + + case Option::SeparateClass: case Option::JoinedOrSeparateClass: + Name += ' '; + // FALLTHROUGH + case Option::JoinedClass: case Option::CommaJoinedClass: + if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) + Name += MetaVarName; + else + Name += "<value>"; + break; + } + + return Name; +} + +void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name, + const char *Title) const { + OS << "OVERVIEW: " << Title << "\n"; + OS << '\n'; + OS << "USAGE: " << Name << " [options] <inputs>\n"; + OS << '\n'; + OS << "OPTIONS:\n"; + + // Render help text into (option, help) pairs. + std::vector< std::pair<std::string, const char*> > OptionHelp; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned Id = i + 1; + if (const char *Text = getOptionHelpText(Id)) + OptionHelp.push_back(std::make_pair(getOptionHelpName(*this, Id), Text)); + } + + // Find the maximum option length. + unsigned OptionFieldWidth = 0; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + // Skip titles. + if (!OptionHelp[i].second) + continue; + + // Limit the amount of padding we are willing to give up for alignment. + unsigned Length = OptionHelp[i].first.size(); + if (Length <= 23) + OptionFieldWidth = std::max(OptionFieldWidth, Length); + } + + const unsigned InitialPad = 2; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + const std::string &Option = OptionHelp[i].first; + int Pad = OptionFieldWidth - int(Option.size()); + OS.indent(InitialPad) << Option; + + // Break on long option names. + if (Pad < 0) { + OS << "\n"; + Pad = OptionFieldWidth + InitialPad; + } + OS.indent(Pad + 1) << OptionHelp[i].second << '\n'; + } + + OS.flush(); +} |