1
0
Эх сурвалжийг харах

cmCTest*Command: Port to cmArgumentParser

Regina Pfeifer 6 жил өмнө
parent
commit
0aa8a2ab8b

+ 19 - 26
Source/CTest/cmCTestBuildCommand.cxx

@@ -9,6 +9,7 @@
 #include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
 #include "cmake.h"
 
 #include <cstring>
@@ -16,17 +17,15 @@
 
 class cmExecutionStatus;
 
-cmCTestBuildCommand::cmCTestBuildCommand()
+void cmCTestBuildCommand::BindArguments()
 {
-  this->GlobalGenerator = nullptr;
-  this->Arguments[ctb_NUMBER_ERRORS] = "NUMBER_ERRORS";
-  this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS";
-  this->Arguments[ctb_TARGET] = "TARGET";
-  this->Arguments[ctb_CONFIGURATION] = "CONFIGURATION";
-  this->Arguments[ctb_FLAGS] = "FLAGS";
-  this->Arguments[ctb_PROJECT_NAME] = "PROJECT_NAME";
-  this->Arguments[ctb_LAST] = nullptr;
-  this->Last = ctb_LAST;
+  this->cmCTestHandlerCommand::BindArguments();
+  this->Bind("NUMBER_ERRORS"_s, this->NumberErrors);
+  this->Bind("NUMBER_WARNINGS"_s, this->NumberWarnings);
+  this->Bind("TARGET"_s, this->Target);
+  this->Bind("CONFIGURATION"_s, this->Configuration);
+  this->Bind("FLAGS"_s, this->Flags);
+  this->Bind("PROJECT_NAME"_s, this->ProjectName);
 }
 
 cmCTestBuildCommand::~cmCTestBuildCommand()
@@ -60,20 +59,17 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
     //
     const char* ctestBuildConfiguration =
       this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
-    const char* cmakeBuildConfiguration =
-      (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION])
-      ? this->Values[ctb_CONFIGURATION]
+    const char* cmakeBuildConfiguration = !this->Configuration.empty()
+      ? this->Configuration.c_str()
       : ((ctestBuildConfiguration && *ctestBuildConfiguration)
            ? ctestBuildConfiguration
            : this->CTest->GetConfigType().c_str());
 
-    const char* cmakeBuildAdditionalFlags =
-      (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
-      ? this->Values[ctb_FLAGS]
+    const char* cmakeBuildAdditionalFlags = !this->Flags.empty()
+      ? this->Flags.c_str()
       : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS");
-    const char* cmakeBuildTarget =
-      (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET])
-      ? this->Values[ctb_TARGET]
+    const char* cmakeBuildTarget = !this->Target.empty()
+      ? this->Target.c_str()
       : this->Makefile->GetDefinition("CTEST_BUILD_TARGET");
 
     if (cmakeGeneratorName && *cmakeGeneratorName) {
@@ -153,16 +149,13 @@ bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
                                       cmExecutionStatus& status)
 {
   bool ret = cmCTestHandlerCommand::InitialPass(args, status);
-  if (this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS]) {
+  if (!this->NumberErrors.empty()) {
     this->Makefile->AddDefinition(
-      this->Values[ctb_NUMBER_ERRORS],
-      std::to_string(this->Handler->GetTotalErrors()));
+      this->NumberErrors, std::to_string(this->Handler->GetTotalErrors()));
   }
-  if (this->Values[ctb_NUMBER_WARNINGS] &&
-      *this->Values[ctb_NUMBER_WARNINGS]) {
+  if (!this->NumberWarnings.empty()) {
     this->Makefile->AddDefinition(
-      this->Values[ctb_NUMBER_WARNINGS],
-      std::to_string(this->Handler->GetTotalWarnings()));
+      this->NumberWarnings, std::to_string(this->Handler->GetTotalWarnings()));
   }
   return ret;
 }

+ 9 - 14
Source/CTest/cmCTestBuildCommand.h

@@ -27,7 +27,6 @@ class cmGlobalGenerator;
 class cmCTestBuildCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestBuildCommand();
   ~cmCTestBuildCommand() override;
 
   /**
@@ -49,23 +48,19 @@ public:
   bool InitialPass(std::vector<std::string> const& args,
                    cmExecutionStatus& status) override;
 
-  cmGlobalGenerator* GlobalGenerator;
+  cmGlobalGenerator* GlobalGenerator = nullptr;
 
 protected:
   cmCTestBuildHandler* Handler;
-  enum
-  {
-    ctb_BUILD = ct_LAST,
-    ctb_NUMBER_ERRORS,
-    ctb_NUMBER_WARNINGS,
-    ctb_TARGET,
-    ctb_CONFIGURATION,
-    ctb_FLAGS,
-    ctb_PROJECT_NAME,
-    ctb_LAST
-  };
-
+  void BindArguments() override;
   cmCTestGenericHandler* InitializeHandler() override;
+
+  std::string NumberErrors;
+  std::string NumberWarnings;
+  std::string Target;
+  std::string Configuration;
+  std::string Flags;
+  std::string ProjectName;
 };
 
 #endif

+ 6 - 6
Source/CTest/cmCTestConfigureCommand.cxx

@@ -8,25 +8,25 @@
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
 #include "cmake.h"
 
 #include <cstring>
 #include <sstream>
 #include <vector>
 
-cmCTestConfigureCommand::cmCTestConfigureCommand()
+void cmCTestConfigureCommand::BindArguments()
 {
-  this->Arguments[ctc_OPTIONS] = "OPTIONS";
-  this->Arguments[ctc_LAST] = nullptr;
-  this->Last = ctc_LAST;
+  this->cmCTestHandlerCommand::BindArguments();
+  this->Bind("OPTIONS"_s, this->Options);
 }
 
 cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
 {
   std::vector<std::string> options;
 
-  if (this->Values[ctc_OPTIONS]) {
-    cmExpandList(this->Values[ctc_OPTIONS], options);
+  if (!this->Options.empty()) {
+    cmExpandList(this->Options, options);
   }
 
   if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {

+ 2 - 8
Source/CTest/cmCTestConfigureCommand.h

@@ -23,8 +23,6 @@ class cmCTestGenericHandler;
 class cmCTestConfigureCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestConfigureCommand();
-
   /**
    * This is a virtual constructor for the command.
    */
