浏览代码

ENH: Add support for multi-arguments: -f arg1 arg2 arg3 ... and support for lists: -f arg1 -f arg2 -f arg3 ... and for boolean to be stored as strings and doubles

Andy Cedilnik 19 年之前
父节点
当前提交
d2a3ccd505

+ 18 - 0
Source/kwsys/CMakeLists.txt

@@ -819,6 +819,24 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
     ENDIF(NOT CYGWIN)
     ADD_TEST(kwsys.testHashSTL ${EXEC_DIR}/testHashSTL)
     ADD_TEST(kwsys.testRegistry ${EXEC_DIR}/testRegistry)
+    ADD_TEST(kwsys.testCommandLineArguments ${EXEC_DIR}/testCommandLineArguments
+      --another-bool-variable
+      --long3=opt
+      --set-bool-arg1
+      -SSS ken brad bill andy
+      --some-bool-variable=true
+      --some-double-variable12.5
+      --some-int-variable 14
+      "--some-string-variable=test string with space"
+      --some-multi-argument 5 1 8 3 7 1 3 9 7 1
+      -N 12.5 -SS=andy -N 1.31 -N 22
+      -SS=bill -BBtrue -SS=brad
+      -BBtrue 
+      -BBfalse
+      -SS=ken
+      -A
+      -C=test
+      --long2 hello)
     IF(COMMAND SET_TESTS_PROPERTIES AND COMMAND GET_TEST_PROPERTY AND KWSYS_STANDALONE)
       ADD_TEST(kwsys.testFail ${EXEC_DIR}/testFail)
       # We expect test to fail

+ 308 - 162
Source/kwsys/CommandLineArguments.cxx

@@ -15,6 +15,7 @@
 #include KWSYS_HEADER(CommandLineArguments.hxx)
 
 #include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(String.hxx)
 
 #include KWSYS_HEADER(stl/vector)
 #include KWSYS_HEADER(stl/map)
@@ -44,22 +45,18 @@
 # pragma set woff 1375 /* base class destructor not virtual */
 #endif
 
+#if 0
+#  define CommandLineArguments_DEBUG(x) \
+  kwsys_ios::cout << __LINE__ << " CLA: " << x << kwsys_ios::endl
+#else
+#  define CommandLineArguments_DEBUG(x)
+#endif
+
 namespace KWSYS_NAMESPACE
 {
 
 //----------------------------------------------------------------------------
 //============================================================================
-class CommandLineArgumentsString : public kwsys_stl::string 
-{
-public:
-  typedef kwsys_stl::string StdString;
-  CommandLineArgumentsString(): StdString() {}
-  CommandLineArgumentsString(const value_type* s): StdString(s) {}
-  CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
-  CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
-    StdString(s, pos, n) {}
-};
-
 struct CommandLineArgumentsCallbackStructure
 {
   const char* Argument;
@@ -72,11 +69,11 @@ struct CommandLineArgumentsCallbackStructure
 };
  
 class CommandLineArgumentsVectorOfStrings : 
-  public kwsys_stl::vector<CommandLineArgumentsString> {};
+  public kwsys_stl::vector<kwsys::String> {};
 class CommandLineArgumentsSetOfStrings :
-  public kwsys_stl::set<CommandLineArgumentsString> {};
+  public kwsys_stl::set<kwsys::String> {};
 class CommandLineArgumentsMapOfStrucs : 
-  public kwsys_stl::map<CommandLineArgumentsString,
+  public kwsys_stl::map<kwsys::String,
     CommandLineArgumentsCallbackStructure> {};
 
 class CommandLineArgumentsInternal
@@ -91,7 +88,7 @@ public:
 
   typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
   typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
-  typedef CommandLineArgumentsString String;
+  typedef kwsys::String String;
   typedef CommandLineArgumentsSetOfStrings SetOfStrings;
 
   VectorOfStrings Argv;
@@ -153,38 +150,47 @@ void CommandLineArguments::ProcessArgument(const char* arg)
 }
 
 //----------------------------------------------------------------------------
