Support for multi-valued options in CommandLine
authorMikhail Glushenkov <foldr@codedgers.com>
Fri, 16 Jan 2009 22:54:19 +0000 (22:54 +0000)
committerMikhail Glushenkov <foldr@codedgers.com>
Fri, 16 Jan 2009 22:54:19 +0000 (22:54 +0000)
Makes possible to specify options that take multiple arguments (a-la
-sectalign on Darwin). See documentation for details.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62372 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CommandLine.html
include/llvm/Support/CommandLine.h
lib/Support/CommandLine.cpp

index 7fcd66caf142e33a7d9b1b5e6c6a931d0e371bd9..97df9f787cdc3cb69da373b4f3bc8a710a1385c7 100644 (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
index b7de038f50befa59d5e1e70a522c264766b83942..e7f5a02b77d7f7e539655827305844ccaaff7f6e 100644 (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
 
index 20c2b8e83f223d01088dcbbc4f175ec3ccb7d077..87dfc5a703fa885d9a36ecd1effd3c4214c258ec 100644 (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: