Home | History | Annotate | Download | only in Driver
      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 "clang/Driver/Option.h"
     11 #include "clang/Driver/Arg.h"
     12 #include "clang/Driver/ArgList.h"
     13 #include "llvm/ADT/Twine.h"
     14 #include "llvm/Support/ErrorHandling.h"
     15 #include "llvm/Support/raw_ostream.h"
     16 #include <algorithm>
     17 #include <cassert>
     18 using namespace clang::driver;
     19 
     20 Option::Option(const OptTable::Info *info, const OptTable *owner)
     21   : Info(info), Owner(owner) {
     22 
     23   // Multi-level aliases are not supported, and alias options cannot
     24   // have groups. This just simplifies option tracking, it is not an
     25   // inherent limitation.
     26   assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
     27          !getGroup().isValid())) &&
     28          "Multi-level aliases and aliases with groups are unsupported.");
     29 }
     30 
     31 Option::~Option() {
     32 }
     33 
     34 void Option::dump() const {
     35   llvm::errs() << "<";
     36   switch (getKind()) {
     37 #define P(N) case N: llvm::errs() << #N; break
     38     P(GroupClass);
     39     P(InputClass);
     40     P(UnknownClass);
     41     P(FlagClass);
     42     P(JoinedClass);
     43     P(SeparateClass);
     44     P(CommaJoinedClass);
     45     P(MultiArgClass);
     46     P(JoinedOrSeparateClass);
     47     P(JoinedAndSeparateClass);
     48 #undef P
     49   }
     50 
     51   llvm::errs() << " Prefixes:[";
     52   for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
     53     llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
     54   }
     55   llvm::errs() << ']';
     56 
     57   llvm::errs() << " Name:\"" << getName() << '"';
     58 
     59   const Option Group = getGroup();
     60   if (Group.isValid()) {
     61     llvm::errs() << " Group:";
     62     Group.dump();
     63   }
     64 
     65   const Option Alias = getAlias();
     66   if (Alias.isValid()) {
     67     llvm::errs() << " Alias:";
     68     Alias.dump();
     69   }
     70 
     71   if (getKind() == MultiArgClass)
     72     llvm::errs() << " NumArgs:" << getNumArgs();
     73 
     74   llvm::errs() << ">\n";
     75 }
     76 
     77 bool Option::matches(OptSpecifier Opt) const {
     78   // Aliases are never considered in matching, look through them.
     79   const Option Alias = getAlias();
     80   if (Alias.isValid())
     81     return Alias.matches(Opt);
     82 
     83   // Check exact match.
     84   if (getID() == Opt.getID())
     85     return true;
     86 
     87   const Option Group = getGroup();
     88   if (Group.isValid())
     89     return Group.matches(Opt);
     90   return false;
     91 }
     92 
     93 Arg *Option::accept(const ArgList &Args,
     94                     unsigned &Index,
     95                     unsigned ArgSize) const {
     96   const Option &UnaliasedOption = getUnaliasedOption();
     97   StringRef Spelling;
     98   // If the option was an alias, get the spelling from the unaliased one.
     99   if (getID() == UnaliasedOption.getID()) {
    100     Spelling = StringRef(Args.getArgString(Index), ArgSize);
    101   } else {
    102     Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
    103                                   Twine(UnaliasedOption.getName()));
    104   }
    105 
    106   switch (getKind()) {
    107   case FlagClass:
    108     if (ArgSize != strlen(Args.getArgString(Index)))
    109       return 0;
    110 
    111     return new Arg(UnaliasedOption, Spelling, Index++);
    112   case JoinedClass: {
    113     const char *Value = Args.getArgString(Index) + ArgSize;
    114     return new Arg(UnaliasedOption, Spelling, Index++, Value);
    115   }
    116   case CommaJoinedClass: {
    117     // Always matches.
    118     const char *Str = Args.getArgString(Index) + ArgSize;
    119     Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
    120 
    121     // Parse out the comma separated values.
    122     const char *Prev = Str;
    123     for (;; ++Str) {
    124       char c = *Str;
    125 
    126       if (!c || c == ',') {
    127         if (Prev != Str) {
    128           char *Value = new char[Str - Prev + 1];
    129           memcpy(Value, Prev, Str - Prev);
    130           Value[Str - Prev] = '\0';
    131           A->getValues().push_back(Value);
    132         }
    133 
    134         if (!c)
    135           break;
    136 
    137         Prev = Str + 1;
    138       }
    139     }
    140     A->setOwnsValues(true);
    141 
    142     return A;
    143   }
    144   case SeparateClass:
    145     // Matches iff this is an exact match.
    146     // FIXME: Avoid strlen.
    147     if (ArgSize != strlen(Args.getArgString(Index)))
    148       return 0;
    149 
    150     Index += 2;
    151     if (Index > Args.getNumInputArgStrings())
    152       return 0;
    153 
    154     return new Arg(UnaliasedOption, Spelling,
    155                    Index - 2, Args.getArgString(Index - 1));
    156   case MultiArgClass: {
    157     // Matches iff this is an exact match.
    158     // FIXME: Avoid strlen.
    159     if (ArgSize != strlen(Args.getArgString(Index)))
    160       return 0;
    161 
    162     Index += 1 + getNumArgs();
    163     if (Index > Args.getNumInputArgStrings())
    164       return 0;
    165 
    166     Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
    167                       Args.getArgString(Index - getNumArgs()));
    168     for (unsigned i = 1; i != getNumArgs(); ++i)
    169       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
    170     return A;
    171   }
    172   case JoinedOrSeparateClass: {
    173     // If this is not an exact match, it is a joined arg.
    174     // FIXME: Avoid strlen.
    175     if (ArgSize != strlen(Args.getArgString(Index))) {
    176       const char *Value = Args.getArgString(Index) + ArgSize;
    177       return new Arg(*this, Spelling, Index++, Value);
    178     }
    179 
    180     // Otherwise it must be separate.
    181     Index += 2;
    182     if (Index > Args.getNumInputArgStrings())
    183       return 0;
    184 
    185     return new Arg(UnaliasedOption, Spelling,
    186                    Index - 2, Args.getArgString(Index - 1));
    187   }
    188   case JoinedAndSeparateClass:
    189     // Always matches.
    190     Index += 2;
    191     if (Index > Args.getNumInputArgStrings())
    192       return 0;
    193 
    194     return new Arg(UnaliasedOption, Spelling, Index - 2,
    195                    Args.getArgString(Index - 2) + ArgSize,
    196                    Args.getArgString(Index - 1));
    197   default:
    198     llvm_unreachable("Invalid option kind!");
    199   }
    200 }
    201