-int CommandLineArguments::Parse()
+bool CommandLineArguments::GetMatchedArguments(
+  kwsys_stl::vector<kwsys_stl::string>* matches,
+  const kwsys_stl::string& arg)
 {
-  CommandLineArguments::Internal::VectorOfStrings::size_type cc;
-  CommandLineArguments::Internal::VectorOfStrings matches;
-  for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
+  matches->clear();
+  CommandLineArguments::Internal::CallbacksMap::iterator it;
+
+  // Does the argument match to any we know about?
+  for ( it = this->Internals->Callbacks.begin();
+    it != this->Internals->Callbacks.end();
+    it ++ )
     {
-    this->Internals->LastArgument = cc;
-    matches.clear();
-    CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
-    CommandLineArguments::Internal::CallbacksMap::iterator it;
-
-    // Does the argument match to any we know about?
-    for ( it = this->Internals->Callbacks.begin();
-      it != this->Internals->Callbacks.end();
-      it ++ )
+    const CommandLineArguments::Internal::String& parg = it->first;
+    CommandLineArgumentsCallbackStructure *cs = &it->second;
+    if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
+      cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) 
       {
-      const CommandLineArguments::Internal::String& parg = it->first;
-      CommandLineArgumentsCallbackStructure *cs = &it->second;
-      if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
-        cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) 
+      if ( arg == parg )
         {
-        if ( arg == parg )
-          {
-          matches.push_back(parg);
-          }
-        }
-      else if ( arg.find( parg ) == 0 )
-        {
-        matches.push_back(parg);
+        matches->push_back(parg);
         }
       }
-    if ( matches.size() > 0 )
+    else if ( arg.find( parg ) == 0 )
+      {
+      matches->push_back(parg);
+      }
+    }
+  return matches->size() > 0;
+}
+
+//----------------------------------------------------------------------------
+int CommandLineArguments::Parse()
+{
+  kwsys_stl::vector<kwsys_stl::string>::size_type cc;
+  kwsys_stl::vector<kwsys_stl::string> matches;
+  for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
+    {
+    const kwsys_stl::string& arg = this->Internals->Argv[cc]; 
+    CommandLineArguments_DEBUG("Process argument: " << arg);
+    this->Internals->LastArgument = cc;
+    if ( this->GetMatchedArguments(&matches, arg) )
       {
       // Ok, we found one or more arguments that match what user specified.
       // Let's find the longest one.
@@ -201,112 +207,84 @@ int CommandLineArguments::Parse()
         }
       // So, the longest one is probably the right one. Now see if it has any
       // additional value
-      const char* value = 0;
       CommandLineArgumentsCallbackStructure *cs 
         = &this->Internals->Callbacks[matches[maxidx]];
       const CommandLineArguments::Internal::String& sarg = matches[maxidx];
-      if ( cs->ArgumentType == NO_ARGUMENT )
+      if ( cs->Argument != sarg )
         {
-        // No value
+        abort();
         }
-      else if ( cs->ArgumentType == SPACE_ARGUMENT )
+      switch ( cs->ArgumentType )
         {
+      case NO_ARGUMENT:
+        // No value
+        if ( !this->PopulateVariable(cs, 0) )
+          {
+          return 0;
+          }
+        break;
+      case SPACE_ARGUMENT:
         if ( cc == this->Internals->Argv.size()-1 )
           {
           this->Internals->LastArgument --;
           return 0;
           }
+        CommandLineArguments_DEBUG("This is a space argument: " << arg
+          << " value: " << this->Internals->Argv[cc+1].c_str());
         // Value is the next argument
-        value = this->Internals->Argv[cc+1].c_str();
+        if ( !this->PopulateVariable(cs, this->Internals->Argv[cc+1].c_str()) )
+          {
+          return 0;
+          }
         cc ++;
-        }
-      else if ( cs->ArgumentType == EQUAL_ARGUMENT )
-        {
+        break;
+      case EQUAL_ARGUMENT:
         if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
           {
           this->Internals->LastArgument --;
           return 0;
           }
         // Value is everythng followed the '=' sign
-        value = arg.c_str() + sarg.size()+1;
-        }
-      else if ( cs->ArgumentType == CONCAT_ARGUMENT )
-        {
-        // Value is whatever follows the argument
-        value = arg.c_str() + sarg.size();
-        }
-
-      // Call the callback
-      if ( cs->Callback )
-        {
-        if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
+        if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1) )
           {
-          this->Internals->LastArgument --;
           return 0;
           }
-        }
-      if ( cs->Variable )
-        {
-        kwsys_stl::string var = "1";
-        if ( value )
-          {
-          var = value;
-          }
-        if ( cs->VariableType == CommandLineArguments::INT_TYPE )
-          {
-          int* variable = static_cast<int*>(cs->Variable);
-          char* res = 0;
-          *variable = strtol(var.c_str(), &res, 10);
-          //if ( res && *res )
-          //  {
-          //  Can handle non-int
-          //  }
-          }
-        else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
-          {
-          double* variable = static_cast<double*>(cs->Variable);
-          char* res = 0;
-          *variable = strtod(var.c_str(), &res);
-          //if ( res && *res )
-          //  {
-          //  Can handle non-int
-          //  }
-          }
-        else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
-          {
-          char** variable = static_cast<char**>(cs->Variable);
-          if ( *variable )
-            {
-            delete [] *variable;
-            *variable = 0;
-            }
-          *variable = new char[ strlen(var.c_str()) + 1 ];
-          strcpy(*variable, var.c_str());
-          }
-        else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
+        break;
+      case CONCAT_ARGUMENT:
+        // Value is whatever follows the argument
+        if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size()) )
           {
-          kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
-          *variable = var;
+          return 0;
           }