@@ -42,14 +40,10 @@ public:
   std::string GetName() const override { return "ctest_configure"; }
 
 protected:
+  void BindArguments() override;
   cmCTestGenericHandler* InitializeHandler() override;
 
-  enum
-  {
-    ctc_FIRST = ct_LAST,
-    ctc_OPTIONS,
-    ctc_LAST
-  };
+  std::string Options;
 };
 
 #endif

+ 16 - 28
Source/CTest/cmCTestCoverageCommand.cxx

@@ -2,14 +2,26 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestCoverageCommand.h"
 
+#include <set>
+
+#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestCoverageHandler.h"
+#include "cm_static_string_view.hxx"
 
 class cmCTestGenericHandler;
 
-cmCTestCoverageCommand::cmCTestCoverageCommand()
+void cmCTestCoverageCommand::BindArguments()
+{
+  this->cmCTestHandlerCommand::BindArguments();
+  this->Bind("LABELS"_s, this->Labels);
+}
+
+void cmCTestCoverageCommand::CheckArguments(
+  std::vector<std::string> const& keywords)
 {
-  this->LabelsMentioned = false;
+  this->LabelsMentioned =
+    !this->Labels.empty() || cmContains(keywords, "LABELS");
 }
 
 cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
@@ -24,34 +36,10 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
 
   // If a LABELS option was given, select only files with the labels.
   if (this->LabelsMentioned) {
-    handler->SetLabelFilter(this->Labels);
+    handler->SetLabelFilter(
+      std::set<std::string>(this->Labels.begin(), this->Labels.end()));
   }
 
   handler->SetQuiet(this->Quiet);
   return handler;
 }
-
-bool cmCTestCoverageCommand::CheckArgumentKeyword(std::string const& arg)
-{
-  // Look for arguments specific to this command.
-  if (arg == "LABELS") {
-    this->ArgumentDoing = ArgumentDoingLabels;
-    this->LabelsMentioned = true;
-    return true;
-  }
-
-  // Look for other arguments.
-  return this->Superclass::CheckArgumentKeyword(arg);
-}
-
-bool cmCTestCoverageCommand::CheckArgumentValue(std::string const& arg)
-{
-  // Handle states specific to this command.
-  if (this->ArgumentDoing == ArgumentDoingLabels) {
-    this->Labels.insert(arg);
-    return true;
-  }
-
-  // Look for other arguments.
-  return this->Superclass::CheckArgumentValue(arg);
-}

+ 4 - 15
Source/CTest/cmCTestCoverageCommand.h

@@ -8,9 +8,9 @@
 #include "cmCTestHandlerCommand.h"
 #include "cmCommand.h"
 
-#include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "cm_memory.hxx"
 
@@ -24,8 +24,6 @@ class cmCTestGenericHandler;
 class cmCTestCoverageCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestCoverageCommand();
-
   /**
    * This is a virtual constructor for the command.
    */
@@ -42,22 +40,13 @@ public:
    */
   std::string GetName() const override { return "ctest_coverage"; }
 
-  using Superclass = cmCTestHandlerCommand;
-
 protected:
+  void BindArguments() override;
+  void CheckArguments(std::vector<std::string> const& keywords) override;
   cmCTestGenericHandler* InitializeHandler() override;
 
-  bool CheckArgumentKeyword(std::string const& arg) override;
-  bool CheckArgumentValue(std::string const& arg) override;
-
-  enum
-  {
-    ArgumentDoingLabels = Superclass::ArgumentDoingLast1,
-    ArgumentDoingLast2
-  };
-
   bool LabelsMentioned;
-  std::set<std::string> Labels;
+  std::vector<std::string> Labels;
 };
 
 #endif

+ 47 - 100
Source/CTest/cmCTestHandlerCommand.cxx

@@ -7,31 +7,16 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
+#include "cm_static_string_view.hxx"
 
+#include <algorithm>
 #include <cstdlib>
 #include <cstring>
 #include <sstream>
 
