Home | History | Annotate | Download | only in Driver
      1 //===--- OptTable.cpp - Option Table Implementation -----------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "clang/Driver/OptTable.h"
     11 #include "clang/Driver/Arg.h"
     12 #include "clang/Driver/ArgList.h"
     13 #include "clang/Driver/Option.h"
     14 #include "clang/Driver/Options.h"
     15 #include "llvm/Support/ErrorHandling.h"
     16 #include "llvm/Support/raw_ostream.h"
     17 #include <algorithm>
     18 #include <map>
     19 using namespace clang::driver;
     20 using namespace clang::driver::options;
     21 using namespace clang;
     22 
     23 // Ordering on Info. The ordering is *almost* lexicographic, with two
     24 // exceptions. First, '\0' comes at the end of the alphabet instead of
     25 // the beginning (thus options precede any other options which prefix
     26 // them). Second, for options with the same name, the less permissive
     27 // version should come first; a Flag option should precede a Joined
     28 // option, for example.
     29 
     30 static int StrCmpOptionName(const char *A, const char *B) {
     31   char a = *A, b = *B;
     32   while (a == b) {
     33     if (a == '\0')
     34       return 0;
     35 
     36     a = *++A;
     37     b = *++B;
     38   }
     39 
     40   if (a == '\0') // A is a prefix of B.
     41     return 1;
     42   if (b == '\0') // B is a prefix of A.
     43     return -1;
     44 
     45   // Otherwise lexicographic.
     46   return (a < b) ? -1 : 1;
     47 }
     48 
     49 namespace clang {
     50 namespace driver {
     51 static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
     52   if (&A == &B)
     53     return false;
     54 
     55   if (int N = StrCmpOptionName(A.Name, B.Name))
     56     return N == -1;
     57 
     58   for (const char * const *APre = A.Prefixes,
     59                   * const *BPre = B.Prefixes;
     60                           *APre != 0 && *BPre != 0; ++APre, ++BPre) {
     61     if (int N = StrCmpOptionName(*APre, *BPre))
     62       return N == -1;
     63   }
     64 
     65   // Names are the same, check that classes are in order; exactly one
     66   // should be joined, and it should succeed the other.
     67   assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
     68          "Unexpected classes for options with same name.");
     69   return B.Kind == Option::JoinedClass;
     70 }
     71 
     72 // Support lower_bound between info and an option name.
     73 static inline bool operator<(const OptTable::Info &I, const char *Name) {
     74   return StrCmpOptionName(I.Name, Name) == -1;
     75 }
     76 static inline bool operator<(const char *Name, const OptTable::Info &I) {
     77   return StrCmpOptionName(Name, I.Name) == -1;
     78 }
     79 }
     80 }
     81 
     82 //
     83 
     84 OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
     85 
     86 //
     87 
     88 OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
     89   : OptionInfos(_OptionInfos),
     90     NumOptionInfos(_NumOptionInfos),
     91     TheInputOptionID(0),
     92     TheUnknownOptionID(0),
     93     FirstSearchableIndex(0)
     94 {
     95   // Explicitly zero initialize the error to work around a bug in array
     96   // value-initialization on MinGW with gcc 4.3.5.
     97 
     98   // Find start of normal options.
     99   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
    100     unsigned Kind = getInfo(i + 1).Kind;
    101     if (Kind == Option::InputClass) {
    102       assert(!TheInputOptionID && "Cannot have multiple input options!");
    103       TheInputOptionID = getInfo(i + 1).ID;
    104     } else if (Kind == Option::UnknownClass) {
    105       assert(!TheUnknownOptionID && "Cannot have multiple unknown options!");
    106       TheUnknownOptionID = getInfo(i + 1).ID;
    107     } else if (Kind != Option::GroupClass) {
    108       FirstSearchableIndex = i;
    109       break;
    110     }
    111   }
    112   assert(FirstSearchableIndex != 0 && "No searchable options?");
    113 
    114 #ifndef NDEBUG
    115   // Check that everything after the first searchable option is a
    116   // regular option class.
    117   for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
    118     Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
    119     assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
    120             Kind != Option::GroupClass) &&
    121            "Special options should be defined first!");
    122   }
    123 
    124   // Check that options are in order.
    125   for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
    126     if (!(getInfo(i) < getInfo(i + 1))) {
    127       getOption(i).dump();
    128       getOption(i + 1).dump();
    129       llvm_unreachable("Options are not in order!");
    130     }
    131   }
    132 #endif
    133 
    134   // Build prefixes.
    135   for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
    136     if (const char *const *P = getInfo(i).Prefixes) {
    137       for (; *P != 0; ++P) {
    138         PrefixesUnion.insert(*P);
    139       }
    140     }
    141   }
    142 
    143   // Build prefix chars.
    144   for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
    145                                          E = PrefixesUnion.end(); I != E; ++I) {
    146     StringRef Prefix = I->getKey();
    147     for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
    148                                    C != CE; ++C)
    149       if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
    150             == PrefixChars.end())
    151         PrefixChars.push_back(*C);
    152   }
    153 }
    154 
    155 OptTable::~OptTable() {
    156 }
    157 
    158 const Option OptTable::getOption(OptSpecifier Opt) const {
    159   unsigned id = Opt.getID();
    160   if (id == 0)
    161     return Option(0, 0);
    162   assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
    163   return Option(&getInfo(id), this);
    164 }
    165 
    166 static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
    167   if (Arg == "-")
    168     return true;
    169   for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
    170                                          E = Prefixes.end(); I != E; ++I)
    171     if (Arg.startswith(I->getKey()))
    172       return false;
    173   return true;
    174 }
    175 
    176 /// \returns Matched size. 0 means no match.
    177 static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
    178   for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
    179     StringRef Prefix(*Pre);
    180     if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
    181       return Prefix.size() + StringRef(I->Name).size();
    182   }
    183   return 0;
    184 }
    185 
    186 Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
    187   unsigned Prev = Index;
    188   const char *Str = Args.getArgString(Index);
    189 
    190   // Anything that doesn't start with PrefixesUnion is an input, as is '-'
    191   // itself.
    192   if (isInput(PrefixesUnion, Str))
    193     return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
    194 
    195   const Info *Start = OptionInfos + FirstSearchableIndex;
    196   const Info *End = OptionInfos + getNumOptions();
    197   StringRef Name = StringRef(Str).ltrim(PrefixChars);
    198 
    199   // Search for the first next option which could be a prefix.
    200   Start = std::lower_bound(Start, End, Name.data());
    201 
    202   // Options are stored in sorted order, with '\0' at the end of the
    203   // alphabet. Since the only options which can accept a string must
    204   // prefix it, we iteratively search for the next option which could
    205   // be a prefix.
    206   //
    207   // FIXME: This is searching much more than necessary, but I am
    208   // blanking on the simplest way to make it fast. We can solve this
    209   // problem when we move to TableGen.
    210   for (; Start != End; ++Start) {
    211     unsigned ArgSize = 0;
    212     // Scan for first option which is a proper prefix.
    213     for (; Start != End; ++Start)
    214       if ((ArgSize = matchOption(Start, Str)))
    215         break;
    216     if (Start == End)
    217       break;
    218 
    219     // See if this option matches.
    220     if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
    221       return A;
    222 
    223     // Otherwise, see if this argument was missing values.
    224     if (Prev != Index)
    225       return 0;
    226   }
    227 
    228   return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
    229 }
    230 
    231 InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
    232                                   const char* const *ArgEnd,
    233                                   unsigned &MissingArgIndex,
    234                                   unsigned &MissingArgCount) const {
    235   InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
    236 
    237   // FIXME: Handle '@' args (or at least error on them).
    238 
    239   MissingArgIndex = MissingArgCount = 0;
    240   unsigned Index = 0, End = ArgEnd - ArgBegin;
    241   while (Index < End) {
    242     // Ignore empty arguments (other things may still take them as arguments).
    243     if (Args->getArgString(Index)[0] == '\0') {
    244       ++Index;
    245       continue;
    246     }
    247 
    248     unsigned Prev = Index;
    249     Arg *A = ParseOneArg(*Args, Index);
    250     assert(Index > Prev && "Parser failed to consume argument.");
    251 
    252     // Check for missing argument error.
    253     if (!A) {
    254       assert(Index >= End && "Unexpected parser error.");
    255       assert(Index - Prev - 1 && "No missing arguments!");
    256       MissingArgIndex = Prev;
    257       MissingArgCount = Index - Prev - 1;
    258       break;
    259     }
    260 
    261     Args->append(A);
    262   }
    263 
    264   return Args;
    265 }
    266 
    267 static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
    268   const Option O = Opts.getOption(Id);
    269   std::string Name = O.getPrefixedName();
    270 
    271   // Add metavar, if used.
    272   switch (O.getKind()) {
    273   case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
    274     llvm_unreachable("Invalid option with help text.");
    275 
    276   case Option::MultiArgClass:
    277     llvm_unreachable("Cannot print metavar for this kind of option.");
    278 
    279   case Option::FlagClass:
    280     break;
    281 
    282   case Option::SeparateClass: case Option::JoinedOrSeparateClass:
    283     Name += ' ';
    284     // FALLTHROUGH
    285   case Option::JoinedClass: case Option::CommaJoinedClass:
    286   case Option::JoinedAndSeparateClass:
    287     if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
    288       Name += MetaVarName;
    289     else
    290       Name += "<value>";
    291     break;
    292   }
    293 
    294   return Name;
    295 }
    296 
    297 static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
    298                                 std::vector<std::pair<std::string,
    299                                 const char*> > &OptionHelp) {
    300   OS << Title << ":\n";
    301 
    302   // Find the maximum option length.
    303   unsigned OptionFieldWidth = 0;
    304   for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
    305     // Skip titles.
    306     if (!OptionHelp[i].second)
    307       continue;
    308 
    309     // Limit the amount of padding we are willing to give up for alignment.
    310     unsigned Length = OptionHelp[i].first.size();
    311     if (Length <= 23)
    312       OptionFieldWidth = std::max(OptionFieldWidth, Length);
    313   }
    314 
    315   const unsigned InitialPad = 2;
    316   for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
    317     const std::string &Option = OptionHelp[i].first;
    318     int Pad = OptionFieldWidth - int(Option.size());
    319     OS.indent(InitialPad) << Option;
    320 
    321     // Break on long option names.
    322     if (Pad < 0) {
    323       OS << "\n";
    324       Pad = OptionFieldWidth + InitialPad;
    325     }
    326     OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
    327   }
    328 }
    329 
    330 static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
    331   unsigned GroupID = Opts.getOptionGroupID(Id);
    332 
    333   // If not in a group, return the default help group.
    334   if (!GroupID)
    335     return "OPTIONS";
    336 
    337   // Abuse the help text of the option groups to store the "help group"
    338   // name.
    339   //
    340   // FIXME: Split out option groups.
    341   if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
    342     return GroupHelp;
    343 
    344   // Otherwise keep looking.
    345   return getOptionHelpGroup(Opts, GroupID);
    346 }
    347 
    348 void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
    349                          const char *Title, unsigned short FlagsToInclude,
    350                          unsigned short FlagsToExclude) const {
    351   OS << "OVERVIEW: " << Title << "\n";
    352   OS << '\n';
    353   OS << "USAGE: " << Name << " [options] <inputs>\n";
    354   OS << '\n';
    355 
    356   // Render help text into a map of group-name to a list of (option, help)
    357   // pairs.
    358   typedef std::map<std::string,
    359                  std::vector<std::pair<std::string, const char*> > > helpmap_ty;
    360   helpmap_ty GroupedOptionHelp;
    361 
    362   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
    363     unsigned Id = i + 1;
    364 
    365     // FIXME: Split out option groups.
    366     if (getOptionKind(Id) == Option::GroupClass)
    367       continue;
    368 
    369     if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) ||
    370         getInfo(Id).Flags & FlagsToExclude)
    371       continue;
    372 
    373     if (const char *Text = getOptionHelpText(Id)) {
    374       const char *HelpGroup = getOptionHelpGroup(*this, Id);
    375       const std::string &OptName = getOptionHelpName(*this, Id);
    376       GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
    377     }
    378   }
    379 
    380   for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
    381          ie = GroupedOptionHelp.end(); it != ie; ++it) {
    382     if (it != GroupedOptionHelp .begin())
    383       OS << "\n";
    384     PrintHelpOptionList(OS, it->first, it->second);
    385   }
    386 
    387   OS.flush();
    388 }
    389