Home | History | Annotate | Download | only in Option
      1 //===- Option.cpp - Abstract Driver Options -------------------------------===//
      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/ADT/StringRef.h"
     11 #include "llvm/ADT/Twine.h"
     12 #include "llvm/Config/llvm-config.h"
     13 #include "llvm/Option/Arg.h"
     14 #include "llvm/Option/ArgList.h"
     15 #include "llvm/Option/Option.h"
     16 #include "llvm/Option/OptTable.h"
     17 #include "llvm/Support/Compiler.h"
     18 #include "llvm/Support/Debug.h"
     19 #include "llvm/Support/ErrorHandling.h"
     20 #include "llvm/Support/raw_ostream.h"
     21 #include <cassert>
     22 #include <cstring>
     23 
     24 using namespace llvm;
     25 using namespace llvm::opt;
     26 
     27 Option::Option(const OptTable::Info *info, const OptTable *owner)
     28   : Info(info), Owner(owner) {
     29   // Multi-level aliases are not supported. This just simplifies option
     30   // tracking, it is not an inherent limitation.
     31   assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
     32          "Multi-level aliases are not supported.");
     33 
     34   if (Info && getAliasArgs()) {
     35     assert(getAlias().isValid() && "Only alias options can have alias args.");
     36     assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");
     37     assert(getAlias().getKind() != FlagClass &&
     38            "Cannot provide alias args to a flag option.");
     39   }
     40 }
     41 
     42 void Option::print(raw_ostream &O) const {
     43   O << "<";
     44   switch (getKind()) {
     45 #define P(N) case N: O << #N; break
     46     P(GroupClass);
     47     P(InputClass);
     48     P(UnknownClass);
     49     P(FlagClass);
     50     P(JoinedClass);
     51     P(ValuesClass);
     52     P(SeparateClass);
     53     P(CommaJoinedClass);
     54     P(MultiArgClass);
     55     P(JoinedOrSeparateClass);
     56     P(JoinedAndSeparateClass);
     57     P(RemainingArgsClass);
     58     P(RemainingArgsJoinedClass);
     59 #undef P
     60   }
     61 
     62   if (Info->Prefixes) {
     63     O << " Prefixes:[";
     64     for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) {
     65       O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
     66     }
     67     O << ']';
     68   }
     69 
     70   O << " Name:\"" << getName() << '"';
     71 
     72   const Option Group = getGroup();
     73   if (Group.isValid()) {
     74     O << " Group:";
     75     Group.print(O);
     76   }
     77 
     78   const Option Alias = getAlias();
     79   if (Alias.isValid()) {
     80     O << " Alias:";
     81     Alias.print(O);
     82   }
     83 
     84   if (getKind() == MultiArgClass)
     85     O << " NumArgs:" << getNumArgs();
     86 
     87   O << ">\n";
     88 }
     89 
     90 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
     91 LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); }
     92 #endif
     93 
     94 bool Option::matches(OptSpecifier Opt) const {
     95   // Aliases are never considered in matching, look through them.
     96   const Option Alias = getAlias();
     97   if (Alias.isValid())
     98     return Alias.matches(Opt);
     99 
    100   // Check exact match.
    101   if (getID() == Opt.getID())
    102     return true;
    103 
    104   const Option Group = getGroup();
    105   if (Group.isValid())
    106     return Group.matches(Opt);
    107   return false;
    108 }
    109 
    110 Arg *Option::accept(const ArgList &Args,
    111                     unsigned &Index,
    112                     unsigned ArgSize) const {
    113   const Option &UnaliasedOption = getUnaliasedOption();
    114   StringRef Spelling;
    115   // If the option was an alias, get the spelling from the unaliased one.
    116   if (getID() == UnaliasedOption.getID()) {
    117     Spelling = StringRef(Args.getArgString(Index), ArgSize);
    118   } else {
    119     Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
    120                                   Twine(UnaliasedOption.getName()));
    121   }
    122 
    123   switch (getKind()) {
    124   case FlagClass: {
    125     if (ArgSize != strlen(Args.getArgString(Index)))
    126       return nullptr;
    127 
    128     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
    129     if (getAliasArgs()) {
    130       const char *Val = getAliasArgs();
    131       while (*Val != '\0') {
    132         A->getValues().push_back(Val);
    133 
    134         // Move past the '\0' to the next argument.
    135         Val += strlen(Val) + 1;
    136       }
    137     }
    138 
    139     if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
    140       // A Flag alias for a Joined option must provide an argument.
    141       A->getValues().push_back("");
    142 
    143     return A;
    144   }
    145   case JoinedClass: {
    146     const char *Value = Args.getArgString(Index) + ArgSize;
    147     return new Arg(UnaliasedOption, Spelling, Index++, Value);
    148   }
    149   case CommaJoinedClass: {
    150     // Always matches.
    151     const char *Str = Args.getArgString(Index) + ArgSize;
    152     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
    153 
    154     // Parse out the comma separated values.
    155     const char *Prev = Str;
    156     for (;; ++Str) {
    157       char c = *Str;
    158 
    159       if (!c || c == ',') {
    160         if (Prev != Str) {
    161           char *Value = new char[Str - Prev + 1];
    162           memcpy(Value, Prev, Str - Prev);
    163           Value[Str - Prev] = '\0';
    164           A->getValues().push_back(Value);
    165         }
    166 
    167         if (!c)
    168           break;
    169 
    170         Prev = Str + 1;
    171       }
    172     }
    173     A->setOwnsValues(true);
    174 
    175     return A;
    176   }
    177   case SeparateClass:
    178     // Matches iff this is an exact match.
    179     // FIXME: Avoid strlen.
    180     if (ArgSize != strlen(Args.getArgString(Index)))
    181       return nullptr;
    182 
    183     Index += 2;
    184     if (Index > Args.getNumInputArgStrings() ||
    185         Args.getArgString(Index - 1) == nullptr)
    186       return nullptr;
    187 
    188     return new Arg(UnaliasedOption, Spelling,
    189                    Index - 2, Args.getArgString(Index - 1));
    190   case MultiArgClass: {
    191     // Matches iff this is an exact match.
    192     // FIXME: Avoid strlen.
    193     if (ArgSize != strlen(Args.getArgString(Index)))
    194       return nullptr;
    195 
    196     Index += 1 + getNumArgs();
    197     if (Index > Args.getNumInputArgStrings())
    198       return nullptr;
    199 
    200     Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
    201                       Args.getArgString(Index - getNumArgs()));
    202     for (unsigned i = 1; i != getNumArgs(); ++i)
    203       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
    204     return A;
    205   }
    206   case JoinedOrSeparateClass: {
    207     // If this is not an exact match, it is a joined arg.
    208     // FIXME: Avoid strlen.
    209     if (ArgSize != strlen(Args.getArgString(Index))) {
    210       const char *Value = Args.getArgString(Index) + ArgSize;
    211       return new Arg(*this, Spelling, Index++, Value);
    212     }
    213 
    214     // Otherwise it must be separate.
    215     Index += 2;
    216     if (Index > Args.getNumInputArgStrings() ||
    217         Args.getArgString(Index - 1) == nullptr)
    218       return nullptr;
    219 
    220     return new Arg(UnaliasedOption, Spelling,
    221                    Index - 2, Args.getArgString(Index - 1));
    222   }
    223   case JoinedAndSeparateClass:
    224     // Always matches.
    225     Index += 2;
    226     if (Index > Args.getNumInputArgStrings() ||
    227         Args.getArgString(Index - 1) == nullptr)
    228       return nullptr;
    229 
    230     return new Arg(UnaliasedOption, Spelling, Index - 2,
    231                    Args.getArgString(Index - 2) + ArgSize,
    232                    Args.getArgString(Index - 1));
    233   case RemainingArgsClass: {
    234     // Matches iff this is an exact match.
    235     // FIXME: Avoid strlen.
    236     if (ArgSize != strlen(Args.getArgString(Index)))
    237       return nullptr;
    238     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
    239     while (Index < Args.getNumInputArgStrings() &&
    240            Args.getArgString(Index) != nullptr)
    241       A->getValues().push_back(Args.getArgString(Index++));
    242     return A;
    243   }
    244   case RemainingArgsJoinedClass: {
    245     Arg *A = new Arg(UnaliasedOption, Spelling, Index);
    246     if (ArgSize != strlen(Args.getArgString(Index))) {
    247       // An inexact match means there is a joined arg.
    248       A->getValues().push_back(Args.getArgString(Index) + ArgSize);
    249     }
    250     Index++;
    251     while (Index < Args.getNumInputArgStrings() &&
    252            Args.getArgString(Index) != nullptr)
    253       A->getValues().push_back(Args.getArgString(Index++));
    254     return A;
    255   }
    256 
    257   default:
    258     llvm_unreachable("Invalid option kind!");
    259   }
    260 }
    261