-cmCTestHandlerCommand::cmCTestHandlerCommand()
-{
-  const size_t INIT_SIZE = 100;
-  size_t cc;
-  this->Arguments.reserve(INIT_SIZE);
-  for (cc = 0; cc < INIT_SIZE; ++cc) {
-    this->Arguments.push_back(nullptr);
-  }
-  this->Arguments[ct_RETURN_VALUE] = "RETURN_VALUE";
-  this->Arguments[ct_CAPTURE_CMAKE_ERROR] = "CAPTURE_CMAKE_ERROR";
-  this->Arguments[ct_SOURCE] = "SOURCE";
-  this->Arguments[ct_BUILD] = "BUILD";
-  this->Arguments[ct_SUBMIT_INDEX] = "SUBMIT_INDEX";
-  this->Last = ct_LAST;
-  this->AppendXML = false;
-  this->Quiet = false;
-}
-
 namespace {
 // class to save and restore the error state for ctest_* commands
 // if a ctest_* command has a CAPTURE_CMAKE_ERROR then put the error
@@ -90,30 +75,30 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
   // save error state and restore it if needed
   SaveRestoreErrorState errorState;
   // Allocate space for argument values.
-  this->Values.clear();
-  this->Values.resize(this->Last, nullptr);
+  this->BindArguments();
 
   // Process input arguments.
-  this->ArgumentDoing = ArgumentDoingNone;
-  // look at all arguments and do not short circuit on the first
-  // bad one so that CAPTURE_CMAKE_ERROR can override setting the
-  // global error state
-  bool foundBadArgument = false;
-  for (std::string const& arg : args) {
-    // Check this argument.
-    if (!this->CheckArgumentKeyword(arg) && !this->CheckArgumentValue(arg)) {
-      std::ostringstream e;
-      e << "called with unknown argument \"" << arg << "\".";
-      this->SetError(e.str());
-      foundBadArgument = true;
-    }
-    // note bad argument
-    if (this->ArgumentDoing == ArgumentDoingError) {
-      foundBadArgument = true;
-    }
+  std::vector<std::string> unparsedArguments;
+  std::vector<std::string> keywordsMissingValue;
+  std::vector<std::string> parsedKeywords;
+  this->Parse(args, &unparsedArguments, &keywordsMissingValue,
+              &parsedKeywords);
+  this->CheckArguments(keywordsMissingValue);
+
+  std::sort(parsedKeywords.begin(), parsedKeywords.end());
+  auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end());
+  if (it != parsedKeywords.end()) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("Called with more than one value for ", *it));
+  }
+
+  bool const foundBadArgument = !unparsedArguments.empty();
+  if (foundBadArgument) {
+    this->SetError(cmStrCat("called with unknown argument \"",
+                            unparsedArguments.front(), "\"."));
   }
-  bool captureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] &&
-                            *this->Values[ct_CAPTURE_CMAKE_ERROR]);
+  bool const captureCMakeError = !this->CaptureCMakeError.empty();
   // now that arguments are parsed check to see if there is a
   // CAPTURE_CMAKE_ERROR specified let the errorState object know.
   if (captureCMakeError) {
@@ -123,8 +108,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
   if (foundBadArgument) {
     // store the cmake error
     if (captureCMakeError) {
-      this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
-                                    "-1");
+      this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
       std::string const err = this->GetName() + " " + status.GetError();
       if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
         cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
@@ -146,10 +130,9 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
     this->CTest->SetConfigType(ctestConfigType);
   }
 
-  if (this->Values[ct_BUILD]) {
+  if (!this->Build.empty()) {
     this->CTest->SetCTestConfiguration(
-      "BuildDirectory",
-      cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(),
+      "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build).c_str(),
       this->Quiet);
   } else {
     std::string const& bdir =
@@ -163,13 +146,11 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
                  "CTEST_BINARY_DIRECTORY not set" << std::endl;);
     }
   }
-  if (this->Values[ct_SOURCE]) {
+  if (!this->Source.empty()) {
     cmCTestLog(this->CTest, DEBUG,
-               "Set source directory to: " << this->Values[ct_SOURCE]
-                                           << std::endl);
+               "Set source directory to: " << this->Source << std::endl);
     this->CTest->SetCTestConfiguration(
-      "SourceDirectory",
-      cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+      "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(),
       this->Quiet);
   } else {
     this->CTest->SetCTestConfiguration(
@@ -192,8 +173,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
                "Cannot instantiate test handler " << this->GetName()
                                                   << std::endl);
     if (captureCMakeError) {
-      this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
-                                    "-1");
+      this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
       std::string const& err = status.GetError();
       if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
         cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
@@ -203,11 +183,11 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
     return false;
   }
 
-  handler->SetAppendXML(this->AppendXML);
+  handler->SetAppendXML(this->Append);
 
   handler->PopulateCustomVectors(this->Makefile);
-  if (this->Values[ct_SUBMIT_INDEX]) {
-    handler->SetSubmitIndex(atoi(this->Values[ct_SUBMIT_INDEX]));
+  if (!this->SubmitIndex.empty()) {
+    handler->SetSubmitIndex(atoi(this->SubmitIndex.c_str()));
   }
   cmWorkingDirectory workdir(
     this->CTest->GetCTestConfiguration("BuildDirectory"));
@@ -216,8 +196,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
                    this->CTest->GetCTestConfiguration("BuildDirectory") +
                    " : " + std::strerror(workdir.GetLastResult()));
     if (captureCMakeError) {
-      this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
-                                    "-1");
+      this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
       cmCTestLog(this->CTest, ERROR_MESSAGE,
                  this->GetName() << " " << status.GetError() << "\n");
       // return success because failure is recorded in CAPTURE_CMAKE_ERROR
@@ -227,9 +206,8 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
   }
 
   int res = handler->ProcessHandler();
-  if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) {
-    this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE],
-                                  std::to_string(res));
+  if (!this->ReturnValue.empty()) {
+    this->Makefile->AddDefinition(this->ReturnValue, std::to_string(res));
   }
   this->ProcessAdditionalValues(handler);
   // log the error message if there was an error
@@ -245,8 +223,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
       }
     }
     // store the captured cmake error state 0 or -1
-    this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
-                                  returnString);
+    this->Makefile->AddDefinition(this->CaptureCMakeError, returnString);
   }
   return true;
 }
@@ -255,47 +232,17 @@ void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
 {
 }
 
