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