#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstring>
using namespace llvm;
using namespace llvm::opt;
Option::Option(const OptTable::Info *info, const OptTable *owner)
: Info(info), Owner(owner) {
assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
"Multi-level aliases are not supported.");
if (Info && getAliasArgs()) {
assert(getAlias().isValid() && "Only alias options can have alias args.");
assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");
assert(getAlias().getKind() != FlagClass &&
"Cannot provide alias args to a flag option.");
}
}
void Option::print(raw_ostream &O) const {
O << "<";
switch (getKind()) {
#define P(N) case N: O << #N; break
P(GroupClass);
P(InputClass);
P(UnknownClass);
P(FlagClass);
P(JoinedClass);
P(ValuesClass);
P(SeparateClass);
P(CommaJoinedClass);
P(MultiArgClass);
P(JoinedOrSeparateClass);
P(JoinedAndSeparateClass);
P(RemainingArgsClass);
P(RemainingArgsJoinedClass);
#undef P
}
if (Info->Prefixes) {
O << " Prefixes:[";
for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) {
O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
}
O << ']';
}
O << " Name:\"" << getName() << '"';
const Option Group = getGroup();
if (Group.isValid()) {
O << " Group:";
Group.print(O);
}
const Option Alias = getAlias();
if (Alias.isValid()) {
O << " Alias:";
Alias.print(O);
}
if (getKind() == MultiArgClass)
O << " NumArgs:" << getNumArgs();
O << ">\n";
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); }
#endif
bool Option::matches(OptSpecifier Opt) const {
const Option Alias = getAlias();
if (Alias.isValid())
return Alias.matches(Opt);
if (getID() == Opt.getID())
return true;
const Option Group = getGroup();
if (Group.isValid())
return Group.matches(Opt);
return false;
}
std::unique_ptr<Arg> Option::acceptInternal(const ArgList &Args,
StringRef Spelling,
unsigned &Index) const {
size_t ArgSize = Spelling.size();
switch (getKind()) {
case FlagClass: {
if (ArgSize != strlen(Args.getArgString(Index)))
return nullptr;
return std::make_unique<Arg>(*this, Spelling, Index++);
}
case JoinedClass: {
const char *Value = Args.getArgString(Index) + ArgSize;
return std::make_unique<Arg>(*this, Spelling, Index++, Value);
}
case CommaJoinedClass: {
const char *Str = Args.getArgString(Index) + ArgSize;
auto A = std::make_unique<Arg>(*this, Spelling, Index++);
const char *Prev = Str;
for (;; ++Str) {
char c = *Str;
if (!c || c == ',') {
if (Prev != Str) {
char *Value = new char[Str - Prev + 1];
memcpy(Value, Prev, Str - Prev);
Value[Str - Prev] = '\0';
A->getValues().push_back(Value);
}
if (!c)
break;
Prev = Str + 1;
}
}
A->setOwnsValues(true);
return A;
}
case SeparateClass:
if (ArgSize != strlen(Args.getArgString(Index)))
return nullptr;
Index += 2;
if (Index > Args.getNumInputArgStrings() ||
Args.getArgString(Index - 1) == nullptr)
return nullptr;
return std::make_unique<Arg>(*this, Spelling, Index - 2,
Args.getArgString(Index - 1));
case MultiArgClass: {
if (ArgSize != strlen(Args.getArgString(Index)))
return nullptr;
Index += 1 + getNumArgs();
if (Index > Args.getNumInputArgStrings())
return nullptr;
auto A = std::make_unique<Arg>(*this, Spelling, Index - 1 - getNumArgs(),
Args.getArgString(Index - getNumArgs()));
for (unsigned i = 1; i != getNumArgs(); ++i)
A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
return A;
}
case JoinedOrSeparateClass: {
if (ArgSize != strlen(Args.getArgString(Index))) {
const char *Value = Args.getArgString(Index) + ArgSize;
return std::make_unique<Arg>(*this, Spelling, Index++, Value);
}
Index += 2;
if (Index > Args.getNumInputArgStrings() ||
Args.getArgString(Index - 1) == nullptr)
return nullptr;
return std::make_unique<Arg>(*this, Spelling, Index - 2,
Args.getArgString(Index - 1));
}
case JoinedAndSeparateClass:
Index += 2;
if (Index > Args.getNumInputArgStrings() ||
Args.getArgString(Index - 1) == nullptr)
return nullptr;
return std::make_unique<Arg>(*this, Spelling, Index - 2,
Args.getArgString(Index - 2) + ArgSize,
Args.getArgString(Index - 1));
case RemainingArgsClass: {
if (ArgSize != strlen(Args.getArgString(Index)))
return nullptr;
auto A = std::make_unique<Arg>(*this, Spelling, Index++);
while (Index < Args.getNumInputArgStrings() &&
Args.getArgString(Index) != nullptr)
A->getValues().push_back(Args.getArgString(Index++));
return A;
}
case RemainingArgsJoinedClass: {
auto A = std::make_unique<Arg>(*this, Spelling, Index);
if (ArgSize != strlen(Args.getArgString(Index))) {
A->getValues().push_back(Args.getArgString(Index) + ArgSize);
}
Index++;
while (Index < Args.getNumInputArgStrings() &&
Args.getArgString(Index) != nullptr)
A->getValues().push_back(Args.getArgString(Index++));
return A;
}
default:
llvm_unreachable("Invalid option kind!");
}
}
std::unique_ptr<Arg> Option::accept(const ArgList &Args, StringRef CurArg,
bool GroupedShortOption,
unsigned &Index) const {
auto A(GroupedShortOption && getKind() == FlagClass
? std::make_unique<Arg>(*this, CurArg, Index)
: acceptInternal(Args, CurArg, Index));
if (!A)
return nullptr;
const Option &UnaliasedOption = getUnaliasedOption();
if (getID() == UnaliasedOption.getID())
return A;
StringRef UnaliasedSpelling = Args.MakeArgString(
Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName()));
auto UnaliasedA =
std::make_unique<Arg>(UnaliasedOption, UnaliasedSpelling, A->getIndex());
Arg *RawA = A.get();
UnaliasedA->setAlias(std::move(A));
if (getKind() != FlagClass) {
UnaliasedA->getValues() = RawA->getValues();
UnaliasedA->setOwnsValues(RawA->getOwnsValues());
RawA->setOwnsValues(false);
return UnaliasedA;
}
if (const char *Val = getAliasArgs()) {
while (*Val != '\0') {
UnaliasedA->getValues().push_back(Val);
Val += strlen(Val) + 1;
}
}
if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
UnaliasedA->getValues().push_back("");
return UnaliasedA;
}