-bool cmCTestHandlerCommand::CheckArgumentKeyword(std::string const& arg)
+void cmCTestHandlerCommand::BindArguments()
 {
-  // Look for non-value arguments common to all commands.
-  if (arg == "APPEND") {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->AppendXML = true;
-    return true;
-  }
-  if (arg == "QUIET") {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->Quiet = true;
-    return true;
-  }
-
-  // Check for a keyword in our argument/value table.
-  for (unsigned int k = 0; k < this->Arguments.size(); ++k) {
-    if (this->Arguments[k] && arg == this->Arguments[k]) {
-      this->ArgumentDoing = ArgumentDoingKeyword;
-      this->ArgumentIndex = k;
-      return true;
-    }
-  }
-  return false;
+  this->Bind("APPEND"_s, this->Append);
+  this->Bind("QUIET"_s, this->Quiet);
+  this->Bind("RETURN_VALUE"_s, this->ReturnValue);
+  this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
+  this->Bind("SOURCE"_s, this->Source);
+  this->Bind("BUILD"_s, this->Build);
+  this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex);
 }
 
-bool cmCTestHandlerCommand::CheckArgumentValue(std::string const& arg)
+void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&)
 {
-  if (this->ArgumentDoing == ArgumentDoingKeyword) {
-    this->ArgumentDoing = ArgumentDoingNone;
-    unsigned int k = this->ArgumentIndex;
-    if (this->Values[k]) {
-      std::ostringstream e;
-      e << "Called with more than one value for " << this->Arguments[k];
-      this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      this->ArgumentDoing = ArgumentDoingError;
-      return true;
-    }
-    this->Values[k] = arg.c_str();
-    cmCTestLog(this->CTest, DEBUG,
-               "Set " << this->Arguments[k] << " to " << arg << "\n");
-    return true;
-  }
-  return false;
 }

+ 14 - 34
Source/CTest/cmCTestHandlerCommand.h

@@ -5,9 +5,9 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include "cmArgumentParser.h"
 #include "cmCTestCommand.h"
 
-#include <stddef.h>
 #include <string>
 #include <vector>
 
@@ -19,11 +19,11 @@ class cmExecutionStatus;
  *
  * cmCTestHandlerCommand defineds the command to test the project.
  */
-class cmCTestHandlerCommand : public cmCTestCommand
+class cmCTestHandlerCommand
+  : public cmCTestCommand
+  , public cmArgumentParser<void>
 {
 public:
-  cmCTestHandlerCommand();
-
   /**
    * The name of the command as specified in CMakeList.txt.
    */
@@ -36,42 +36,22 @@ public:
   bool InitialPass(std::vector<std::string> const& args,
                    cmExecutionStatus& status) override;
 
-  enum
-  {
-    ct_NONE,
-    ct_RETURN_VALUE,
-    ct_CAPTURE_CMAKE_ERROR,
-    ct_BUILD,
-    ct_SOURCE,
-    ct_SUBMIT_INDEX,
-    ct_LAST
-  };
-
 protected:
   virtual cmCTestGenericHandler* InitializeHandler() = 0;
 
   virtual void ProcessAdditionalValues(cmCTestGenericHandler* handler);
 
   // Command argument handling.
-  virtual bool CheckArgumentKeyword(std::string const& arg);
-  virtual bool CheckArgumentValue(std::string const& arg);
-  enum
-  {
-    ArgumentDoingNone,
-    ArgumentDoingError,
-    ArgumentDoingKeyword,
-    ArgumentDoingLast1
-  };
-  int ArgumentDoing;
-  unsigned int ArgumentIndex;
-
-  bool AppendXML;
-  bool Quiet;
-
-  std::string ReturnVariable;
-  std::vector<const char*> Arguments;
-  std::vector<const char*> Values;
-  size_t Last;
+  virtual void BindArguments();
+  virtual void CheckArguments(std::vector<std::string> const& keywords);
+
+  bool Append = false;
+  bool Quiet = false;
+  std::string CaptureCMakeError;
+  std::string ReturnValue;
+  std::string Build;
+  std::string Source;
+  std::string SubmitIndex;
 };
 
 #define CTEST_COMMAND_APPEND_OPTION_DOCS                                      \

+ 6 - 9
Source/CTest/cmCTestMemCheckCommand.cxx

@@ -2,18 +2,15 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestMemCheckCommand.h"
 
-#include <string>
-#include <vector>
-
 #include "cmCTest.h"
 #include "cmCTestMemCheckHandler.h"
 #include "cmMakefile.h"
+#include "cm_static_string_view.hxx"
 
-cmCTestMemCheckCommand::cmCTestMemCheckCommand()
+void cmCTestMemCheckCommand::BindArguments()
 {
-  this->Arguments[ctm_DEFECT_COUNT] = "DEFECT_COUNT";
-  this->Arguments[ctm_LAST] = nullptr;
-  this->Last = ctm_LAST;
+  this->cmCTestTestCommand::BindArguments();
+  this->Bind("DEFECT_COUNT"_s, this->DefectCount);
 }
 
 cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
