Support for multi-valued options in CommandLine

Makes possible to specify options that take multiple arguments (a-la
-sectalign on Darwin). See documentation for details.

llvm-svn: 62372
This commit is contained in:
Mikhail Glushenkov 2009-01-16 22:54:19 +00:00
parent 7067b4f49d
commit cbc26fdb6e
3 changed files with 72 additions and 6 deletions

View File

@ -1146,6 +1146,17 @@ specify macro options where the option name doesn't equal the enum name. For
this macro, the first argument is the enum value, the second is the flag name,
and the second is the description.</li>
<li><a name="cl::multi_val">The <b><tt>cl::multi_val</tt></b></a>
attribute specifies that this option takes has multiple values
(example: <tt>-sectalign segname sectname sectvalue</tt>). This
attribute takes one unsigned argument - the number of values for the
option. This attribute is valid only on <tt>cl::list</tt> options (and
will fail with compile error if you try to use it with other option
types). It is allowed to use all of the usual modifiers on
multi-valued options (besides <tt>cl::ValueDisallowed</tt>,
obviously).</li>
</ol>
You will get a compile time error if you try to use cl::values with a parser

View File

@ -155,6 +155,7 @@ class Option {
int NumOccurrences; // The number of times specified
int Flags; // Flags for the argument
unsigned Position; // Position of last occurrence of the option
unsigned AdditionalVals;// Greater than 0 for multi-valued option.
Option *NextRegistered; // Singly linked list of registered options.
public:
const char *ArgStr; // The argument string itself (ex: "help", "o")
@ -179,6 +180,7 @@ public:
return Flags & MiscMask;
}
inline unsigned getPosition() const { return Position; }
inline unsigned getNumAdditionalVals() const { return AdditionalVals; }
// hasArgStr - Return true if the argstr != ""
bool hasArgStr() const { return ArgStr[0] != 0; }
@ -206,11 +208,14 @@ public:
protected:
explicit Option(unsigned DefaultFlags)
: NumOccurrences(0), Flags(DefaultFlags | NormalFormatting), Position(0),
NextRegistered(0), ArgStr(""), HelpStr(""), ValueStr("") {
AdditionalVals(0), NextRegistered(0),
ArgStr(""), HelpStr(""), ValueStr("") {
assert(getNumOccurrencesFlag() != 0 &&
getOptionHiddenFlag() != 0 && "Not all default flags specified!");
}
inline void setNumAdditionalVals(unsigned n)
{ AdditionalVals = n; }
public:
// addArgument - Register this argument with the commandline system.
//
@ -231,7 +236,7 @@ public:
// addOccurrence - Wrapper around handleOccurrence that enforces Flags
//
bool addOccurrence(unsigned pos, const char *ArgName,
const std::string &Value);
const std::string &Value, bool MultiArg = false);
// Prints option name followed by message. Always returns true.
bool error(std::string Message, const char *ArgName = 0);
@ -1000,6 +1005,10 @@ public:
return Positions[optnum];
}
void setNumAdditionalVals(unsigned n) {
Option::setNumAdditionalVals(n);
}
// One option...
template<class M0t>
explicit list(const M0t &M0) : Option(ZeroOrMore | NotHidden) {
@ -1065,6 +1074,16 @@ public:
}
};
// multi_arg - Modifier to set the number of additional values.
struct multi_val {
unsigned AdditionalVals;
explicit multi_val(unsigned N) : AdditionalVals(N) {}
template <typename D, typename S, typename P>
void apply(list<D, S, P> &L) const { L.setNumAdditionalVals(AdditionalVals); }
};
//===----------------------------------------------------------------------===//
// bits_storage class

View File

@ -172,6 +172,9 @@ static Option *LookupOption(const char *&Arg, const char *&Value,
static inline bool ProvideOption(Option *Handler, const char *ArgName,
const char *Value, int argc, char **argv,
int &i) {
// Is this a multi-argument option?
unsigned NumAdditionalVals = Handler->getNumAdditionalVals();
// Enforce value requirements
switch (Handler->getValueExpectedFlag()) {
case ValueRequired:
@ -184,6 +187,10 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName,
}
break;
case ValueDisallowed:
if (NumAdditionalVals > 0)
return Handler->error(": multi-valued option specified"
" with ValueDisallowed modifier!");
if (Value)
return Handler->error(" does not allow a value! '" +
std::string(Value) + "' specified.");
@ -198,8 +205,35 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName,
break;
}
// Run the handler now!
return Handler->addOccurrence(i, ArgName, Value ? Value : "");
// If this isn't a multi-arg option, just run the handler.
if (NumAdditionalVals == 0) {
return Handler->addOccurrence(i, ArgName, Value ? Value : "");
}
// If it is, run the handle several times.
else {
bool MultiArg = false;
if (Value) {
if (Handler->addOccurrence(i, ArgName, Value, MultiArg))
return true;
--NumAdditionalVals;
MultiArg = true;
}
while (NumAdditionalVals > 0) {
if (i+1 < argc) {
Value = argv[++i];
} else {
return Handler->error(": not enough values!");
}
if (Handler->addOccurrence(i, ArgName, Value, MultiArg))
return true;
MultiArg = true;
--NumAdditionalVals;
}
return false;
}
}
static bool ProvidePositionalOption(Option *Handler, const std::string &Arg,
@ -738,8 +772,10 @@ bool Option::error(std::string Message, const char *ArgName) {
}
bool Option::addOccurrence(unsigned pos, const char *ArgName,
const std::string &Value) {
NumOccurrences++; // Increment the number of times we have been seen
const std::string &Value,
bool MultiArg) {
if (!MultiArg)
NumOccurrences++; // Increment the number of times we have been seen
switch (getNumOccurrencesFlag()) {
case Optional: