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