@@ -43,9 +40,9 @@ cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
 void cmCTestMemCheckCommand::ProcessAdditionalValues(
   cmCTestGenericHandler* handler)
 {
-  if (this->Values[ctm_DEFECT_COUNT] && *this->Values[ctm_DEFECT_COUNT]) {
+  if (!this->DefectCount.empty()) {
     this->Makefile->AddDefinition(
-      this->Values[ctm_DEFECT_COUNT],
+      this->DefectCount,
       std::to_string(
         static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount()));
   }

+ 4 - 7
Source/CTest/cmCTestMemCheckCommand.h

@@ -5,6 +5,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <string>
 #include <utility>
 
 #include "cm_memory.hxx"
@@ -22,8 +23,6 @@ class cmCTestGenericHandler;
 class cmCTestMemCheckCommand : public cmCTestTestCommand
 {
 public:
-  cmCTestMemCheckCommand();
-
   /**
    * This is a virtual constructor for the command.
    */
@@ -36,15 +35,13 @@ public:
   }
 
 protected:
+  void BindArguments() override;
+
   cmCTestGenericHandler* InitializeActualHandler() override;
 
   void ProcessAdditionalValues(cmCTestGenericHandler* handler) override;
 
-  enum
-  {
-    ctm_DEFECT_COUNT = ctt_LAST,
-    ctm_LAST
-  };
+  std::string DefectCount;
 };
 
 #endif

+ 40 - 115
Source/CTest/cmCTestSubmitCommand.cxx

@@ -2,14 +2,18 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestSubmitCommand.h"
 
+#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestSubmitHandler.h"
 #include "cmCommand.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
 
+#include <set>
 #include <sstream>
 #include <utility>
 
@@ -17,18 +21,6 @@
 
 class cmExecutionStatus;
 
-cmCTestSubmitCommand::cmCTestSubmitCommand()
-{
-  this->PartsMentioned = false;
-  this->FilesMentioned = false;
-  this->InternalTest = false;
-  this->RetryCount = "";
-  this->RetryDelay = "";
-  this->CDashUpload = false;
-  this->Arguments[cts_BUILD_ID] = "BUILD_ID";
-  this->Last = cts_LAST;
-}
-
 /**
  * This is a virtual constructor for the command.
  */
@@ -106,13 +98,18 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
     // without any of the default parts.
     //
     handler->SelectParts(std::set<cmCTest::Part>());
-    handler->SelectFiles(this->Files);
+    handler->SelectFiles(
+      std::set<std::string>(this->Files.begin(), this->Files.end()));
   }
 
   // If a PARTS option was given, select only the named parts for submission.
   //
   if (this->PartsMentioned) {
-    handler->SelectParts(this->Parts);
+    auto parts =
+      cmMakeRange(this->Parts).transform([this](std::string const& arg) {
+        return this->CTest->GetPartFromName(arg.c_str());
+      });
+    handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end()));
   }
 
   // Pass along any HTTPHEADER to the handler if this option was given.
@@ -140,133 +137,61 @@ bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
 
   bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
 
-  if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) {
-    this->Makefile->AddDefinition(this->Values[cts_BUILD_ID],
-                                  this->CTest->GetBuildID());
+  if (!this->BuildID.empty()) {
+    this->Makefile->AddDefinition(this->BuildID, this->CTest->GetBuildID());
   }
 
   return ret;
 }
 
-bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
+void cmCTestSubmitCommand::BindArguments()
 {
   if (this->CDashUpload) {
     // Arguments specific to the CDASH_UPLOAD signature.
-    if (arg == "CDASH_UPLOAD") {
-      this->ArgumentDoing = ArgumentDoingCDashUpload;
-      return true;
-    }
-
-    if (arg == "CDASH_UPLOAD_TYPE") {
-      this->ArgumentDoing = ArgumentDoingCDashUploadType;
-      return true;
-    }
+    this->Bind("CDASH_UPLOAD", this->CDashUploadFile);
+    this->Bind("CDASH_UPLOAD_TYPE", this->CDashUploadType);
   } else {
     // Arguments that cannot be used with CDASH_UPLOAD.
-    if (arg == "PARTS") {
-      this->ArgumentDoing = ArgumentDoingParts;
-      this->PartsMentioned = true;
-      return true;
-    }
-
-    if (arg == "FILES") {
-      this->ArgumentDoing = ArgumentDoingFiles;
-      this->FilesMentioned = true;
-      return true;
-    }
+    this->Bind("PARTS"_s, this->Parts);
+    this->Bind("FILES"_s, this->Files);
   }
   // Arguments used by both modes.
-  if (arg == "HTTPHEADER") {
-    this->ArgumentDoing = ArgumentDoingHttpHeader;
-    return true;
-  }
-
-  if (arg == "RETRY_COUNT") {
-    this->ArgumentDoing = ArgumentDoingRetryCount;
-    return true;
-  }
-
-  if (arg == "RETRY_DELAY") {
-    this->ArgumentDoing = ArgumentDoingRetryDelay;
-    return true;
-  }
-
-  if (arg == "SUBMIT_URL") {
-    this->ArgumentDoing = ArgumentDoingSubmitURL;
-    return true;
-  }
-
-  if (arg == "INTERNAL_TEST_CHECKSUM") {
-    this->InternalTest = true;
-    return true;
-  }
+  this->Bind("BUILD_ID"_s, this->BuildID);
+  this->Bind("HTTPHEADER"_s, this->HttpHeaders);
+  this->Bind("RETRY_COUNT"_s, this->RetryCount);
+  this->Bind("RETRY_DELAY"_s, this->RetryDelay);
+  this->Bind("SUBMIT_URL"_s, this->SubmitURL);
+  this->Bind("INTERNAL_TEST_CHECKSUM", this->InternalTest);
 
   // Look for other arguments.
-  return this->Superclass::CheckArgumentKeyword(arg);
+  this->cmCTestHandlerCommand::BindArguments();
 }
 
-bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
+void cmCTestSubmitCommand::CheckArguments(
+  std::vector<std::string> const& keywords)
 {
-  // Handle states specific to this command.
-  if (this->ArgumentDoing == ArgumentDoingParts) {
+  this->PartsMentioned = !this->Parts.empty() || cmContains(keywords, "PARTS");
+  this->FilesMentioned = !this->Files.empty() || cmContains(keywords, "FILES");
+
+  cmEraseIf(this->Parts, [this](std::string const& arg) -> bool {
     cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str());
-    if (p != cmCTest::PartCount) {
-      this->Parts.insert(p);
-    } else {
+    if (p == cmCTest::PartCount) {
       std::ostringstream e;
       e << "Part name \"" << arg << "\" is invalid.";
       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      this->ArgumentDoing = ArgumentDoingError;
+      return true;
     }
-    return true;
-  }
+    return false;
+  });
 
-  if (this->ArgumentDoing == ArgumentDoingFiles) {
-    if (cmSystemTools::FileExists(arg)) {
-      this->Files.insert(arg);
-    } else {
+  cmEraseIf(this->Files, [this](std::string const& arg) -> bool {
+    if (!cmSystemTools::FileExists(arg)) {
       std::ostringstream e;
       e << "File \"" << arg << "\" does not exist. Cannot submit "
         << "a non-existent file.";
       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      this->ArgumentDoing = ArgumentDoingError;
+      return true;
     }
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingHttpHeader) {
-    this->HttpHeaders.push_back(arg);
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingRetryCount) {
-    this->RetryCount = arg;
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingRetryDelay) {
-    this->RetryDelay = arg;
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingCDashUpload) {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->CDashUploadFile = arg;
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingCDashUploadType) {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->CDashUploadType = arg;
-    return true;
-  }
-
-  if (this->ArgumentDoing == ArgumentDoingSubmitURL) {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->SubmitURL = arg;
-    return true;
-  }
-
-  // Look for other arguments.
-  return this->Superclass::CheckArgumentValue(arg);
+    return false;
+  });
 }

+ 13 - 35
Source/CTest/cmCTestSubmitCommand.h

@@ -5,11 +5,9 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include "cmCTest.h"
 #include "cmCTestHandlerCommand.h"
 
 #include <memory>
-#include <set>
 #include <string>
 #include <vector>
 
@@ -26,7 +24,6 @@ class cmExecutionStatus;
 class cmCTestSubmitCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestSubmitCommand();
   std::unique_ptr<cmCommand> Clone() override;
 
   bool InitialPass(std::vector<std::string> const& args,
@@ -37,45 +34,26 @@ public:
    */
   std::string GetName() const override { return "ctest_submit"; }
 
-  using Superclass = cmCTestHandlerCommand;
-
 protected:
+  void BindArguments() override;
+  void CheckArguments(std::vector<std::string> const& keywords) override;
   cmCTestGenericHandler* InitializeHandler() override;
 
-  bool CheckArgumentKeyword(std::string const& arg) override;
-  bool CheckArgumentValue(std::string const& arg) override;
-
-  enum
-  {
-    ArgumentDoingParts = Superclass::ArgumentDoingLast1,
-    ArgumentDoingFiles,
-    ArgumentDoingRetryDelay,
-    ArgumentDoingRetryCount,
-    ArgumentDoingCDashUpload,
-    ArgumentDoingCDashUploadType,
-    ArgumentDoingHttpHeader,
-    ArgumentDoingSubmitURL,
-    ArgumentDoingLast2
-  };
-
-  enum
-  {
-    cts_BUILD_ID = ct_LAST,
-    cts_LAST
-  };
+  bool CDashUpload = false;
+  bool FilesMentioned = false;
+  bool InternalTest = false;
+  bool PartsMentioned = false;
 
-  bool PartsMentioned;
-  std::set<cmCTest::Part> Parts;
-  bool FilesMentioned;
-  bool InternalTest;
-  std::set<std::string> Files;
-  std::string RetryCount;
-  std::string RetryDelay;
-  bool CDashUpload;
+  std::string BuildID;
   std::string CDashUploadFile;
   std::string CDashUploadType;
-  std::vector<std::string> HttpHeaders;
+  std::string RetryCount;
+  std::string RetryDelay;
   std::string SubmitURL;
+
+  std::vector<std::string> Files;
+  std::vector<std::string> HttpHeaders;
+  std::vector<std::string> Parts;
 };
 
 #endif

+ 45 - 59
Source/CTest/cmCTestTestCommand.cxx

@@ -8,30 +8,29 @@
 #include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
+#include "cm_static_string_view.hxx"
 
 #include <chrono>
 #include <cstdlib>
 #include <sstream>
-#include <vector>
 
-cmCTestTestCommand::cmCTestTestCommand()
+void cmCTestTestCommand::BindArguments()
 {
-  this->Arguments[ctt_START] = "START";
-  this->Arguments[ctt_END] = "END";
-  this->Arguments[ctt_STRIDE] = "STRIDE";
-  this->Arguments[ctt_EXCLUDE] = "EXCLUDE";
-  this->Arguments[ctt_INCLUDE] = "INCLUDE";
-  this->Arguments[ctt_EXCLUDE_LABEL] = "EXCLUDE_LABEL";
-  this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL";
-  this->Arguments[ctt_EXCLUDE_FIXTURE] = "EXCLUDE_FIXTURE";
-  this->Arguments[ctt_EXCLUDE_FIXTURE_SETUP] = "EXCLUDE_FIXTURE_SETUP";
-  this->Arguments[ctt_EXCLUDE_FIXTURE_CLEANUP] = "EXCLUDE_FIXTURE_CLEANUP";
-  this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL";
-  this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM";
-  this->Arguments[ctt_STOP_TIME] = "STOP_TIME";
-  this->Arguments[ctt_TEST_LOAD] = "TEST_LOAD";
-  this->Arguments[ctt_LAST] = nullptr;
-  this->Last = ctt_LAST;
+  this->cmCTestHandlerCommand::BindArguments();
+  this->Bind("START"_s, this->Start);
+  this->Bind("END"_s, this->End);
+  this->Bind("STRIDE"_s, this->Stride);
+  this->Bind("EXCLUDE"_s, this->Exclude);
+  this->Bind("INCLUDE"_s, this->Include);
+  this->Bind("EXCLUDE_LABEL"_s, this->ExcludeLabel);
+  this->Bind("INCLUDE_LABEL"_s, this->IncludeLabel);
+  this->Bind("EXCLUDE_FIXTURE"_s, this->ExcludeFixture);
+  this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup);
+  this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup);
+  this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel);
+  this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom);
+  this->Bind("STOP_TIME"_s, this->StopTime);
+  this->Bind("TEST_LOAD"_s, this->TestLoad);
 }
 
 cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