-        else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
+        break;
+      case MULTI_ARGUMENT:
+        // Suck in all the rest of the arguments
+        CommandLineArguments_DEBUG("This is a multi argument: " << arg);
+        for (cc++; cc < this->Internals->Argv.size(); ++ cc )
           {
-          bool* variable = static_cast<bool*>(cs->Variable);
-          if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
-            var == "True" || var == "yes" || var == "Yes" || var == "YES" )
+          const kwsys_stl::string& marg = this->Internals->Argv[cc];
+          CommandLineArguments_DEBUG(" check multi argument value: " << marg);
+          if ( this->GetMatchedArguments(&matches, marg) )
             {
-            *variable = true;
+            CommandLineArguments_DEBUG("End of multi argument " << arg << " with value: " << marg);
+            break;
             }
-          else
+          CommandLineArguments_DEBUG(" populate multi argument value: " << marg);
+          if ( !this->PopulateVariable(cs, marg.c_str()) )
             {
-            *variable = false;
+            return 0;
             }
           }
-        else
+        if ( cc != this->Internals->Argv.size() )
           {
-          kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
-          this->Internals->LastArgument --;
-          return 0;
+          CommandLineArguments_DEBUG("Again End of multi argument " << arg);
+          cc--;
+          continue;
           }
+      default:
+        kwsys_ios::cerr << "Got unknown argument type: \"" << cs->ArgumentType << "\"" << kwsys_ios::endl;
+        this->Internals->LastArgument --;
+        return 0;
         }
       }
     else
@@ -404,55 +382,45 @@ void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum ty
 }
 
 //----------------------------------------------------------------------------
-void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
-  int* variable, const char* help)
-{
-  this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
-}
-
-//----------------------------------------------------------------------------
-void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
-  double* variable, const char* help)
-{
-  this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
-}
-
-//----------------------------------------------------------------------------
-void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
-  char** variable, const char* help)
-{
-  this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
-}
-
-//----------------------------------------------------------------------------
-void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
-  kwsys_stl::string* variable, const char* help)
-{
-  this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
-}
-
-//----------------------------------------------------------------------------
-void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
-  bool* variable, const char* help)
-{
-  this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
-}
+#define CommandLineArgumentsAddArgumentMacro(type, ctype) \
+  void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type, \
+    ctype* variable, const char* help) \
+  { \
+    this->AddArgument(argument, type, CommandLineArguments::type##_TYPE, variable, help); \
+  }
+
+CommandLineArgumentsAddArgumentMacro(BOOL,       bool);
+CommandLineArgumentsAddArgumentMacro(INT,        int);
+CommandLineArgumentsAddArgumentMacro(DOUBLE,     double);
+CommandLineArgumentsAddArgumentMacro(STRING,     char*);
+CommandLineArgumentsAddArgumentMacro(STL_STRING, kwsys_stl::string);
+
+CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL,       kwsys_stl::vector<bool>);
+CommandLineArgumentsAddArgumentMacro(VECTOR_INT,        kwsys_stl::vector<int>);
+CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE,     kwsys_stl::vector<double>);
+CommandLineArgumentsAddArgumentMacro(VECTOR_STRING,     kwsys_stl::vector<char*>);
+CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, kwsys_stl::vector<kwsys_stl::string>);
 
 //----------------------------------------------------------------------------