@@ -51,57 +50,44 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   }
   this->CTest->SetTimeOut(timeout);
   cmCTestGenericHandler* handler = this->InitializeActualHandler();
-  if (this->Values[ctt_START] || this->Values[ctt_END] ||
-      this->Values[ctt_STRIDE]) {
-    std::ostringstream testsToRunString;
-    if (this->Values[ctt_START]) {
-      testsToRunString << this->Values[ctt_START];
-    }
-    testsToRunString << ",";
-    if (this->Values[ctt_END]) {
-      testsToRunString << this->Values[ctt_END];
-    }
-    testsToRunString << ",";
-    if (this->Values[ctt_STRIDE]) {
-      testsToRunString << this->Values[ctt_STRIDE];
-    }
-    handler->SetOption("TestsToRunInformation",
-                       testsToRunString.str().c_str());
+  if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) {
+    handler->SetOption(
+      "TestsToRunInformation",
+      cmStrCat(this->Start, ',', this->End, ',', this->Stride).c_str());
   }
-  if (this->Values[ctt_EXCLUDE]) {
-    handler->SetOption("ExcludeRegularExpression", this->Values[ctt_EXCLUDE]);
+  if (!this->Exclude.empty()) {
+    handler->SetOption("ExcludeRegularExpression", this->Exclude.c_str());
   }
-  if (this->Values[ctt_INCLUDE]) {
-    handler->SetOption("IncludeRegularExpression", this->Values[ctt_INCLUDE]);
+  if (!this->Include.empty()) {
+    handler->SetOption("IncludeRegularExpression", this->Include.c_str());
   }
-  if (this->Values[ctt_EXCLUDE_LABEL]) {
+  if (!this->ExcludeLabel.empty()) {
     handler->SetOption("ExcludeLabelRegularExpression",
-                       this->Values[ctt_EXCLUDE_LABEL]);
+                       this->ExcludeLabel.c_str());
   }
-  if (this->Values[ctt_INCLUDE_LABEL]) {
-    handler->SetOption("LabelRegularExpression",
-                       this->Values[ctt_INCLUDE_LABEL]);
+  if (!this->IncludeLabel.empty()) {
+    handler->SetOption("LabelRegularExpression", this->IncludeLabel.c_str());
   }
-  if (this->Values[ctt_EXCLUDE_FIXTURE]) {
+  if (!this->ExcludeFixture.empty()) {
     handler->SetOption("ExcludeFixtureRegularExpression",
-                       this->Values[ctt_EXCLUDE_FIXTURE]);
+                       this->ExcludeFixture.c_str());
   }
-  if (this->Values[ctt_EXCLUDE_FIXTURE_SETUP]) {
+  if (!this->ExcludeFixtureSetup.empty()) {
     handler->SetOption("ExcludeFixtureSetupRegularExpression",
-                       this->Values[ctt_EXCLUDE_FIXTURE_SETUP]);
+                       this->ExcludeFixtureSetup.c_str());
   }
-  if (this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]) {
+  if (!this->ExcludeFixtureCleanup.empty()) {
     handler->SetOption("ExcludeFixtureCleanupRegularExpression",
-                       this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]);
+                       this->ExcludeFixtureCleanup.c_str());
   }
-  if (this->Values[ctt_PARALLEL_LEVEL]) {
-    handler->SetOption("ParallelLevel", this->Values[ctt_PARALLEL_LEVEL]);
+  if (!this->ParallelLevel.empty()) {
+    handler->SetOption("ParallelLevel", this->ParallelLevel.c_str());
   }
-  if (this->Values[ctt_SCHEDULE_RANDOM]) {
-    handler->SetOption("ScheduleRandom", this->Values[ctt_SCHEDULE_RANDOM]);
+  if (!this->ScheduleRandom.empty()) {
+    handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str());
   }
-  if (this->Values[ctt_STOP_TIME]) {
-    this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]);
+  if (!this->StopTime.empty()) {
+    this->CTest->SetStopTime(this->StopTime);
   }
 
   // Test load is determined by: TEST_LOAD argument,
@@ -109,12 +95,12 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   // command line argument... in that order.
   unsigned long testLoad;
   const char* ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
-  if (this->Values[ctt_TEST_LOAD] && *this->Values[ctt_TEST_LOAD]) {
-    if (!cmStrToULong(this->Values[ctt_TEST_LOAD], &testLoad)) {
+  if (!this->TestLoad.empty()) {
+    if (!cmStrToULong(this->TestLoad.c_str(), &testLoad)) {
       testLoad = 0;
       cmCTestLog(this->CTest, WARNING,
-                 "Invalid value for 'TEST_LOAD' : "
-                   << this->Values[ctt_TEST_LOAD] << std::endl);
+                 "Invalid value for 'TEST_LOAD' : " << this->TestLoad
+                                                    << std::endl);
     }
   } else if (ctestTestLoad && *ctestTestLoad) {
     if (!cmStrToULong(ctestTestLoad, &testLoad)) {

+ 15 - 22
Source/CTest/cmCTestTestCommand.h

@@ -23,8 +23,6 @@ class cmCTestGenericHandler;
 class cmCTestTestCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestTestCommand();
-
   /**
    * This is a virtual constructor for the command.
    */
@@ -42,29 +40,24 @@ public:
   std::string GetName() const override { return "ctest_test"; }
 
 protected:
+  void BindArguments() override;
   virtual cmCTestGenericHandler* InitializeActualHandler();
   cmCTestGenericHandler* InitializeHandler() override;
 
-  enum
-  {
-    ctt_BUILD = ct_LAST,
-    ctt_RETURN_VALUE,
-    ctt_START,
-    ctt_END,
-    ctt_STRIDE,
-    ctt_EXCLUDE,
-    ctt_INCLUDE,
-    ctt_EXCLUDE_LABEL,
-    ctt_INCLUDE_LABEL,
-    ctt_EXCLUDE_FIXTURE,
-    ctt_EXCLUDE_FIXTURE_SETUP,
-    ctt_EXCLUDE_FIXTURE_CLEANUP,
-    ctt_PARALLEL_LEVEL,
-    ctt_SCHEDULE_RANDOM,
-    ctt_STOP_TIME,
-    ctt_TEST_LOAD,
-    ctt_LAST
-  };
+  std::string Start;
+  std::string End;
+  std::string Stride;
+  std::string Exclude;
+  std::string Include;
+  std::string ExcludeLabel;
+  std::string IncludeLabel;
+  std::string ExcludeFixture;
+  std::string ExcludeFixtureSetup;
+  std::string ExcludeFixtureCleanup;
+  std::string ParallelLevel;
+  std::string ScheduleRandom;
+  std::string StopTime;
+  std::string TestLoad;
 };
 
 #endif

+ 2 - 5
Source/CTest/cmCTestUpdateCommand.cxx

@@ -7,14 +7,11 @@
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
 
-#include <vector>
-
 cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
 {
-  if (this->Values[ct_SOURCE]) {
+  if (!this->Source.empty()) {
     this->CTest->SetCTestConfiguration(
-      "SourceDirectory",
-      cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+      "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(),
       this->Quiet);
   } else {
     this->CTest->SetCTestConfiguration(

+ 0 - 2
Source/CTest/cmCTestUpdateCommand.h

@@ -23,8 +23,6 @@ class cmCTestGenericHandler;
 class cmCTestUpdateCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestUpdateCommand() {}
-
   /**
    * This is a virtual constructor for the command.
    */

+ 24 - 40
Source/CTest/cmCTestUploadCommand.cxx

@@ -2,61 +2,45 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestUploadCommand.h"
 
+#include <set>
 #include <sstream>
 #include <vector>
 
+#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestUploadHandler.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
 
-cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
-{
-  cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
-  handler->Initialize();
-  handler->SetFiles(this->Files);
-  handler->SetQuiet(this->Quiet);
-  return handler;
-}
-
-bool cmCTestUploadCommand::CheckArgumentKeyword(std::string const& arg)
+void cmCTestUploadCommand::BindArguments()
 {
-  if (arg == "FILES") {
-    this->ArgumentDoing = ArgumentDoingFiles;
-    return true;
-  }
-  if (arg == "QUIET") {
-    this->ArgumentDoing = ArgumentDoingNone;
-    this->Quiet = true;
-    return true;
-  }
-  if (arg == "CAPTURE_CMAKE_ERROR") {
-    this->ArgumentDoing = ArgumentDoingCaptureCMakeError;
-    return true;
-  }
-  return false;
+  this->Bind("FILES"_s, this->Files);
+  this->Bind("QUIET"_s, this->Quiet);
+  this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
 }
 
-bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg)
+void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&)
 {
-  if (this->ArgumentDoing == ArgumentDoingCaptureCMakeError) {
-    this->Values[ct_CAPTURE_CMAKE_ERROR] = arg.c_str();
-    return true;
-  }
-  if (this->ArgumentDoing == ArgumentDoingFiles) {
-    if (cmSystemTools::FileExists(arg)) {
-      this->Files.insert(arg);
+  cmEraseIf(this->Files, [this](std::string const& arg) -> bool {
+    if (!cmSystemTools::FileExists(arg)) {
+      std::ostringstream e;
+      e << "File \"" << arg << "\" does not exist. Cannot submit "
+        << "a non-existent file.";
+      this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return true;
     }
-    std::ostringstream e;
-    e << "File \"" << arg << "\" does not exist. Cannot submit "
-      << "a non-existent file.";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
-    this->ArgumentDoing = ArgumentDoingError;
     return false;
-  }
+  });
+}
 
-  // Look for other arguments.
-  return this->Superclass::CheckArgumentValue(arg);
+cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
+{
+  cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
+  handler->Initialize();
+  handler->SetFiles(
+    std::set<std::string>(this->Files.begin(), this->Files.end()));
+  handler->SetQuiet(this->Quiet);
+  return handler;
 }

+ 4 - 14
Source/CTest/cmCTestUploadCommand.h

@@ -8,9 +8,9 @@
 #include "cmCTestHandlerCommand.h"
 #include "cmCommand.h"
 
-#include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "cm_memory.hxx"
 
@@ -41,22 +41,12 @@ public:
    */
   std::string GetName() const override { return "ctest_upload"; }
 
-  using Superclass = cmCTestHandlerCommand;
-
 protected:
+  void BindArguments() override;
+  void CheckArguments(std::vector<std::string> const&) override;
   cmCTestGenericHandler* InitializeHandler() override;
 
-  bool CheckArgumentKeyword(std::string const& arg) override;
-  bool CheckArgumentValue(std::string const& arg) override;
-
-  enum
-  {
-    ArgumentDoingFiles = Superclass::ArgumentDoingLast1,
-    ArgumentDoingCaptureCMakeError,
-    ArgumentDoingLast2
-  };
-
-  std::set<std::string> Files;
+  std::vector<std::string> Files;
 };
 
 #endif