-void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
-  variable, const char* help)
-{
-  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
-    CommandLineArguments::BOOL_TYPE, variable, help);
-}
-
-//----------------------------------------------------------------------------
-void CommandLineArguments::AddBooleanArgument(const char* argument, int*
-  variable, const char* help)
-{
-  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
-    CommandLineArguments::INT_TYPE, variable, help);
-}
+#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype) \
+  void CommandLineArguments::AddBooleanArgument(const char* argument, \
+    ctype* variable, const char* help) \
+  { \
+    this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT, \
+      CommandLineArguments::type##_TYPE, variable, help); \
+  }
+
+CommandLineArgumentsAddBooleanArgumentMacro(BOOL,       bool);
+CommandLineArgumentsAddBooleanArgumentMacro(INT,        int);
+CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE,     double);
+CommandLineArgumentsAddBooleanArgumentMacro(STRING,     char*);
+CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, kwsys_stl::string);
+
+CommandLineArgumentsAddBooleanArgumentMacro(VECTOR_BOOL,       kwsys_stl::vector<bool>);
+CommandLineArgumentsAddBooleanArgumentMacro(VECTOR_INT,        kwsys_stl::vector<int>);
+CommandLineArgumentsAddBooleanArgumentMacro(VECTOR_DOUBLE,     kwsys_stl::vector<double>);
+CommandLineArgumentsAddBooleanArgumentMacro(VECTOR_STRING,     kwsys_stl::vector<char*>);
+CommandLineArgumentsAddBooleanArgumentMacro(VECTOR_STL_STRING, kwsys_stl::vector<kwsys_stl::string>);
 
 //----------------------------------------------------------------------------
 void CommandLineArguments::SetClientData(void* client_data)
@@ -614,6 +582,7 @@ void CommandLineArguments::GenerateHelp()
         case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "opt"); break;
         case CommandLineArguments::SPACE_ARGUMENT:  strcat(argument, " opt"); break;
         case CommandLineArguments::EQUAL_ARGUMENT:  strcat(argument, "=opt"); break;
+        case CommandLineArguments::MULTI_ARGUMENT:  strcat(argument, " opt opt ..."); break;
         }
       char buffer[80];
       sprintf(buffer, format, argument);
@@ -678,4 +647,181 @@ void CommandLineArguments::GenerateHelp()
   this->Help = str.str();
 }
 
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  bool* variable, const kwsys_stl::string& value)
+{
+  if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
+    value == "TRUE" || value == "true" || value == "True" ||
+    value == "yes" || value == "Yes" || value == "YES" )
+    {
+    *variable = true;
+    }
+  else
+    {
+    *variable = false;
+    }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  int* variable, const kwsys_stl::string& value)
+{
+  char* res = 0;
+  *variable = strtol(value.c_str(), &res, 10);
+  //if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  double* variable, const kwsys_stl::string& value)
+{
+  char* res = 0;
+  *variable = strtod(value.c_str(), &res);
+  //if ( res && *res )
+  //  {
+  //  Can handle non-double
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  char** variable, const kwsys_stl::string& value)
+{
+  if ( *variable )
+    {
+    delete [] *variable;
+    *variable = 0;
+    }
+  *variable = new char[ value.size() + 1 ];
+  strcpy(*variable, value.c_str());
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::string* variable, const kwsys_stl::string& value)
+{
+  *variable = value;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::vector<bool>* variable, const kwsys_stl::string& value)
+{
+  bool val = false;
+  if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
+    value == "TRUE" || value == "true" || value == "True" ||
+    value == "yes" || value == "Yes" || value == "YES" )
+    {
+    val = true;
+    }
+  variable->push_back(val);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::vector<int>* variable, const kwsys_stl::string& value)
+{
+  char* res = 0;
+  variable->push_back(strtol(value.c_str(), &res, 10));
+  //if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::vector<double>* variable, const kwsys_stl::string& value)
+{
+  char* res = 0;
+  variable->push_back(strtod(value.c_str(), &res));
+  //if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::vector<char*>* variable, const kwsys_stl::string& value)
+{
+  char* var = new char[ value.size() + 1 ];
+  strcpy(var, value.c_str());
+  variable->push_back(var);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(
+  kwsys_stl::vector<kwsys_stl::string>* variable,
+  const kwsys_stl::string& value)
+{
+  variable->push_back(value);
+}
+
+//----------------------------------------------------------------------------
+bool CommandLineArguments::PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
+  const char* value)
+{
+  // Call the callback
+  if ( cs->Callback )
+    {
+    if ( !cs->Callback(cs->Argument, value, cs->CallData) )
+      {
+      this->Internals->LastArgument --;
+      return 0;
+      }
+    }
+  if ( cs->Variable )
+    {
+    kwsys_stl::string var = "1";
+    if ( value )
+      {
+      var = value;
+      }
+    switch ( cs->VariableType )
+      {
+    case CommandLineArguments::INT_TYPE:
+      this->PopulateVariable(static_cast<int*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::DOUBLE_TYPE:
+      this->PopulateVariable(static_cast<double*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::STRING_TYPE:
+      this->PopulateVariable(static_cast<char**>(cs->Variable), var);
+      break;
+    case CommandLineArguments::STL_STRING_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::string*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::BOOL_TYPE:
+      this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::VECTOR_BOOL_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::vector<bool>*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::VECTOR_INT_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::vector<int>*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::VECTOR_DOUBLE_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::vector<double>*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::VECTOR_STRING_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::vector<char*>*>(cs->Variable), var);
+      break;
+    case CommandLineArguments::VECTOR_STL_STRING_TYPE:
+      this->PopulateVariable(static_cast<kwsys_stl::vector<kwsys_stl::string>*>(cs->Variable), var);
+      break;
+    default:
+      kwsys_ios::cerr << "Got unknown variable type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
+      this->Internals->LastArgument --;
+      return 0;
+      }
+    }
+  return 1;
+}
+
+
 } // namespace KWSYS_NAMESPACE

+ 77 - 10
Source/kwsys/CommandLineArguments.hxx.in

@@ -18,6 +18,7 @@
 #include <@KWSYS_NAMESPACE@/Configure.hxx>
 
 #include <@KWSYS_NAMESPACE@/stl/string>
+#include <@KWSYS_NAMESPACE@/stl/vector>
 
 /* Define this macro temporarily to keep the code readable.  */
 #if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
@@ -28,6 +29,7 @@ namespace @KWSYS_NAMESPACE@
 {
 
 class CommandLineArgumentsInternal;
+class CommandLineArgumentsCallbackStructure;
 
 /** \class CommandLineArguments
  * \brief Command line arguments processing code.
@@ -53,6 +55,7 @@ class CommandLineArgumentsInternal;
  *   CONCAT_ARGUMENT - The argument takes value after no space : --Aval
  *   SPACE_ARGUMENT  - The argument takes value after space    : --A val 
  *   EQUAL_ARGUMENT  - The argument takes value after equal    : --A=val
+ *   MULTI_ARGUMENT  - The argument takes values after space   : --A val1 val2 val3 ...
  *
  * Example use:
  *
@@ -82,7 +85,8 @@ public:
     NO_ARGUMENT,
     CONCAT_ARGUMENT,
     SPACE_ARGUMENT,
-    EQUAL_ARGUMENT
+    EQUAL_ARGUMENT,
+    MULTI_ARGUMENT
   };
 
   /**
@@ -95,7 +99,13 @@ public:
     BOOL_TYPE,            // The vairable is boolean (bool)
     DOUBLE_TYPE,          // The variable is float (double)
     STRING_TYPE,          // The variable is string (char*)
-    STL_STRING_TYPE       // The variable is string (char*)
+    STL_STRING_TYPE,      // The variable is string (char*)
+    VECTOR_INT_TYPE,             // The variable is integer (int)
+    VECTOR_BOOL_TYPE,            // The vairable is boolean (bool)
+    VECTOR_DOUBLE_TYPE,          // The variable is float (double)
+    VECTOR_STRING_TYPE,          // The variable is string (char*)
+    VECTOR_STL_STRING_TYPE,      // The variable is string (char*)
+    LAST_VARIABLE_TYPE
   };
 
   /**
@@ -138,10 +148,10 @@ public:
    * specified value. If the argument is specified, the option is casted to the
    * apropriate type.
    */
-  void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable,
-    const char* help);
-  void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable,
-    const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+    bool* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+    int* variable, const char* help);
   void AddArgument(const char* argument, ArgumentTypeEnum type, 
     double* variable, const char* help);
   void AddArgument(const char* argument, ArgumentTypeEnum type, 
@@ -149,15 +159,53 @@ public:
   void AddArgument(const char* argument, ArgumentTypeEnum type,
     kwsys_stl::string* variable, const char* help);
 
+  /**
+   * Add handler for argument which is going to set the variable to the
+   * specified value. If the argument is specified, the option is casted to the
+   * apropriate type. This will handle the multi argument values.
+   */
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+    kwsys_stl::vector<bool>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+    kwsys_stl::vector<int>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type, 
+    kwsys_stl::vector<double>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type, 
+    kwsys_stl::vector<char*>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+    kwsys_stl::vector<kwsys_stl::string>* variable, const char* help);
+
   /**
    * Add handler for boolean argument. The argument does not take any option
    * and if it is specified, the value of the variable is true/1, otherwise it
    * is false/0.
    */
-  void AddBooleanArgument(const char* argument, bool* variable, const char*
-    help);
-  void AddBooleanArgument(const char* argument, int* variable, const char*
-    help);
+  void AddBooleanArgument(const char* argument,
+    bool* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    int* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    double* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    char** variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::string* variable, const char* help);
+
+  /**
+   * Add handler for boolean argument. The argument does not take any option
+   * and if it is specified, the value of the variable is true/1, otherwise it
+   * is false/0. This will handle the multi argument values.
+   */
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::vector<bool>* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::vector<int>* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::vector<double>* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::vector<char*>* variable, const char* help);
+  void AddBooleanArgument(const char* argument,
+    kwsys_stl::vector<kwsys_stl::string>* variable, const char* help);
 
   /**
    * Set the callbacks for error handling.
@@ -205,6 +253,25 @@ protected:
   void AddArgument(const char* argument, ArgumentTypeEnum type,
     VariableTypeEnum vtype, void* variable, const char* help);
 
+  bool GetMatchedArguments(kwsys_stl::vector<kwsys_stl::string>* matches,
+    const kwsys_stl::string& arg);
+
+  //! Populate individual variables
+  bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
+    const char* value);
+
+  //! Populate individual variables of type ...
+  void PopulateVariable(bool* variable, const kwsys_stl::string& value);
+  void PopulateVariable(int* variable, const kwsys_stl::string& value);
+  void PopulateVariable(double* variable, const kwsys_stl::string& value);
+  void PopulateVariable(char** variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::string* variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::vector<bool>* variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::vector<int>* variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::vector<double>* variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::vector<char*>* variable, const kwsys_stl::string& value);
+  void PopulateVariable(kwsys_stl::vector<kwsys_stl::string>* variable, const kwsys_stl::string& value);
+
   typedef CommandLineArgumentsInternal Internal;
   Internal* Internals;
   kwsys_stl::string Help;

+ 1 - 1
Source/kwsys/SystemTools.cxx

@@ -3157,7 +3157,7 @@ bool SystemTools::LocateFileInDir(const char *filename,
         {
         filename_dir = SystemTools::GetFilenamePath(filename_dir);
         filename_dir_base = SystemTools::GetFilenameName(filename_dir);
-#if _WIN32
+#if defined( _WIN32 )
         if (!filename_dir_base.size() || 
             filename_dir_base[filename_dir_base.size() - 1] == ':')
 #else

+ 60 - 1
Source/kwsys/testCommandLineArguments.cxx

@@ -14,6 +14,7 @@
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(CommandLineArguments.hxx)
 #include KWSYS_HEADER(ios/iostream)
+#include KWSYS_HEADER(stl/vector)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -46,6 +47,12 @@ int unknown_argument(const char* argument, void* call_data)
   return 1;
 }
 
+bool CompareTwoItemsOnList(bool i1, bool i2) { return i1 == i2; }
+bool CompareTwoItemsOnList(int i1, int i2) { return i1 == i2; }
+bool CompareTwoItemsOnList(double i1, double i2) { return i1 == i2; }
+bool CompareTwoItemsOnList(const kwsys_stl::string& i1,
+  const kwsys_stl::string& i2) { return i1 == i2; }
+
 int main(int argc, char* argv[])
 {
   // Example run: ./testCommandLineArguments --some-int-variable 4
@@ -70,6 +77,21 @@ int main(int argc, char* argv[])
   bool bool_arg1 = false;
   int bool_arg2 = 0;
 
+  kwsys_stl::vector<int> numbers_argument;
+  int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 };
+
+  kwsys_stl::vector<double> doubles_argument;
+  double valid_doubles[] = { 12.5, 1.31, 22 };
+
+  kwsys_stl::vector<bool> bools_argument;
+  bool valid_bools[] = { true, true, false };
+
+  kwsys_stl::vector<char*> strings_argument;
+  char* valid_strings[] = { "andy", "bill", "brad", "ken" };
+
+  kwsys_stl::vector<kwsys_stl::string> stl_strings_argument;
+  kwsys_stl::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" };
+
   typedef kwsys::CommandLineArguments argT;
 
   arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, &some_int_variable, "Set some random int variable");
@@ -80,6 +102,11 @@ int main(int argc, char* argv[])
   arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, &some_bool_variable1, "Set some random bool variable 1");
   arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, "Test AddBooleanArgument 1");
   arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, "Test AddBooleanArgument 2");
+  arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT, &numbers_argument, "Some multiple values variable");
+  arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument, "Some explicit multiple values variable");
+  arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument, "Some explicit multiple values variable");
+  arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument, "Some explicit multiple values variable");
+  arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument, "Some explicit multiple values variable");
 
   arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, "Some option -A. This option has a multiline comment. It should demonstrate how the code splits lines.");
   arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, "Option -B takes argument with space");
@@ -99,7 +126,7 @@ int main(int argc, char* argv[])
 
   kwsys_ios::cout << "Some int variable was set to: " << some_int_variable << kwsys_ios::endl;
   kwsys_ios::cout << "Some double variable was set to: " << some_double_variable << kwsys_ios::endl;
-  if ( some_string_variable )
+  if ( some_string_variable && strcmp(some_string_variable, "test string with space") == 0)
     {
     kwsys_ios::cout << "Some string variable was set to: " << some_string_variable << kwsys_ios::endl;
     delete [] some_string_variable;
@@ -109,6 +136,38 @@ int main(int argc, char* argv[])
     kwsys_ios::cerr << "Problem setting string variable" << kwsys_ios::endl;
     res = 1;
     }
+  size_t cc;
+#define CompareTwoLists(list1, list_valid, lsize) \
+  if ( list1.size() != lsize ) \
+    { \
+    kwsys_ios::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \
+     << " should be: " << lsize << kwsys_ios::endl; \
+    res = 1; \
+    } \
+  else \
+    { \
+    kwsys_ios::cout << #list1 " argument set:"; \
+    for ( cc =0; cc < lsize; ++ cc ) \
+      { \
+      kwsys_ios::cout << " " << list1[cc]; \
+      if ( !CompareTwoItemsOnList(list1[cc], list_valid[cc]) ) \
+        { \
+        kwsys_ios::cerr << "Problem setting " #list1 ". Value of " \
+        << cc << " is: [" << list1[cc] << "] <> [" \
+        << list_valid[cc] << "]" << kwsys_ios::endl; \
+        res = 1; \
+        break; \
+        } \
+      } \
+    kwsys_ios::cout << kwsys_ios::endl; \
+    }
+
+  CompareTwoLists(numbers_argument, valid_numbers, 10);
+  CompareTwoLists(doubles_argument, valid_doubles, 3);
+  CompareTwoLists(bools_argument, valid_bools, 3);
+  CompareTwoLists(strings_argument, valid_strings, 4);
+  CompareTwoLists(stl_strings_argument, valid_stl_strings, 4);
+
   kwsys_ios::cout << "Some STL String variable was set to: " << some_stl_string_variable.c_str() << kwsys_ios::endl;
   kwsys_ios::cout << "Some bool variable was set to: " << some_bool_variable << kwsys_ios::endl;
   kwsys_ios::cout << "Some bool variable was set to: " << some_bool_variable1 << kwsys_ios::endl;