Преглед изворни кода

Merge topic 'string-prefix'

ec7928ef26 use _s to construct static string_views at several places
94de927cab VS10Generator: avoid many string allocations
8ca2504a4d use string_views to avoid memory allocations
761f1adcae check for a valid URL scheme before starting to do any splitting
ef778d77e0 replace std::string::substr() with operations that do not allocate memory
77616f4681 pass cm::string_view to cmVisualStudioSlnParser::ParseTag()
ada6a3226f use cm::string_view for language extension lookups
48adc29721 replace "std::string::find(x) == 0" with cmHasPrefix()
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4501
Brad King пре 5 година
родитељ
комит
577fc3ef19
62 измењених фајлова са 493 додато и 515 уклоњено
  1. 2 8
      Source/CPack/IFW/cmCPackIFWGenerator.cxx
  2. 1 2
      Source/CPack/IFW/cmCPackIFWPackage.cxx
  3. 7 8
      Source/CPack/WiX/cmCPackWIXGenerator.cxx
  4. 9 6
      Source/CPack/WiX/cmWIXAccessControlList.cxx
  5. 7 8
      Source/CPack/cmCPackNSISGenerator.cxx
  6. 3 2
      Source/CPack/cmCPackNSISGenerator.h
  7. 1 1
      Source/CPack/cpack.cxx
  8. 19 13
      Source/CTest/cmCTestBuildAndTestHandler.cxx
  9. 8 12
      Source/CTest/cmCTestBuildHandler.cxx
  10. 21 23
      Source/CTest/cmCTestCoverageHandler.cxx
  11. 3 1
      Source/CTest/cmCTestGIT.cxx
  12. 3 1
      Source/CTest/cmCTestScriptHandler.cxx
  13. 7 6
      Source/CTest/cmCTestSubmitHandler.cxx
  14. 38 61
      Source/CTest/cmCTestTestHandler.cxx
  15. 1 1
      Source/CTest/cmCTestTestHandler.h
  16. 2 2
      Source/CTest/cmParseCacheCoverage.cxx
  17. 1 1
      Source/CTest/cmParseCacheCoverage.h
  18. 1 1
      Source/CTest/cmParseCoberturaCoverage.cxx
  19. 1 1
      Source/CTest/cmParseGTMCoverage.cxx
  20. 1 1
      Source/CTest/cmParseGTMCoverage.h
  21. 5 4
      Source/CTest/cmParseMumpsCoverage.cxx
  22. 2 2
      Source/CTest/cmParseMumpsCoverage.h
  23. 3 2
      Source/CursesDialog/ccmake.cxx
  24. 3 3
      Source/bindexplib.cxx
  25. 4 1
      Source/cmAddSubDirectoryCommand.cxx
  26. 4 3
      Source/cmAuxSourceDirectoryCommand.cxx
  27. 9 6
      Source/cmBinUtilsLinuxELFLinker.cxx
  28. 100 108
      Source/cmCTest.cxx
  29. 6 3
      Source/cmCTest.h
  30. 3 1
      Source/cmCacheManager.cxx
  31. 12 11
      Source/cmComputeLinkInformation.cxx
  32. 2 2
      Source/cmConditionEvaluator.cxx
  33. 4 4
      Source/cmDependsC.cxx
  34. 2 2
      Source/cmExportBuildAndroidMKGenerator.cxx
  35. 3 3
      Source/cmExportTryCompileFileGenerator.cxx
  36. 4 4
      Source/cmExtraCodeBlocksGenerator.cxx
  37. 3 3
      Source/cmExtraEclipseCDT4Generator.cxx
  38. 3 3
      Source/cmExtraKateGenerator.cxx
  39. 3 3
      Source/cmExtraSublimeTextGenerator.cxx
  40. 2 2
      Source/cmGeneratorExpressionDAGChecker.cxx
  41. 2 2
      Source/cmGeneratorTarget.cxx
  42. 2 1
      Source/cmGlobalVisualStudio10Generator.cxx
  43. 3 3
      Source/cmGlobalVisualStudio7Generator.cxx
  44. 3 2
      Source/cmGlobalXCodeGenerator.cxx
  45. 3 3
      Source/cmGraphVizWriter.cxx
  46. 2 1
      Source/cmJsonObjects.cxx
  47. 1 1
      Source/cmLocalUnixMakefileGenerator3.cxx
  48. 2 1
      Source/cmLocalVisualStudio7Generator.cxx
  49. 1 1
      Source/cmMakefile.cxx
  50. 5 3
      Source/cmRST.cxx
  51. 1 1
      Source/cmRuntimeDependencyArchive.cxx
  52. 3 1
      Source/cmSourceFileLocation.cxx
  53. 1 2
      Source/cmSystemTools.cxx
  54. 45 54
      Source/cmVisualStudio10TargetGenerator.cxx
  55. 0 2
      Source/cmVisualStudio10TargetGenerator.h
  56. 5 5
      Source/cmVisualStudioSlnParser.cxx
  57. 3 2
      Source/cmVisualStudioSlnParser.h
  58. 56 54
      Source/cmake.cxx
  59. 8 6
      Source/cmake.h
  60. 26 32
      Source/cmcldeps.cxx
  61. 5 6
      Source/cmcmd.cxx
  62. 3 3
      Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp

+ 2 - 8
Source/CPack/IFW/cmCPackIFWGenerator.cxx

@@ -544,10 +544,7 @@ std::string cmCPackIFWGenerator::GetGroupPackageName(
   if (group->ParentGroup) {
     cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup);
     bool dot = !this->ResolveDuplicateNames;
-    if (dot && name.substr(0, package->Name.size()) == package->Name) {
-      dot = false;
-    }
-    if (dot) {
+    if (dot && !cmHasPrefix(name, package->Name)) {
       name = package->Name + "." + name;
     }
   }
@@ -576,10 +573,7 @@ std::string cmCPackIFWGenerator::GetComponentPackageName(
       return package->Name;
     }
     bool dot = !this->ResolveDuplicateNames;
-    if (dot && name.substr(0, package->Name.size()) == package->Name) {
-      dot = false;
-    }
-    if (dot) {
+    if (dot && !cmHasPrefix(name, package->Name)) {
       name = package->Name + "." + name;
     }
   }

+ 1 - 2
Source/CPack/IFW/cmCPackIFWPackage.cxx

@@ -55,8 +55,7 @@ cmCPackIFWPackage::DependenceStruct::DependenceStruct(
   if (dashPos != std::string::npos) {
     pos = dashPos;
   }
-  this->Name =
-    pos == std::string::npos ? dependence : dependence.substr(0, pos);
+  this->Name = dependence.substr(0, pos);
 }
 
 std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const

+ 7 - 8
Source/CPack/WiX/cmCPackWIXGenerator.cxx

@@ -98,7 +98,7 @@ bool cmCPackWIXGenerator::RunCandleCommand(std::string const& sourceFile,
     command << " -ext " << QuotePath(ext);
   }
 
-  if (sourceFile.rfind(this->CPackTopLevel, 0) != 0) {
+  if (!cmHasSuffix(sourceFile, this->CPackTopLevel)) {
     command << " " << QuotePath("-I" + this->CPackTopLevel);
   }
 
@@ -350,8 +350,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
   std::vector<std::string> options = GetOptions();
 
   for (std::string const& name : options) {
-    if (name.length() > prefix.length() &&
-        name.substr(0, prefix.length()) == prefix) {
+    if (cmHasPrefix(name, prefix)) {
       std::string id = name.substr(prefix.length());
       std::string value = GetOption(name.c_str());
 
@@ -1099,14 +1098,14 @@ std::string cmCPackWIXGenerator::CreateHashedId(
   cmCryptoHash sha1(cmCryptoHash::AlgoSHA1);
   std::string const hash = sha1.HashString(path);
 
-  std::string identifier = cmStrCat(cm::string_view(hash).substr(0, 7), '_');
-
   const size_t maxFileNameLength = 52;
+  std::string identifier =
+    cmStrCat(cm::string_view(hash).substr(0, 7), '_',
+             cm::string_view(normalizedFilename).substr(0, maxFileNameLength));
+
+  // if the name was truncated
   if (normalizedFilename.length() > maxFileNameLength) {
-    identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
     identifier += "...";
-  } else {
-    identifier += normalizedFilename;
   }
 
   return identifier;

+ 9 - 6
Source/CPack/WiX/cmWIXAccessControlList.cxx

@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmWIXAccessControlList.h"
 
+#include <cm/string_view>
+
 #include "cmCPackGenerator.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -35,12 +37,13 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry)
     return;
   }
 
-  std::string user_and_domain = entry.substr(0, pos);
-  std::string permission_string = entry.substr(pos + 1);
+  cm::string_view enview(entry);
+  cm::string_view user_and_domain = enview.substr(0, pos);
+  cm::string_view permission_string = enview.substr(pos + 1);
 
   pos = user_and_domain.find('@');
-  std::string user;
-  std::string domain;
+  cm::string_view user;
+  cm::string_view domain;
   if (pos != std::string::npos) {
     user = user_and_domain.substr(0, pos);
     domain = user_and_domain.substr(pos + 1);
@@ -51,9 +54,9 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry)
   std::vector<std::string> permissions = cmTokenize(permission_string, ",");
 
   this->SourceWriter.BeginElement("Permission");
-  this->SourceWriter.AddAttribute("User", user);
+  this->SourceWriter.AddAttribute("User", std::string(user));
   if (!domain.empty()) {
-    this->SourceWriter.AddAttribute("Domain", domain);
+    this->SourceWriter.AddAttribute("Domain", std::string(domain));
   }
   for (std::string const& permission : permissions) {
     this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission));

+ 7 - 8
Source/CPack/cmCPackNSISGenerator.cxx

@@ -68,7 +68,7 @@ int cmCPackNSISGenerator::PackageFiles()
 
       // Use the custom component install directory if we have one
       if (pos != std::string::npos) {
-        const std::string componentName = fileN.substr(0, pos);
+        auto componentName = cm::string_view(fileN).substr(0, pos);
         outputDir = CustomComponentInstallDirectory(componentName);
       } else {
         outputDir = CustomComponentInstallDirectory(fileN);
@@ -103,7 +103,7 @@ int cmCPackNSISGenerator::PackageFiles()
         componentName = fileN.substr(0, slash);
 
         // Strip off the component part of the path.
-        fileN = fileN.substr(slash + 1);
+        fileN.erase(0, slash + 1);
       }
     }
     std::replace(fileN.begin(), fileN.end(), '/', '\\');
@@ -672,7 +672,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
 
   const std::string componentOutputDir =
     CustomComponentInstallDirectory(component->Name);
-  componentCode += "  SetOutPath \"" + componentOutputDir + "\"\n";
+  componentCode += cmStrCat("  SetOutPath \"", componentOutputDir, "\"\n");
 
   // Create the actual installation commands
   if (component->IsDownloaded) {
@@ -921,12 +921,11 @@ std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
 }
 
 std::string cmCPackNSISGenerator::CustomComponentInstallDirectory(
-  const std::string& componentName)
+  cm::string_view componentName)
 {
-  const char* outputDir =
-    this->GetOption("CPACK_NSIS_" + componentName + "_INSTALL_DIRECTORY");
-  const std::string componentOutputDir = (outputDir ? outputDir : "$INSTDIR");
-  return componentOutputDir;
+  const char* outputDir = this->GetOption(
+    cmStrCat("CPACK_NSIS_", componentName, "_INSTALL_DIRECTORY"));
+  return outputDir ? outputDir : "$INSTDIR";
 }
 
 std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)

+ 3 - 2
Source/CPack/cmCPackNSISGenerator.h

@@ -10,6 +10,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmCPackGenerator.h"
 
 class cmCPackComponent;
@@ -75,8 +77,7 @@ protected:
 
   /// Returns the custom install directory if available for the specified
   /// component, otherwise $INSTDIR is returned.
-  std::string CustomComponentInstallDirectory(
-    const std::string& componentName);
+  std::string CustomComponentInstallDirectory(cm::string_view componentName);
 
   /// Translations any newlines found in the string into \\r\\n, so that the
   /// resulting string can be used within NSIS.

+ 1 - 1
Source/CPack/cpack.cxx

@@ -85,7 +85,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue,
     return 0;
   }
   std::string key = value.substr(0, pos);
-  value = value.substr(pos + 1);
+  value.erase(0, pos + 1);
   def->Map[key] = value;
   cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
               "Set CPack variable: " << key << " to \"" << value << "\""

+ 19 - 13
Source/CTest/cmCTestBuildAndTestHandler.cxx

@@ -379,7 +379,7 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
   const std::vector<std::string>& allArgs)
 {
   // --build-and-test options
-  if (currentArg.find("--build-and-test", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-and-test") &&
       idx < allArgs.size() - 1) {
     if (idx + 2 < allArgs.size()) {
       idx++;
@@ -397,25 +397,29 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
       return 0;
     }
   }
-  if (currentArg.find("--build-target", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-target") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildTargets.push_back(allArgs[idx]);
   }
-  if (currentArg.find("--build-nocmake", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-nocmake")) {
     this->BuildNoCMake = true;
   }
-  if (currentArg.find("--build-run-dir", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-run-dir") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildRunDir = allArgs[idx];
   }
-  if (currentArg.find("--build-two-config", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-two-config")) {
     this->BuildTwoConfig = true;
   }
-  if (currentArg.find("--build-exe-dir", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-exe-dir") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->ExecutableDirectory = allArgs[idx];
   }
-  if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--test-timeout") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->Timeout = cmDuration(atof(allArgs[idx].c_str()));
   }
@@ -431,31 +435,33 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
     idx++;
     this->BuildGeneratorToolset = allArgs[idx];
   }
-  if (currentArg.find("--build-project", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-project") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildProject = allArgs[idx];
   }
-  if (currentArg.find("--build-makeprogram", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-makeprogram") &&
       idx < allArgs.size() - 1) {
     idx++;
     this->BuildMakeProgram = allArgs[idx];
   }
-  if (currentArg.find("--build-config-sample", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-config-sample") &&
       idx < allArgs.size() - 1) {
     idx++;
     this->ConfigSample = allArgs[idx];
   }
-  if (currentArg.find("--build-noclean", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-noclean")) {
     this->BuildNoClean = true;
   }
-  if (currentArg.find("--build-options", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-options")) {
     while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" &&
            allArgs[idx + 1] != "--test-command") {
       ++idx;
       this->BuildOptions.push_back(allArgs[idx]);
     }
   }
-  if (currentArg.find("--test-command", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--test-command") &&
+      idx < allArgs.size() - 1) {
     ++idx;
     this->TestCommand = allArgs[idx];
     while (idx + 1 < allArgs.size()) {

+ 8 - 12
Source/CTest/cmCTestBuildHandler.cxx

@@ -386,24 +386,20 @@ int cmCTestBuildHandler::ProcessHandler()
   if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
     std::string srcdir =
       this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
-    for (cc = srcdir.size() - 2; cc > 0; cc--) {
-      if (srcdir[cc] == '/') {
-        srcdir = srcdir.substr(0, cc + 1);
-        break;
-      }
+    cc = srcdir.rfind('/', srcdir.size() - 2);
+    if (cc != std::string::npos) {
+      srcdir.resize(cc + 1);
+      this->SimplifySourceDir = std::move(srcdir);
     }
-    this->SimplifySourceDir = srcdir;
   }
   if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
     std::string bindir =
       this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
-    for (cc = bindir.size() - 2; cc > 0; cc--) {
-      if (bindir[cc] == '/') {
-        bindir = bindir.substr(0, cc + 1);
-        break;
-      }
+    cc = bindir.rfind('/', bindir.size() - 2);
+    if (cc != std::string::npos) {
+      bindir.resize(cc + 1);
+      this->SimplifyBuildDir = std::move(bindir);
     }
-    this->SimplifyBuildDir = bindir;
   }
 
   // Ok, let's do the build

+ 21 - 23
Source/CTest/cmCTestCoverageHandler.cxx

@@ -680,8 +680,9 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf)
 //
 #ifdef _WIN32
 #  define fnc(s) cmSystemTools::LowerCase(s)
+#  define fnc_prefix(s, t) fnc(s.substr(0, t.size())) == fnc(t)
 #else
-#  define fnc(s) s
+#  define fnc_prefix(s, t) cmHasPrefix(s, t)
 #endif
 
 bool IsFileInDir(const std::string& infile, const std::string& indir)
@@ -689,8 +690,8 @@ bool IsFileInDir(const std::string& infile, const std::string& indir)
   std::string file = cmSystemTools::CollapseFullPath(infile);
   std::string dir = cmSystemTools::CollapseFullPath(indir);
 
-  return file.size() > dir.size() &&
-    fnc(file.substr(0, dir.size())) == fnc(dir) && file[dir.size()] == '/';
+  return file.size() > dir.size() && fnc_prefix(file, dir) &&
+    file[dir.size()] == '/';
 }
 
 int cmCTestCoverageHandler::HandlePHPCoverage(
@@ -1709,29 +1710,26 @@ int cmCTestCoverageHandler::HandleTracePyCoverage(
 
         // Read the coverage count from the beginning of the Trace.py output
         // line
-        std::string prefix = nl.substr(0, 6);
-        if (prefix[5] != ' ' && prefix[5] != ':') {
-          // This is a hack. We should really do something more elaborate
-          prefix = nl.substr(0, 7);
-          if (prefix[6] != ' ' && prefix[6] != ':') {
-            prefix = nl.substr(0, 8);
-            if (prefix[7] != ' ' && prefix[7] != ':') {
-              cmCTestLog(this->CTest, ERROR_MESSAGE,
-                         "Currently the limit is maximum coverage of 999999"
-                           << std::endl);
-            }
+        std::string::size_type pos;
+        int cov = 0;
+        // This is a hack. We should really do something more elaborate
+        for (pos = 5; pos < 8; pos++) {
+          if (nl[pos] == ' ') {
+            // This line does not have ':' so no coverage here. That said,
+            // Trace.py does not handle not covered lines versus comments etc.
+            // So, this will be set to 0.
+            break;
+          }
+          if (nl[pos] == ':') {
+            cov = atoi(nl.substr(0, pos - 1).c_str());
+            break;
           }
         }
-        int cov = atoi(prefix.c_str());
-        if (prefix[prefix.size() - 1] != ':') {
-          // This line does not have ':' so no coverage here. That said,
-          // Trace.py does not handle not covered lines versus comments etc.
-          // So, this will be set to 0.
-          cov = 0;
+        if (pos == 8) {
+          cmCTestLog(this->CTest, ERROR_MESSAGE,
+                     "Currently the limit is maximum coverage of 999999"
+                       << std::endl);
         }
-        cmCTestOptionalLog(
-          this->CTest, DEBUG,
-          "Prefix: " << prefix << " cov: " << cov << std::endl, this->Quiet);
         // Read the line number starting at the 10th character of the gcov
         // output line
         long lineIdx = cnt;

+ 3 - 1
Source/CTest/cmCTestGIT.cxx

@@ -6,6 +6,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <ctime>
+#include <utility>
 #include <vector>
 
 #include "cmsys/FStream.hxx"
@@ -193,7 +194,8 @@ bool cmCTestGIT::UpdateByFetchAndReset()
       if (line.find("\tnot-for-merge\t") == std::string::npos) {
         std::string::size_type pos = line.find('\t');
         if (pos != std::string::npos) {
-          sha1 = line.substr(0, pos);
+          sha1 = std::move(line);
+          sha1.resize(pos);
         }
       }
     }

+ 3 - 1
Source/CTest/cmCTestScriptHandler.cxx

@@ -284,12 +284,14 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
   // if the argument has a , in it then it needs to be broken into the fist
   // argument (which is the script) and the second argument which will be
   // passed into the scripts as S_ARG
-  std::string script = total_script_arg;
+  std::string script;
   std::string script_arg;
   const std::string::size_type comma_pos = total_script_arg.find(',');
   if (comma_pos != std::string::npos) {
     script = total_script_arg.substr(0, comma_pos);
     script_arg = total_script_arg.substr(comma_pos + 1);
+  } else {
+    script = total_script_arg;
   }
   // make sure the file exists
   if (!cmSystemTools::FileExists(script)) {

+ 7 - 6
Source/CTest/cmCTestSubmitHandler.cxx

@@ -506,18 +506,19 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
   curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
   curl.SetHttpHeaders(this->HttpHeaders);
   std::string url = this->CTest->GetSubmitURL();
-  std::string fields;
-  std::string::size_type pos = url.find('?');
-  if (pos != std::string::npos) {
-    fields = url.substr(pos + 1);
-    url = url.substr(0, pos);
-  }
   if (!cmHasLiteralPrefix(url, "http://") &&
       !cmHasLiteralPrefix(url, "https://")) {
     cmCTestLog(this->CTest, ERROR_MESSAGE,
                "Only http and https are supported for CDASH_UPLOAD\n");
     return -1;
   }
+
+  std::string fields;
+  std::string::size_type pos = url.find('?');
+  if (pos != std::string::npos) {
+    fields = url.substr(pos + 1);
+    url.erase(pos);
+  }
   bool internalTest = cmIsOn(this->GetOption("InternalTest"));
 
   // Get RETRY_COUNT and RETRY_DELAY values if they were set.

+ 38 - 61
Source/CTest/cmCTestTestHandler.cxx

@@ -18,12 +18,14 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 
 #include "cmsys/FStream.hxx"
 #include <cmsys/Base64.h>
 #include <cmsys/Directory.hxx>
 #include <cmsys/RegularExpression.hxx>
 
+#include "cm_static_string_view.hxx"
 #include "cm_utf8.h"
 
 #include "cmAlgorithms.h"
@@ -1893,7 +1895,8 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
         continue;
       }
 
-      int val = atoi(line.substr(0, pos).c_str());
+      line.erase(pos);
+      int val = atoi(line.c_str());
       this->TestsToRun.push_back(val);
     }
     ifs.close();
@@ -2089,11 +2092,11 @@ void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
   }
 }
 
-bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
+void cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
 {
   if (!length || length >= output.size() ||
       output.find("CTEST_FULL_OUTPUT") != std::string::npos) {
-    return true;
+    return;
   }
 
   // Truncate at given length but do not break in the middle of a multi-byte
@@ -2114,7 +2117,7 @@ bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
       ++current;
     }
   }
-  output = output.substr(0, current - begin);
+  output.erase(current - begin);
 
   // Append truncation message.
   std::ostringstream msg;
@@ -2124,7 +2127,6 @@ bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
          "of "
       << length << " bytes.\n";
   output += msg.str();
-  return true;
 }
 
 bool cmCTestTestHandler::SetTestsProperties(
@@ -2145,16 +2147,16 @@ bool cmCTestTestHandler::SetTestsProperties(
   }
   ++it; // skip PROPERTIES
   for (; it != args.end(); ++it) {
-    std::string key = *it;
+    std::string const& key = *it;
     ++it;
     if (it == args.end()) {
       break;
     }
-    std::string val = *it;
+    std::string const& val = *it;
     for (std::string const& t : tests) {
       for (cmCTestTestProperties& rt : this->TestList) {
         if (t == rt.Name) {
-          if (key == "_BACKTRACE_TRIPLES") {
+          if (key == "_BACKTRACE_TRIPLES"_s) {
             std::vector<std::string> triples;
             // allow empty args in the triples
             cmExpandList(val, triples, true);
@@ -2178,91 +2180,70 @@ bool cmCTestTestHandler::SetTestsProperties(
                 rt.Backtrace = rt.Backtrace.Push(fc);
               }
             }
-          }
-          if (key == "WILL_FAIL") {
+          } else if (key == "WILL_FAIL"_s) {
             rt.WillFail = cmIsOn(val);
-          }
-          if (key == "DISABLED") {
+          } else if (key == "DISABLED"_s) {
             rt.Disabled = cmIsOn(val);
-          }
-          if (key == "ATTACHED_FILES") {
+          } else if (key == "ATTACHED_FILES"_s) {
             cmExpandList(val, rt.AttachedFiles);
-          }
-          if (key == "ATTACHED_FILES_ON_FAIL") {
+          } else if (key == "ATTACHED_FILES_ON_FAIL"_s) {
             cmExpandList(val, rt.AttachOnFail);
-          }
-          if (key == "RESOURCE_LOCK") {
+          } else if (key == "RESOURCE_LOCK"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.LockedResources.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_SETUP") {
+          } else if (key == "FIXTURES_SETUP"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesSetup.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_CLEANUP") {
+          } else if (key == "FIXTURES_CLEANUP"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesCleanup.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_REQUIRED") {
+          } else if (key == "FIXTURES_REQUIRED"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesRequired.insert(lval.begin(), lval.end());
-          }
-          if (key == "TIMEOUT") {
+          } else if (key == "TIMEOUT"_s) {
             rt.Timeout = cmDuration(atof(val.c_str()));
             rt.ExplicitTimeout = true;
-          }
-          if (key == "COST") {
+          } else if (key == "COST"_s) {
             rt.Cost = static_cast<float>(atof(val.c_str()));
-          }
-          if (key == "REQUIRED_FILES") {
+          } else if (key == "REQUIRED_FILES"_s) {
             cmExpandList(val, rt.RequiredFiles);
-          }
-          if (key == "RUN_SERIAL") {
+          } else if (key == "RUN_SERIAL"_s) {
             rt.RunSerial = cmIsOn(val);
-          }
-          if (key == "FAIL_REGULAR_EXPRESSION") {
+          } else if (key == "FAIL_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.ErrorRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "SKIP_REGULAR_EXPRESSION") {
+          } else if (key == "SKIP_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.SkipRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "PROCESSORS") {
+          } else if (key == "PROCESSORS"_s) {
             rt.Processors = atoi(val.c_str());
             if (rt.Processors < 1) {
               rt.Processors = 1;
             }
-          }
-          if (key == "PROCESSOR_AFFINITY") {
+          } else if (key == "PROCESSOR_AFFINITY"_s) {
             rt.WantAffinity = cmIsOn(val);
-          }
-          if (key == "RESOURCE_GROUPS") {
+          } else if (key == "RESOURCE_GROUPS"_s) {
             if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) {
               return false;
             }
-          }
-          if (key == "SKIP_RETURN_CODE") {
+          } else if (key == "SKIP_RETURN_CODE"_s) {
             rt.SkipReturnCode = atoi(val.c_str());
             if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) {
               rt.SkipReturnCode = -1;
             }
-          }
-          if (key == "DEPENDS") {
+          } else if (key == "DEPENDS"_s) {
             cmExpandList(val, rt.Depends);
-          }
-          if (key == "ENVIRONMENT") {
+          } else if (key == "ENVIRONMENT"_s) {
             cmExpandList(val, rt.Environment);
-          }
-          if (key == "LABELS") {
+          } else if (key == "LABELS"_s) {
             std::vector<std::string> Labels = cmExpandedList(val);
             rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
             // sort the array
@@ -2270,8 +2251,7 @@ bool cmCTestTestHandler::SetTestsProperties(
             // remove duplicates
             auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end());
             rt.Labels.erase(new_end, rt.Labels.end());
-          }
-          if (key == "MEASUREMENT") {
+          } else if (key == "MEASUREMENT"_s) {
             size_t pos = val.find_first_of('=');
             if (pos != std::string::npos) {
               std::string mKey = val.substr(0, pos);
@@ -2280,17 +2260,14 @@ bool cmCTestTestHandler::SetTestsProperties(
             } else {
               rt.Measurements[val] = "1";
             }
-          }
-          if (key == "PASS_REGULAR_EXPRESSION") {
+          } else if (key == "PASS_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.RequiredRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "WORKING_DIRECTORY") {
+          } else if (key == "WORKING_DIRECTORY"_s) {
             rt.Directory = val;
-          }
-          if (key == "TIMEOUT_AFTER_MATCH") {
+          } else if (key == "TIMEOUT_AFTER_MATCH"_s) {
             std::vector<std::string> propArgs = cmExpandedList(val);
             if (propArgs.size() != 2) {
               cmCTestLog(this->CTest, WARNING,
@@ -2330,16 +2307,16 @@ bool cmCTestTestHandler::SetDirectoryProperties(
   }
   ++it; // skip PROPERTIES
   for (; it != args.end(); ++it) {
-    std::string key = *it;
+    std::string const& key = *it;
     ++it;
     if (it == args.end()) {
       break;
     }
-    std::string val = *it;
+    std::string const& val = *it;
     for (cmCTestTestProperties& rt : this->TestList) {
       std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
       if (cwd == rt.Directory) {
-        if (key == "LABELS") {
+        if (key == "LABELS"_s) {
           std::vector<std::string> DirectoryLabels = cmExpandedList(val);
           rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(),
                            DirectoryLabels.end());

+ 1 - 1
Source/CTest/cmCTestTestHandler.h

@@ -235,7 +235,7 @@ protected:
   void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result);
 
   //! Clean test output to specified length
-  bool CleanTestOutput(std::string& output, size_t length);
+  void CleanTestOutput(std::string& output, size_t length);
 
   cmDuration ElapsedTestingTime;
 

+ 2 - 2
Source/CTest/cmParseCacheCoverage.cxx

@@ -19,7 +19,7 @@ cmParseCacheCoverage::cmParseCacheCoverage(
 {
 }
 
-bool cmParseCacheCoverage::LoadCoverageData(const char* d)
+bool cmParseCacheCoverage::LoadCoverageData(std::string const& d)
 {
   // load all the .mcov files in the specified directory
   cmsys::Directory dir;
@@ -155,7 +155,7 @@ bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
     // if we have a routine name, check for end of routine
     else {
       // Totals in arg 0 marks the end of a routine
-      if (separateLine[0].substr(0, 6) == "Totals") {
+      if (cmHasLiteralPrefix(separateLine[0], "Totals")) {
         routine.clear(); // at the end of this routine
         filepath.clear();
         continue; // move to next line

+ 1 - 1
Source/CTest/cmParseCacheCoverage.h

@@ -26,7 +26,7 @@ public:
 
 protected:
   // implement virtual from parent
-  bool LoadCoverageData(const char* dir) override;
+  bool LoadCoverageData(std::string const& dir) override;
   // remove files with no coverage
   void RemoveUnCoveredFiles();
   // Read a single mcov file

+ 1 - 1
Source/CTest/cmParseCoberturaCoverage.cxx

@@ -67,7 +67,7 @@ protected:
           // Check if this is an absolute path that falls within our
           // source or binary directories.
           for (std::string const& filePath : FilePaths) {
-            if (filename.find(filePath) == 0) {
+            if (cmHasPrefix(filename, filePath)) {
               this->CurFileName = filename;
               break;
             }

+ 1 - 1
Source/CTest/cmParseGTMCoverage.cxx

@@ -19,7 +19,7 @@ cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
 {
 }
 
-bool cmParseGTMCoverage::LoadCoverageData(const char* d)
+bool cmParseGTMCoverage::LoadCoverageData(std::string const& d)
 {
   // load all the .mcov files in the specified directory
   cmsys::Directory dir;

+ 1 - 1
Source/CTest/cmParseGTMCoverage.h

@@ -25,7 +25,7 @@ public:
 
 protected:
   // implement virtual from parent
-  bool LoadCoverageData(const char* dir) override;
+  bool LoadCoverageData(std::string const& dir) override;
   // Read a single mcov file
   bool ReadMCovFile(const char* f);
   // find out what line in a mumps file (filepath) the given entry point

+ 5 - 4
Source/CTest/cmParseMumpsCoverage.cxx

@@ -39,9 +39,9 @@ bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
       std::string type = line.substr(0, pos);
       std::string path = line.substr(pos + 1);
       if (type == "packages") {
-        this->LoadPackages(path.c_str());
+        this->LoadPackages(path);
       } else if (type == "coverage_dir") {
-        this->LoadCoverageData(path.c_str());
+        this->LoadCoverageData(path);
       } else {
         cmCTestLog(this->CTest, ERROR_MESSAGE,
                    "Parse Error in Mumps coverage file :\n"
@@ -105,7 +105,7 @@ void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
   }
 }
 
-bool cmParseMumpsCoverage::LoadPackages(const char* d)
+bool cmParseMumpsCoverage::LoadPackages(std::string const& d)
 {
   cmsys::Glob glob;
   glob.RecurseOn();
@@ -113,7 +113,8 @@ bool cmParseMumpsCoverage::LoadPackages(const char* d)
   glob.FindFiles(pat);
   for (std::string& file : glob.GetFiles()) {
     std::string name = cmSystemTools::GetFilenameName(file);
-    this->RoutineToDirectory[name.substr(0, name.size() - 2)] = file;
+    name.erase(name.size() - 2);
+    this->RoutineToDirectory[name] = file;
     // initialize each file, this is left out until CDash is fixed
     // to handle large numbers of files
     this->InitializeMumpsFile(file);

+ 2 - 2
Source/CTest/cmParseMumpsCoverage.h

@@ -29,10 +29,10 @@ public:
 protected:
   // sub classes will use this to
   // load all coverage files found in the given directory
-  virtual bool LoadCoverageData(const char* d) = 0;
+  virtual bool LoadCoverageData(std::string const& d) = 0;
   // search the package directory for mumps files and fill
   // in the RoutineToDirectory map
-  bool LoadPackages(const char* dir);
+  bool LoadPackages(std::string const& dir);
   // initialize the coverage information for a single mumps file
   void InitializeMumpsFile(std::string& file);
   // Find mumps file for routine

+ 3 - 2
Source/CursesDialog/ccmake.cxx

@@ -16,6 +16,7 @@
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmState.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -111,8 +112,8 @@ int main(int argc, char const* const* argv)
 
   std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
   for (i = 1; i < args.size(); ++i) {
-    std::string arg = args[i];
-    if (arg.find("-B", 0) == 0) {
+    std::string const& arg = args[i];
+    if (cmHasPrefix(arg, "-B")) {
       cacheDir = arg.substr(2);
     }
   }

+ 3 - 3
Source/bindexplib.cxx

@@ -352,14 +352,14 @@ bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename,
               line.c_str());
       return false;
     }
-    const std::string sym = line.substr(0, sym_end);
     const char sym_type = line[sym_end + 1];
+    line.resize(sym_end);
     switch (sym_type) {
       case 'D':
-        dataSymbols.insert(sym);
+        dataSymbols.insert(line);
         break;
       case 'T':
-        symbols.insert(sym);
+        symbols.insert(line);
         break;
     }
   }

+ 4 - 1
Source/cmAddSubDirectoryCommand.cxx

@@ -4,6 +4,8 @@
 
 #include <cstring>
 
+#include <cm/string_view>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
@@ -86,7 +88,8 @@ bool cmAddSubDirectoryCommand(std::vector<std::string> const& args,
     if (binLen > 0 && bin.back() == '/') {
       --binLen;
     }
-    binPath = bin.substr(0, binLen) + srcPath.substr(srcLen);
+    binPath = cmStrCat(cm::string_view(bin).substr(0, binLen),
+                       cm::string_view(srcPath).substr(srcLen));
   } else {
     // Use the binary directory specified.
     // Interpret a relative path with respect to the current binary directory.

+ 4 - 3
Source/cmAuxSourceDirectoryCommand.cxx

@@ -6,6 +6,8 @@
 #include <cstddef>
 #include <utility>
 
+#include <cm/string_view>
+
 #include "cmsys/Directory.hxx"
 
 #include "cmExecutionStatus.h"
@@ -50,11 +52,10 @@ bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args,
       // Split the filename into base and extension
       std::string::size_type dotpos = file.rfind('.');
       if (dotpos != std::string::npos) {
-        std::string ext = file.substr(dotpos + 1);
-        std::string base = file.substr(0, dotpos);
+        auto ext = cm::string_view(file).substr(dotpos + 1);
         // Process only source files
         auto cm = mf.GetCMakeInstance();
-        if (!base.empty() && cm->IsSourceExtension(ext)) {
+        if (dotpos > 0 && cm->IsSourceExtension(ext)) {
           std::string fullname = cmStrCat(templateDirectory, '/', file);
           // add the file as a class file so
           // depends can be done

+ 9 - 6
Source/cmBinUtilsLinuxELFLinker.cxx

@@ -6,6 +6,7 @@
 #include <sstream>
 
 #include <cm/memory>
+#include <cm/string_view>
 
 #include <cmsys/RegularExpression.hxx>
 
@@ -26,14 +27,16 @@ static std::string ReplaceOrigin(const std::string& rpath,
 
   cmsys::RegularExpressionMatch match;
   if (originRegex.find(rpath.c_str(), match)) {
-    std::string begin = rpath.substr(0, match.start(1));
-    std::string end = rpath.substr(match.end(1));
-    return begin + origin + end;
+    cm::string_view pathv(rpath);
+    auto begin = pathv.substr(0, match.start(1));
+    auto end = pathv.substr(match.end(1));
+    return cmStrCat(begin, origin, end);
   }
   if (originCurlyRegex.find(rpath.c_str(), match)) {
-    std::string begin = rpath.substr(0, match.start());
-    std::string end = rpath.substr(match.end());
-    return begin + origin + end;
+    cm::string_view pathv(rpath);
+    auto begin = pathv.substr(0, match.start());
+    auto end = pathv.substr(match.end());
+    return cmStrCat(begin, origin, end);
   }
   return rpath;
 }

+ 100 - 108
Source/cmCTest.cxx

@@ -17,6 +17,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
 
 #include "cmsys/Base64.h"
@@ -35,6 +36,8 @@
 #  include <unistd.h> // IWYU pragma: keep
 #endif
 
+#include "cm_static_string_view.hxx"
+
 #include "cmCTestBuildAndTestHandler.h"
 #include "cmCTestBuildHandler.h"
 #include "cmCTestConfigureHandler.h"
@@ -271,9 +274,10 @@ bool cmCTest::GetTomorrowTag() const
   return this->Impl->TomorrowTag;
 }
 
-std::string cmCTest::CleanString(const std::string& str)
+std::string cmCTest::CleanString(const std::string& str,
+                                 std::string::size_type spos)
 {
-  std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
+  spos = str.find_first_not_of(" \n\t\r\f\v", spos);
   std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
   if (spos == std::string::npos) {
     return std::string();
@@ -724,7 +728,7 @@ bool cmCTest::UpdateCTestConfiguration()
         continue;
       }
       while (fin && (line.back() == '\\')) {
-        line = line.substr(0, line.size() - 1);
+        line.resize(line.size() - 1);
         buffer[0] = 0;
         fin.getline(buffer, 1023);
         buffer[1023] = 0;
@@ -738,7 +742,7 @@ bool cmCTest::UpdateCTestConfiguration()
         continue;
       }
       std::string key = line.substr(0, cpos);
-      std::string value = cmCTest::CleanString(line.substr(cpos + 1));
+      std::string value = cmCTest::CleanString(line, cpos + 1);
       this->Impl->CTestConfiguration[key] = value;
     }
     fin.close();
@@ -1813,10 +1817,10 @@ void cmCTest::ErrorMessageUnknownDashDValue(std::string& val)
       << "  ctest -D NightlyMemoryCheck" << std::endl);
 }
 
-bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
+bool cmCTest::CheckArgument(const std::string& arg, cm::string_view varg1,
                             const char* varg2)
 {
-  return (varg1 && arg == varg1) || (varg2 && arg == varg2);
+  return (arg == varg1) || (varg2 && arg == varg2);
 }
 
 // Processes one command line argument (and its arguments if any)
@@ -1826,21 +1830,21 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
                                          std::string& errormsg)
 {
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-F")) {
+  if (this->CheckArgument(arg, "-F"_s)) {
     this->Impl->Failover = true;
-  }
-  if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-j"_s, "--parallel") &&
+             i < args.size() - 1) {
     i++;
     int plevel = atoi(args[i].c_str());
     this->SetParallelLevel(plevel);
     this->Impl->ParallelLevelSetInCli = true;
-  } else if (arg.find("-j") == 0) {
+  } else if (cmHasPrefix(arg, "-j")) {
     int plevel = atoi(arg.substr(2).c_str());
     this->SetParallelLevel(plevel);
     this->Impl->ParallelLevelSetInCli = true;
   }
 
-  if (this->CheckArgument(arg, "--repeat-until-fail")) {
+  else if (this->CheckArgument(arg, "--repeat-until-fail"_s)) {
     if (i >= args.size() - 1) {
       errormsg = "'--repeat-until-fail' requires an argument";
       return false;
@@ -1852,8 +1856,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     i++;
     long repeat = 1;
     if (!cmStrToLong(args[i], &repeat)) {
-      errormsg =
-        "'--repeat-until-fail' given non-integer value '" + args[i] + "'";
+      errormsg = cmStrCat("'--repeat-until-fail' given non-integer value '",
+                          args[i], "'");
       return false;
     }
     this->Impl->RepeatCount = static_cast<int>(repeat);
@@ -1862,7 +1866,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     }
   }
 
-  if (this->CheckArgument(arg, "--repeat")) {
+  else if (this->CheckArgument(arg, "--repeat"_s)) {
     if (i >= args.size() - 1) {
       errormsg = "'--repeat' requires an argument";
       return false;
@@ -1890,12 +1894,12 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
         }
       }
     } else {
-      errormsg = "'--repeat' given invalid value '" + args[i] + "'";
+      errormsg = cmStrCat("'--repeat' given invalid value '", args[i], "'");
       return false;
     }
   }
 
-  if (this->CheckArgument(arg, "--test-load") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--test-load"_s) && i < args.size() - 1) {
     i++;
     unsigned long load;
     if (cmStrToULong(args[i], &load)) {
@@ -1906,76 +1910,66 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     }
   }
 
-  if (this->CheckArgument(arg, "--no-compress-output")) {
+  else if (this->CheckArgument(arg, "--no-compress-output"_s)) {
     this->Impl->CompressTestOutput = false;
   }
 
-  if (this->CheckArgument(arg, "--print-labels")) {
+  else if (this->CheckArgument(arg, "--print-labels"_s)) {
     this->Impl->PrintLabels = true;
   }
 
-  if (this->CheckArgument(arg, "--http1.0")) {
+  else if (this->CheckArgument(arg, "--http1.0"_s)) {
     this->Impl->UseHTTP10 = true;
   }
 
-  if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--timeout"_s) && i < args.size() - 1) {
     i++;
     auto timeout = cmDuration(atof(args[i].c_str()));
     this->Impl->GlobalTimeout = timeout;
   }
 
-  if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--stop-time"_s) && i < args.size() - 1) {
     i++;
     this->SetStopTime(args[i]);
   }
 
-  if (this->CheckArgument(arg, "-C", "--build-config") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-C"_s, "--build-config") &&
+           i < args.size() - 1) {
     i++;
     this->SetConfigType(args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--debug")) {
+  else if (this->CheckArgument(arg, "--debug"_s)) {
     this->Impl->Debug = true;
     this->Impl->ShowLineNumbers = true;
-  }
-  if (this->CheckArgument(arg, "--group") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--group"_s) && i < args.size() - 1) {
     i++;
     this->Impl->SpecificGroup = args[i];
   }
   // This is an undocumented / deprecated option.
   // "Track" has been renamed to "Group".
-  if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--track"_s) && i < args.size() - 1) {
     i++;
     this->Impl->SpecificGroup = args[i];
-  }
-  if (this->CheckArgument(arg, "--show-line-numbers")) {
+  } else if (this->CheckArgument(arg, "--show-line-numbers"_s)) {
     this->Impl->ShowLineNumbers = true;
-  }
-  if (this->CheckArgument(arg, "--no-label-summary")) {
+  } else if (this->CheckArgument(arg, "--no-label-summary"_s)) {
     this->Impl->LabelSummary = false;
-  }
-  if (this->CheckArgument(arg, "--no-subproject-summary")) {
+  } else if (this->CheckArgument(arg, "--no-subproject-summary"_s)) {
     this->Impl->SubprojectSummary = false;
-  }
-  if (this->CheckArgument(arg, "-Q", "--quiet")) {
+  } else if (this->CheckArgument(arg, "-Q"_s, "--quiet")) {
     this->Impl->Quiet = true;
-  }
-  if (this->CheckArgument(arg, "--progress")) {
+  } else if (this->CheckArgument(arg, "--progress"_s)) {
     this->Impl->TestProgressOutput = true;
-  }
-  if (this->CheckArgument(arg, "-V", "--verbose")) {
+  } else if (this->CheckArgument(arg, "-V"_s, "--verbose")) {
     this->Impl->Verbose = true;
-  }
-  if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
+  } else if (this->CheckArgument(arg, "-VV"_s, "--extra-verbose")) {
     this->Impl->ExtraVerbose = true;
     this->Impl->Verbose = true;
-  }
-  if (this->CheckArgument(arg, "--output-on-failure")) {
+  } else if (this->CheckArgument(arg, "--output-on-failure"_s)) {
     this->Impl->OutputTestOutputOnTestFailure = true;
-  }
-  if (this->CheckArgument(arg, "--test-output-size-passed") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--test-output-size-passed"_s) &&
+             i < args.size() - 1) {
     i++;
     long outputSize;
     if (cmStrToLong(args[i], &outputSize)) {
@@ -1985,9 +1979,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
                  "Invalid value for '--test-output-size-passed': " << args[i]
                                                                    << "\n");
     }
-  }
-  if (this->CheckArgument(arg, "--test-output-size-failed") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--test-output-size-failed"_s) &&
+             i < args.size() - 1) {
     i++;
     long outputSize;
     if (cmStrToLong(args[i], &outputSize)) {
@@ -1997,11 +1990,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
                  "Invalid value for '--test-output-size-failed': " << args[i]
                                                                    << "\n");
     }
-  }
-  if (this->CheckArgument(arg, "-N", "--show-only")) {
+  } else if (this->CheckArgument(arg, "-N"_s, "--show-only")) {
     this->Impl->ShowOnly = true;
-  }
-  if (cmHasLiteralPrefix(arg, "--show-only=")) {
+  } else if (cmHasLiteralPrefix(arg, "--show-only=")) {
     this->Impl->ShowOnly = true;
 
     // Check if a specific format is requested. Defaults to human readable
@@ -2019,27 +2010,26 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     }
   }
 
-  if (this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-O"_s, "--output-log") &&
+           i < args.size() - 1) {
     i++;
     this->SetOutputLogFileName(args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--tomorrow-tag")) {
+  else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) {
     this->Impl->TomorrowTag = true;
-  }
-  if (this->CheckArgument(arg, "--force-new-ctest-process")) {
+  } else if (this->CheckArgument(arg, "--force-new-ctest-process"_s)) {
     this->Impl->ForceNewCTestProcess = true;
-  }
-  if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-W"_s, "--max-width") &&
+             i < args.size() - 1) {
     i++;
     this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "--interactive-debug-mode") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--interactive-debug-mode"_s) &&
+             i < args.size() - 1) {
     i++;
     this->Impl->InteractiveDebugMode = cmIsOn(args[i]);
-  }
-  if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--submit-index"_s) &&
+             i < args.size() - 1) {
     i++;
     this->Impl->SubmitIndex = atoi(args[i].c_str());
     if (this->Impl->SubmitIndex < 0) {
@@ -2047,24 +2037,27 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     }
   }
 
-  if (this->CheckArgument(arg, "--overwrite") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--overwrite"_s) && i < args.size() - 1) {
     i++;
     this->AddCTestConfigurationOverwrite(args[i]);
-  }
-  if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-A"_s, "--add-notes") &&
+             i < args.size() - 1) {
     this->Impl->ProduceXML = true;
     this->SetTest("Notes");
     i++;
     this->SetNotesFiles(args[i].c_str());
+    return true;
   }
 
-  const std::string noTestsPrefix = "--no-tests=";
+  cm::string_view noTestsPrefix = "--no-tests=";
   if (cmHasPrefix(arg, noTestsPrefix)) {
-    const std::string noTestsMode = arg.substr(noTestsPrefix.length());
+    cm::string_view noTestsMode =
+      cm::string_view(arg).substr(noTestsPrefix.length());
     if (noTestsMode == "error") {
       this->Impl->NoTestsMode = cmCTest::NoTests::Error;
     } else if (noTestsMode != "ignore") {
-      errormsg = "'--no-tests=' given unknown value '" + noTestsMode + "'";
+      errormsg =
+        cmStrCat("'--no-tests=' given unknown value '", noTestsMode, '\'');
       return false;
     } else {
       this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
@@ -2072,34 +2065,32 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
   }
 
   // options that control what tests are run
-  if (this->CheckArgument(arg, "-I", "--tests-information") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-I"_s, "--tests-information") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-U", "--union")) {
+  } else if (this->CheckArgument(arg, "-U"_s, "--union")) {
     this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
     this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
-  }
-  if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-R"_s, "--tests-regex") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeLabelRegularExpression", args[i].c_str());
@@ -2107,8 +2098,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
       "ExcludeLabelRegularExpression", args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "-E", "--exclude-regex") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
                                                 args[i].c_str());
@@ -2116,24 +2107,22 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
                                                     args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureRegularExpression", args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption(
       "ExcludeFixtureRegularExpression", args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureSetupRegularExpression", args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption(
       "ExcludeFixtureSetupRegularExpression", args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
@@ -2141,8 +2130,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
       "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--resource-spec-file") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--resource-spec-file"_s) &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("ResourceSpecFile",
                                                 args[i].c_str());
@@ -2150,7 +2139,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
                                                     args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--rerun-failed")) {
+  else if (this->CheckArgument(arg, "--rerun-failed"_s)) {
     this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
     this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
   }
@@ -2202,7 +2191,7 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
                                     bool& SRArgumentSpecified)
 {
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
+  if (this->CheckArgument(arg, "-SP"_s, "--script-new-process") &&
       i < args.size() - 1) {
     this->Impl->RunConfigurationScript = true;
     i++;
@@ -2213,7 +2202,8 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
     }
   }
 
-  if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
+  if (this->CheckArgument(arg, "-SR"_s, "--script-run") &&
+      i < args.size() - 1) {
     SRArgumentSpecified = true;
     this->Impl->RunConfigurationScript = true;
     i++;
@@ -2221,7 +2211,7 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
     ch->AddConfigurationScript(args[i].c_str(), true);
   }
 
-  if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
+  if (this->CheckArgument(arg, "-S"_s, "--script") && i < args.size() - 1) {
     this->Impl->RunConfigurationScript = true;
     i++;
     cmCTestScriptHandler* ch = this->GetScriptHandler();
@@ -2271,7 +2261,8 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
 
     // --dashboard: handle a request for a dashboard
     std::string arg = args[i];
-    if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "-D"_s, "--dashboard") &&
+        i < args.size() - 1) {
       this->Impl->ProduceXML = true;
       i++;
       std::string targ = args[i];
@@ -2307,7 +2298,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
     }
 
     // --extra-submit
-    if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "--extra-submit"_s) && i < args.size() - 1) {
       this->Impl->ProduceXML = true;
       this->SetTest("Submit");
       i++;
@@ -2317,12 +2308,13 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
     }
 
     // --build-and-test options
-    if (this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "--build-and-test"_s) &&
+        i < args.size() - 1) {
       cmakeAndTest = true;
     }
 
     // --schedule-random
-    if (this->CheckArgument(arg, "--schedule-random")) {
+    if (this->CheckArgument(arg, "--schedule-random"_s)) {
       this->Impl->ScheduleType = "Random";
     }
 
@@ -2377,7 +2369,7 @@ bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i,
 {
   bool success = true;
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-T", "--test-action") &&
+  if (this->CheckArgument(arg, "-T"_s, "--test-action") &&
       (i < args.size() - 1)) {
     this->Impl->ProduceXML = true;
     i++;
@@ -2409,15 +2401,15 @@ bool cmCTest::HandleTestModelArgument(const char* ctestExec, size_t& i,
 {
   bool success = true;
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-M", "--test-model") &&
+  if (this->CheckArgument(arg, "-M"_s, "--test-model") &&
       (i < args.size() - 1)) {
     i++;
     std::string const& str = args[i];
-    if (cmSystemTools::LowerCase(str) == "nightly") {
+    if (cmSystemTools::LowerCase(str) == "nightly"_s) {
       this->SetTestModel(cmCTest::NIGHTLY);
-    } else if (cmSystemTools::LowerCase(str) == "continuous") {
+    } else if (cmSystemTools::LowerCase(str) == "continuous"_s) {
       this->SetTestModel(cmCTest::CONTINUOUS);
-    } else if (cmSystemTools::LowerCase(str) == "experimental") {
+    } else if (cmSystemTools::LowerCase(str) == "experimental"_s) {
       this->SetTestModel(cmCTest::EXPERIMENTAL);
     } else {
       success = false;
@@ -2684,7 +2676,7 @@ std::string cmCTest::GetShortPathToFile(const char* cfname)
 
     path = "./" + *res;
     if (path.back() == '/') {
-      path = path.substr(0, path.size() - 1);
+      path.resize(path.size() - 1);
     }
   }
 
@@ -2735,7 +2727,7 @@ std::string cmCTest::GetSubmitURL()
     std::string site = this->GetCTestConfiguration("DropSite");
     std::string location = this->GetCTestConfiguration("DropLocation");
 
-    url = cmStrCat(method.empty() ? "http" : method, "://");
+    url = cmStrCat(method.empty() ? "http" : method, "://"_s);
     if (!user.empty()) {
       url += user;
       if (!password.empty()) {

+ 6 - 3
Source/cmCTest.h

@@ -13,6 +13,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmDuration.h"
 #include "cmProcessOutput.h"
 
@@ -140,7 +142,8 @@ public:
 
   std::string GetTestModelString();
   static int GetTestModelFromString(const char* str);
-  static std::string CleanString(const std::string& str);
+  static std::string CleanString(const std::string& str,
+                                 std::string::size_type spos = 0);
   std::string GetCTestConfiguration(const std::string& name);
   void SetCTestConfiguration(const char* name, const char* value,
                              bool suppress = false);
@@ -506,8 +509,8 @@ private:
                                std::vector<std::string> const& files);
 
   /** Check if the argument is the one specified */
-  bool CheckArgument(const std::string& arg, const char* varg1,
-                     const char* varg2 = nullptr);
+  static bool CheckArgument(const std::string& arg, cm::string_view varg1,
+                            const char* varg2 = nullptr);
 
   /** Output errors from a test */
   void OutputTestErrors(std::vector<char> const& process_output);

+ 3 - 1
Source/cmCacheManager.cxx

@@ -383,7 +383,9 @@ void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
 {
   // support : in key name by double quoting
   const char* q =
-    (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : "";
+    (key.find(':') != std::string::npos || cmHasLiteralPrefix(key, "//"))
+    ? "\""
+    : "";
   fout << q << key << q;
 }
 

+ 12 - 11
Source/cmComputeLinkInformation.cxx

@@ -1200,7 +1200,8 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item,
     // CMP0003 so put it in OldUserFlagItems, if it is not a -l
     // or -Wl,-l (-framework -pthread), then allow it without a
     // CMP0003 as -L will not affect those other linker flags
-    if (item.Value.find("-l") == 0 || item.Value.find("-Wl,-l") == 0) {
+    if (cmHasLiteralPrefix(item.Value, "-l") ||
+        cmHasLiteralPrefix(item.Value, "-Wl,-l")) {
       // This is a linker option provided by the user.
       this->OldUserFlagItems.push_back(item.Value);
     }
@@ -1796,11 +1797,11 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
       // support or if using the link path as an rpath.
       if (use_build_rpath) {
         std::string d = ri;
-        if (!rootPath.empty() && d.find(rootPath) == 0) {
-          d = d.substr(rootPath.size());
-        } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
-          std::string suffix = d.substr(strlen(stagePath));
-          d = cmStrCat(installPrefix, '/', suffix);
+        if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+          d.erase(0, rootPath.size());
+        } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) {
+          d.erase(0, strlen(stagePath));
+          d = cmStrCat(installPrefix, '/', d);
           cmSystemTools::ConvertToUnixSlashes(d);
         } else if (use_relative_build_rpath) {
           // If expansion of the $ORIGIN token is supported and permitted per
@@ -1827,11 +1828,11 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
             !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
             !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
           std::string d = ri;
-          if (!rootPath.empty() && d.find(rootPath) == 0) {
-            d = d.substr(rootPath.size());
-          } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
-            std::string suffix = d.substr(strlen(stagePath));
-            d = cmStrCat(installPrefix, '/', suffix);
+          if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+            d.erase(0, rootPath.size());
+          } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) {
+            d.erase(0, strlen(stagePath));
+            d = cmStrCat(installPrefix, '/', d);
             cmSystemTools::ConvertToUnixSlashes(d);
           }
           if (emitted.insert(d).second) {

+ 2 - 2
Source/cmConditionEvaluator.cxx

@@ -494,12 +494,12 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
       if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
         size_t argP1len = argP1->GetValue().size();
         bool bdef = false;
-        if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" &&
+        if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") &&
             argP1->GetValue().operator[](argP1len - 1) == '}') {
           std::string env = argP1->GetValue().substr(4, argP1len - 5);
           bdef = cmSystemTools::HasEnv(env);
         } else if (argP1len > 6 &&
-                   argP1->GetValue().substr(0, 6) == "CACHE{" &&
+                   cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") &&
                    argP1->GetValue().operator[](argP1len - 1) == '}') {
           std::string cache = argP1->GetValue().substr(6, argP1len - 7);
           bdef =

+ 4 - 4
Source/cmDependsC.cxx

@@ -264,19 +264,19 @@ void cmDependsC::ReadCacheFile()
       // file doesn't exist, check that the regular expressions
       // haven't changed
       else if (!res) {
-        if (line.find(INCLUDE_REGEX_LINE_MARKER) == 0) {
+        if (cmHasLiteralPrefix(line, INCLUDE_REGEX_LINE_MARKER)) {
           if (line != this->IncludeRegexLineString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_SCAN_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_SCAN_MARKER)) {
           if (line != this->IncludeRegexScanString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_COMPLAIN_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_COMPLAIN_MARKER)) {
           if (line != this->IncludeRegexComplainString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_TRANSFORM_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_TRANSFORM_MARKER)) {
           if (line != this->IncludeRegexTransformString) {
             return;
           }

+ 2 - 2
Source/cmExportBuildAndroidMKGenerator.cxx

@@ -118,13 +118,13 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
           } else {
             bool relpath = false;
             if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
-              relpath = lib.substr(0, 3) == "../";
+              relpath = cmHasLiteralPrefix(lib, "../");
             }
             // check for full path or if it already has a -l, or
             // in the case of an install check for relative paths
             // if it is full or a link library then use string directly
             if (cmSystemTools::FileIsFullPath(lib) ||
-                lib.substr(0, 2) == "-l" || relpath) {
+                cmHasLiteralPrefix(lib, "-l") || relpath) {
               ldlibs += " " + lib;
               // if it is not a path and does not have a -l then add -l
             } else if (!lib.empty()) {

+ 3 - 3
Source/cmExportTryCompileFileGenerator.cxx

@@ -97,9 +97,9 @@ void cmExportTryCompileFileGenerator::PopulateProperties(
 
     properties[p] = target->GetProperty(p);
 
-    if (p.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 ||
-        p.find("IMPORTED_LINK_DEPENDENT_LIBRARIES") == 0 ||
-        p.find("INTERFACE_LINK_LIBRARIES") == 0) {
+    if (cmHasLiteralPrefix(p, "IMPORTED_LINK_INTERFACE_LIBRARIES") ||
+        cmHasLiteralPrefix(p, "IMPORTED_LINK_DEPENDENT_LIBRARIES") ||
+        cmHasLiteralPrefix(p, "INTERFACE_LINK_LIBRARIES")) {
       std::string evalResult =
         this->FindTargets(p, target, std::string(), emitted);
 

+ 4 - 4
Source/cmExtraCodeBlocksGenerator.cxx

@@ -218,7 +218,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
     // Convert
     for (std::string const& listFile : listFiles) {
       // don't put cmake's own files into the project (#12110):
-      if (listFile.find(cmSystemTools::GetCMakeRoot()) == 0) {
+      if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) {
         continue;
       }
 
@@ -301,11 +301,11 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }

+ 3 - 3
Source/cmExtraEclipseCDT4Generator.cxx

@@ -936,11 +936,11 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }

+ 3 - 3
Source/cmExtraKateGenerator.cxx

@@ -144,11 +144,11 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg,
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }

+ 3 - 3
Source/cmExtraSublimeTextGenerator.cxx

@@ -199,11 +199,11 @@ void cmExtraSublimeTextGenerator::AppendAllTargets(
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }

+ 2 - 2
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -158,8 +158,8 @@ bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
 
 bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression()
 {
-  return this->Property.find("TARGET_GENEX_EVAL:") == 0 ||
-    this->Property.find("GENEX_EVAL:", 0) == 0;
+  return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
+    cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
 }
 
 bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression()

+ 2 - 2
Source/cmGeneratorTarget.cxx

@@ -2023,7 +2023,7 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
     if (cmGeneratorTarget::ImportInfo const* info =
           this->GetImportInfo(config)) {
       if (!info->NoSOName && !info->SOName.empty()) {
-        if (info->SOName.find("@rpath/") == 0) {
+        if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
           install_name_is_rpath = true;
         }
       } else {
@@ -2140,7 +2140,7 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const
         return cmSystemTools::GetFilenameName(info->Location);
       }
       // Use the soname given if any.
-      if (info->SOName.find("@rpath/") == 0) {
+      if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
         return info->SOName.substr(6);
       }
       return info->SOName;

+ 2 - 1
Source/cmGlobalVisualStudio10Generator.cxx

@@ -19,6 +19,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmVersion.h"
 #include "cmVisualStudioSlnData.h"
 #include "cmVisualStudioSlnParser.h"
@@ -313,7 +314,7 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
       version.clear();
     }
 
-    if (version.find(this->GetPlatformToolsetString()) != 0) {
+    if (!cmHasPrefix(version, this->GetPlatformToolsetString())) {
       std::ostringstream e;
       /* clang-format off */
       e <<

+ 3 - 3
Source/cmGlobalVisualStudio7Generator.cxx

@@ -505,13 +505,13 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
   const std::vector<std::string> propKeys =
     root->GetMakefile()->GetPropertyKeys();
   for (std::string const& it : propKeys) {
-    if (it.find("VS_GLOBAL_SECTION_") == 0) {
+    if (cmHasLiteralPrefix(it, "VS_GLOBAL_SECTION_")) {
       std::string sectionType;
       std::string name = it.substr(18);
-      if (name.find("PRE_") == 0) {
+      if (cmHasLiteralPrefix(name, "PRE_")) {
         name = name.substr(4);
         sectionType = "preSolution";
-      } else if (name.find("POST_") == 0) {
+      } else if (cmHasLiteralPrefix(name, "POST_")) {
         name = name.substr(5);
         sectionType = "postSolution";
       } else

+ 3 - 2
Source/cmGlobalXCodeGenerator.cxx

@@ -34,6 +34,7 @@
 #include "cmSourceGroup.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmXCode21Object.h"
@@ -2407,7 +2408,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
   // Convert "XCODE_ATTRIBUTE_*" properties directly.
   {
     for (auto const& prop : gtgt->GetPropertyKeys()) {
-      if (prop.find("XCODE_ATTRIBUTE_") == 0) {
+      if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
         std::string attribute = prop.substr(16);
         this->FilterConfigurationAttribute(configName, attribute);
         if (!attribute.empty()) {
@@ -3143,7 +3144,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
     // Put this last so it can override existing settings
     // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
     for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
-      if (var.find("CMAKE_XCODE_ATTRIBUTE_") == 0) {
+      if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) {
         std::string attribute = var.substr(22);
         this->FilterConfigurationAttribute(config.first, attribute);
         if (!attribute.empty()) {

+ 3 - 3
Source/cmGraphVizWriter.cxx

@@ -402,9 +402,9 @@ bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item)
   }
 
   if (item.Target->GetType() == cmStateEnums::UTILITY) {
-    if ((itemName.find("Nightly") == 0) ||
-        (itemName.find("Continuous") == 0) ||
-        (itemName.find("Experimental") == 0)) {
+    if (cmHasLiteralPrefix(itemName, "Nightly") ||
+        cmHasLiteralPrefix(itemName, "Continuous") ||
+        cmHasLiteralPrefix(itemName, "Experimental")) {
       return true;
     }
   }

+ 2 - 1
Source/cmJsonObjects.cxx

@@ -90,7 +90,8 @@ void cmGetCMakeInputs(const cmGlobalGenerator* gg,
 
       const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
       const bool isInternal = (startOfFile == cmakeRootDir);
-      const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0);
+      const bool isTemporary =
+        !isInternal && (cmHasPrefix(lf, buildDir + '/'));
 
       std::string toAdd = lf;
       if (!sourceDir.empty()) {

+ 1 - 1
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -1778,7 +1778,7 @@ private:
                             const std::string& testDir)
   {
     // First check if the test directory "starts with" the base directory:
-    if (testDir.find(baseDir) != 0) {
+    if (!cmHasPrefix(testDir, baseDir)) {
       return false;
     }
     // If it does, then check that it's either the same string, or that the

+ 2 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -20,6 +20,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmXMLParser.h"
 #include "cmake.h"
@@ -2006,7 +2007,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter(
   fout << "\t<Globals>\n";
 
   for (std::string const& key : target->GetPropertyKeys()) {
-    if (key.find("VS_GLOBAL_") == 0) {
+    if (cmHasLiteralPrefix(key, "VS_GLOBAL_")) {
       std::string name = key.substr(10);
       if (!name.empty()) {
         /* clang-format off */

+ 1 - 1
Source/cmMakefile.cxx

@@ -2622,7 +2622,7 @@ cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const
   };
 
   for (auto const& entry : sdkDatabase) {
-    if (sdkRoot.find(entry.name) == 0 ||
+    if (cmHasPrefix(sdkRoot, entry.name) ||
         sdkRoot.find(std::string("/") + entry.name) != std::string::npos) {
       return entry.sdk;
     }

+ 5 - 3
Source/cmRST.cxx

@@ -89,7 +89,8 @@ void cmRST::ProcessModule(std::istream& is)
         this->ProcessLine(line);
       } else {
         if (line[0] != '#') {
-          this->ProcessLine(line.substr(0, pos));
+          line.resize(pos);
+          this->ProcessLine(line);
         }
         rst.clear();
         this->Reset();
@@ -102,8 +103,9 @@ void cmRST::ProcessModule(std::istream& is)
           this->ProcessLine("");
           continue;
         }
-        if (line.substr(0, 2) == "# ") {
-          this->ProcessLine(line.substr(2));
+        if (cmHasLiteralPrefix(line, "# ")) {
+          line.erase(0, 2);
+          this->ProcessLine(line);
           continue;
         }
         rst.clear();

+ 1 - 1
Source/cmRuntimeDependencyArchive.cxx

@@ -39,7 +39,7 @@ static void AddVisualStudioPath(std::vector<std::string>& paths,
   std::string vsloc;
   bool found = false;
 #  ifndef CMAKE_BOOTSTRAP
-  if (gg->GetName().find(prefix) == 0) {
+  if (cmHasPrefix(gg->GetName(), prefix)) {
     cmGlobalVisualStudioVersionedGenerator* vsgen =
       static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
     if (vsgen->GetVSInstance(vsloc)) {

+ 3 - 1
Source/cmSourceFileLocation.cxx

@@ -4,6 +4,8 @@
 
 #include <cassert>
 
+#include <cm/string_view>
+
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -152,7 +154,7 @@ bool cmSourceFileLocation::MatchesAmbiguousExtension(
 
   // Only a fixed set of extensions will be tried to match a file on
   // disk.  One of these must match if loc refers to this source file.
-  std::string const& ext = this->Name.substr(loc.Name.size() + 1);
+  auto ext = cm::string_view(this->Name).substr(loc.Name.size() + 1);
   cmMakefile const* mf = this->Makefile;
   auto cm = mf->GetCMakeInstance();
   return cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext);

+ 1 - 2
Source/cmSystemTools.cxx

@@ -1065,8 +1065,7 @@ bool cmSystemTools::SimpleGlob(const std::string& glob,
         if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) {
           continue;
         }
-        if (sfname.size() >= ppath.size() &&
-            sfname.substr(0, ppath.size()) == ppath) {
+        if (cmHasPrefix(sfname, ppath)) {
           files.push_back(fname);
           res = true;
         }

+ 45 - 54
Source/cmVisualStudio10TargetGenerator.cxx

@@ -6,6 +6,7 @@
 #include <set>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cm/vector>
 
 #include "windows.h"
@@ -22,6 +23,7 @@
 #include "cmLocalVisualStudio10Generator.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmVisualStudioGeneratorOptions.h"
 
@@ -61,10 +63,10 @@ struct cmVisualStudio10TargetGenerator::Elem
     this->StartElement();
   }
   Elem(const Elem&) = delete;
-  Elem(Elem& par, const std::string& tag)
+  Elem(Elem& par, cm::string_view tag)
     : S(par.S)
     , Indent(par.Indent + 1)
-    , Tag(tag)
+    , Tag(std::string(tag))
   {
     par.SetHasElements();
     this->StartElement();
@@ -78,22 +80,22 @@ struct cmVisualStudio10TargetGenerator::Elem
   }
   std::ostream& WriteString(const char* line);
   void StartElement() { this->WriteString("<") << this->Tag; }
-  void Element(const std::string& tag, const std::string& val)
+  void Element(cm::string_view tag, std::string val)
   {
-    Elem(*this, tag).Content(val);
+    Elem(*this, tag).Content(std::move(val));
   }
-  Elem& Attribute(const char* an, const std::string& av)
+  Elem& Attribute(const char* an, std::string av)
   {
-    this->S << " " << an << "=\"" << cmVS10EscapeAttr(av) << "\"";
+    this->S << " " << an << "=\"" << cmVS10EscapeAttr(std::move(av)) << "\"";
     return *this;
   }
-  void Content(const std::string& val)
+  void Content(std::string val)
   {
     if (!this->HasContent) {
       this->S << ">";
       this->HasContent = true;
     }
-    this->S << cmVS10EscapeXML(val);
+    this->S << cmVS10EscapeXML(std::move(val));
   }
   ~Elem()
   {
@@ -556,10 +558,11 @@ void cmVisualStudio10TargetGenerator::Generate()
 
       std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
       for (std::string const& keyIt : keys) {
-        static const char* prefix = "VS_GLOBAL_";
-        if (keyIt.find(prefix) != 0)
+        static const cm::string_view prefix = "VS_GLOBAL_";
+        if (!cmHasPrefix(keyIt, prefix))
           continue;
-        std::string globalKey = keyIt.substr(strlen(prefix));
+        cm::string_view globalKey =
+          cm::string_view(keyIt).substr(prefix.length());
         // Skip invalid or separately-handled properties.
         if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
             globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
@@ -790,21 +793,14 @@ void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
     for (std::string const& ri : packageReferences) {
       size_t versionIndex = ri.find_last_of('_');
       if (versionIndex != std::string::npos) {
-        WritePackageReference(e1, ri.substr(0, versionIndex),
-                              ri.substr(versionIndex + 1));
+        Elem e2(e1, "PackageReference");
+        e2.Attribute("Include", ri.substr(0, versionIndex));
+        e2.Attribute("Version", ri.substr(versionIndex + 1));
       }
     }
   }
 }
 
-void cmVisualStudio10TargetGenerator::WritePackageReference(
-  Elem& e1, std::string const& ref, std::string const& version)
-{
-  Elem e2(e1, "PackageReference");
-  e2.Attribute("Include", ref);
-  e2.Attribute("Version", version);
-}
-
 void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
 {
   std::vector<std::string> references;
@@ -814,17 +810,15 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
   }
   cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
   for (auto const& i : props.GetList()) {
-    if (i.first.find("VS_DOTNET_REFERENCE_") == 0) {
-      std::string name = i.first.substr(20);
-      if (!name.empty()) {
-        std::string path = i.second;
-        if (!cmsys::SystemTools::FileIsFullPath(path)) {
-          path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
-        }
-        ConvertToWindowsSlash(path);
-        this->DotNetHintReferences[""].push_back(
-          DotNetHintReference(name, path));
+    static const cm::string_view vsDnRef = "VS_DOTNET_REFERENCE_";
+    if (cmHasPrefix(i.first, vsDnRef)) {
+      std::string path = i.second;
+      if (!cmsys::SystemTools::FileIsFullPath(path)) {
+        path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
       }
+      ConvertToWindowsSlash(path);
+      this->DotNetHintReferences[""].emplace_back(
+        DotNetHintReference(i.first.substr(vsDnRef.length()), path));
     }
   }
   if (!references.empty() || !this->DotNetHintReferences.empty()) {
@@ -837,7 +831,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
           cmsys::SystemTools::GetFilenameWithoutLastExtension(ri);
         std::string path = ri;
         ConvertToWindowsSlash(path);
-        this->DotNetHintReferences[""].push_back(
+        this->DotNetHintReferences[""].emplace_back(
           DotNetHintReference(name, path));
       } else {
         this->WriteDotNetReference(e1, ri, "", "");
@@ -910,12 +904,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
   CustomTags tags;
   cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
   for (const auto& i : props.GetList()) {
-    if (i.first.find(refPropFullPrefix) == 0) {
-      std::string refTag = i.first.substr(refPropFullPrefix.length());
-      std::string refVal = i.second;
-      if (!refTag.empty() && !refVal.empty()) {
-        tags[refTag] = refVal;
-      }
+    if (cmHasPrefix(i.first, refPropFullPrefix) && !i.second.empty()) {
+      tags[i.first.substr(refPropFullPrefix.length())] = i.second;
     }
   }
   for (auto const& tag : tags) {
@@ -952,7 +942,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
         // subdirectory
         // of the .csproj file, we have to use relative pathnames, otherwise
         // visual studio does not show the file in the IDE. Sorry.
-        if (obj.find(srcDir) == 0) {
+        if (cmHasPrefix(obj, srcDir)) {
           obj = this->ConvertPath(obj, true);
           ConvertToWindowsSlash(obj);
           useRelativePath = true;
@@ -999,10 +989,10 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
           }
           if (!generator.empty()) {
             e2.Element("Generator", generator);
-            if (designerResource.find(srcDir) == 0) {
-              designerResource = designerResource.substr(srcDir.length() + 1);
-            } else if (designerResource.find(binDir) == 0) {
-              designerResource = designerResource.substr(binDir.length() + 1);
+            if (cmHasPrefix(designerResource, srcDir)) {
+              designerResource.erase(0, srcDir.length());
+            } else if (cmHasPrefix(designerResource, binDir)) {
+              designerResource.erase(0, binDir.length());
             } else {
               designerResource =
                 cmsys::SystemTools::GetFilenameName(designerResource);
@@ -1013,9 +1003,10 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
         }
         const cmPropertyMap& props = oi->GetProperties();
         for (const std::string& p : props.GetKeys()) {
-          static const std::string propNamePrefix = "VS_CSHARP_";
-          if (p.find(propNamePrefix) == 0) {
-            std::string tagName = p.substr(propNamePrefix.length());
+          static const cm::string_view propNamePrefix = "VS_CSHARP_";
+          if (cmHasPrefix(p, propNamePrefix)) {
+            cm::string_view tagName =
+              cm::string_view(p).substr(propNamePrefix.length());
             if (!tagName.empty()) {
               const std::string& value = *props.GetPropertyValue(p);
               if (!value.empty()) {
@@ -1749,8 +1740,8 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1,
   if (this->IsResxHeader(fileName)) {
     e2.Element("FileType", "CppForm");
   } else if (this->IsXamlHeader(fileName)) {
-    std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
-    e2.Element("DependentUpon", xamlFileName);
+    e2.Element("DependentUpon",
+               fileName.substr(0, fileName.find_last_of(".")));
   }
 }
 
@@ -2413,8 +2404,8 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   }
   if (this->IsXamlSource(source->GetFullPath())) {
     const std::string& fileName = source->GetFullPath();
-    std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
-    e2.Element("DependentUpon", xamlFileName);
+    e2.Element("DependentUpon",
+               fileName.substr(0, fileName.find_last_of(".")));
   }
   if (this->ProjectType == csproj) {
     std::string f = source->GetFullPath();
@@ -4798,8 +4789,8 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
   if (this->ProjectType == csproj) {
     const cmPropertyMap& props = sf->GetProperties();
     for (const std::string& p : props.GetKeys()) {
-      static const std::string propNamePrefix = "VS_CSHARP_";
-      if (p.find(propNamePrefix) == 0) {
+      static const cm::string_view propNamePrefix = "VS_CSHARP_";
+      if (cmHasPrefix(p, propNamePrefix)) {
         std::string tagName = p.substr(propNamePrefix.length());
         if (!tagName.empty()) {
           const std::string& val = *props.GetPropertyValue(p);
@@ -4840,9 +4831,9 @@ std::string cmVisualStudio10TargetGenerator::GetCSharpSourceLink(
   if (sourceGroup && !sourceGroup->GetFullName().empty()) {
     link = sourceGroup->GetFullName() + "/" +
       cmsys::SystemTools::GetFilenameName(fullFileName);
-  } else if (fullFileName.find(srcDir) == 0) {
+  } else if (cmHasPrefix(fullFileName, srcDir)) {
     link = fullFileName.substr(srcDir.length() + 1);
-  } else if (fullFileName.find(binDir) == 0) {
+  } else if (cmHasPrefix(fullFileName, binDir)) {
     link = fullFileName.substr(binDir.length() + 1);
   } else if (const char* l = source->GetProperty("VS_CSHARP_Link")) {
     link = l;

+ 0 - 2
Source/cmVisualStudio10TargetGenerator.h

@@ -73,8 +73,6 @@ private:
                              std::vector<size_t> const& exclude_configs);
   void WriteAllSources(Elem& e0);
   void WritePackageReferences(Elem& e0);
-  void WritePackageReference(Elem& e1, std::string const& ref,
-                             std::string const& version);
   void WriteDotNetReferences(Elem& e0);
   void WriteDotNetReference(Elem& e1, std::string const& ref,
                             std::string const& hint,

+ 5 - 5
Source/cmVisualStudioSlnParser.cxx

@@ -517,7 +517,7 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line,
                                                  State& state)
 {
   size_t idxEqualSign = line.find('=');
-  const std::string& fullTag = line.substr(0, idxEqualSign);
+  auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
   if (!this->ParseTag(fullTag, parsedLine, state))
     return false;
   if (idxEqualSign != line.npos) {
@@ -560,7 +560,7 @@ bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line,
                                                   State& state)
 {
   size_t idxEqualSign = line.find('=');
-  const std::string& fullTag = line.substr(0, idxEqualSign);
+  auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
   if (!this->ParseTag(fullTag, parsedLine, state))
     return false;
   if (idxEqualSign != line.npos) {
@@ -586,17 +586,17 @@ bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line,
   return true;
 }
 
-bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag,
+bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag,
                                        ParsedLine& parsedLine, State& state)
 {
   size_t idxLeftParen = fullTag.find('(');
-  if (idxLeftParen == fullTag.npos) {
+  if (idxLeftParen == cm::string_view::npos) {
     parsedLine.SetTag(cmTrimWhitespace(fullTag));
     return true;
   }
   parsedLine.SetTag(cmTrimWhitespace(fullTag.substr(0, idxLeftParen)));
   size_t idxRightParen = fullTag.rfind(')');
-  if (idxRightParen == fullTag.npos) {
+  if (idxRightParen == cm::string_view::npos) {
     this->LastResult.SetError(ResultErrorInputStructure,
                               state.GetCurrentLine());
     return false;

+ 3 - 2
Source/cmVisualStudioSlnParser.h

@@ -9,6 +9,8 @@
 #include <iosfwd>
 #include <string>
 
+#include <cm/string_view>
+
 #include <stddef.h>
 
 class cmSlnData;
@@ -97,8 +99,7 @@ protected:
   bool ParseKeyValuePair(const std::string& line, ParsedLine& parsedLine,
                          State& state);
 
-  bool ParseTag(const std::string& fullTag, ParsedLine& parsedLine,
-                State& state);
+  bool ParseTag(cm::string_view fullTag, ParsedLine& parsedLine, State& state);
 
   bool ParseValue(const std::string& value, ParsedLine& parsedLine);
 };

+ 56 - 54
Source/cmake.cxx

@@ -24,6 +24,7 @@
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cm_static_string_view.hxx"
 #include "cm_sys_stat.h"
 
 #include "cmAlgorithms.h"
@@ -292,7 +293,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
   bool findPackageMode = false;
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-D", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-D")) {
       std::string entry = arg.substr(2);
       if (entry.empty()) {
         ++i;
@@ -381,7 +382,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
         // -Wno-error=<name>
         this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
       }
-    } else if (arg.find("-U", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-U")) {
       std::string entryPattern = arg.substr(2);
       if (entryPattern.empty()) {
         ++i;
@@ -411,7 +412,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
       for (std::string const& currentEntry : entriesToDelete) {
         this->State->RemoveCacheEntry(currentEntry);
       }
-    } else if (arg.find("-C", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-C")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -426,7 +427,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
       // Resolve script path specified on command line relative to $PWD.
       path = cmSystemTools::CollapseFullPath(path);
       this->ReadListFile(args, path);
-    } else if (arg.find("-P", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-P")) {
       i++;
       if (i >= args.size()) {
         cmSystemTools::Error("-P must be followed by a file name.");
@@ -445,7 +446,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
       this->SetHomeOutputDirectory(
         cmSystemTools::GetCurrentWorkingDirectory());
       this->ReadListFile(args, path);
-    } else if (arg.find("--find-package", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
       findPackageMode = true;
     }
   }
@@ -524,11 +525,11 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
     if (!quiet) {
       printf("%s not found.\n", packageName.c_str());
     }
-  } else if (mode == "EXIST") {
+  } else if (mode == "EXIST"_s) {
     if (!quiet) {
       printf("%s found.\n", packageName.c_str());
     }
-  } else if (mode == "COMPILE") {
+  } else if (mode == "COMPILE"_s) {
     std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
     std::vector<std::string> includeDirs = cmExpandedList(includes);
 
@@ -539,7 +540,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
 
     std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
     printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
-  } else if (mode == "LINK") {
+  } else if (mode == "LINK"_s) {
     const char* targetName = "dummy";
     std::vector<std::string> srcs;
     cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
@@ -623,7 +624,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
 #endif
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-H") || cmHasLiteralPrefix(arg, "-S")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -641,9 +642,9 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       path = cmSystemTools::CollapseFullPath(path);
       cmSystemTools::ConvertToUnixSlashes(path);
       this->SetHomeDirectory(path);
-    } else if (arg.find("-O", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-O")) {
       // There is no local generate anymore.  Ignore -O option.
-    } else if (arg.find("-B", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-B")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -662,54 +663,54 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       cmSystemTools::ConvertToUnixSlashes(path);
       this->SetHomeOutputDirectory(path);
     } else if ((i < args.size() - 2) &&
-               (arg.find("--check-build-system", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-build-system")) {
       this->CheckBuildSystemArgument = args[++i];
       this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
     } else if ((i < args.size() - 1) &&
-               (arg.find("--check-stamp-file", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-stamp-file")) {
       this->CheckStampFile = args[++i];
     } else if ((i < args.size() - 1) &&
-               (arg.find("--check-stamp-list", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-stamp-list")) {
       this->CheckStampList = args[++i];
-    } else if (arg == "--regenerate-during-build") {
+    } else if (arg == "--regenerate-during-build"_s) {
       this->RegenerateDuringBuild = true;
     }
 #if defined(CMAKE_HAVE_VS_GENERATORS)
     else if ((i < args.size() - 1) &&
-             (arg.find("--vs-solution-file", 0) == 0)) {
+             cmHasLiteralPrefix(arg, "--vs-solution-file")) {
       this->VSSolutionFile = args[++i];
     }
 #endif
-    else if (arg.find("-D", 0) == 0) {
+    else if (cmHasLiteralPrefix(arg, "-D")) {
       // skip for now
       // in case '-D var=val' is given, also skip the next
       // in case '-Dvar=val' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-U", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-U")) {
       // skip for now
       // in case '-U var' is given, also skip the next
       // in case '-Uvar' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-C", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-C")) {
       // skip for now
       // in case '-C path' is given, also skip the next
       // in case '-Cpath' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-P", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-P")) {
       // skip for now
       i++;
-    } else if (arg.find("--find-package", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
       // skip for now
       i++;
-    } else if (arg.find("-W", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-W")) {
       // skip for now
-    } else if (arg.find("--graphviz=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--graphviz=")) {
       std::string path = arg.substr(strlen("--graphviz="));
       path = cmSystemTools::CollapseFullPath(path);
       cmSystemTools::ConvertToUnixSlashes(path);
@@ -718,13 +719,13 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         cmSystemTools::Error("No file specified for --graphviz");
         return;
       }
-    } else if (arg.find("--debug-trycompile", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-trycompile")) {
       std::cout << "debug trycompile on\n";
       this->DebugTryCompileOn();
-    } else if (arg.find("--debug-output", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-output")) {
       std::cout << "Running with debug output on.\n";
       this->SetDebugOutputOn(true);
-    } else if (arg.find("--log-level=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--log-level=")) {
       const auto logLevel =
         StringToLogLevel(arg.substr(sizeof("--log-level=") - 1));
       if (logLevel == LogLevel::LOG_UNDEFINED) {
@@ -733,7 +734,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       }
       this->SetLogLevel(logLevel);
       this->LogLevelWasSetViaCLI = true;
-    } else if (arg.find("--loglevel=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--loglevel=")) {
       // This is supported for backward compatibility. This option only
       // appeared in the 3.15.x release series and was renamed to
       // --log-level in 3.16.0
@@ -745,16 +746,16 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       }
       this->SetLogLevel(logLevel);
       this->LogLevelWasSetViaCLI = true;
-    } else if (arg == "--log-context") {
+    } else if (arg == "--log-context"_s) {
       this->SetShowLogContext(true);
-    } else if (arg.find("--debug-find", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-find")) {
       std::cout << "Running with debug output on for the `find` commands.\n";
       this->SetDebugFindOutputOn(true);
-    } else if (arg.find("--trace-expand", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-expand")) {
       std::cout << "Running with expanded trace output on.\n";
       this->SetTrace(true);
       this->SetTraceExpand(true);
-    } else if (arg.find("--trace-format=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-format=")) {
       this->SetTrace(true);
       const auto traceFormat =
         StringToTraceFormat(arg.substr(strlen("--trace-format=")));
@@ -764,35 +765,35 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         return;
       }
       this->SetTraceFormat(traceFormat);
-    } else if (arg.find("--trace-source=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-source=")) {
       std::string file = arg.substr(strlen("--trace-source="));
       cmSystemTools::ConvertToUnixSlashes(file);
       this->AddTraceSource(file);
       this->SetTrace(true);
-    } else if (arg.find("--trace-redirect=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-redirect=")) {
       std::string file = arg.substr(strlen("--trace-redirect="));
       cmSystemTools::ConvertToUnixSlashes(file);
       this->SetTraceFile(file);
       this->SetTrace(true);
-    } else if (arg.find("--trace", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace")) {
       std::cout << "Running with trace output on.\n";
       this->SetTrace(true);
       this->SetTraceExpand(false);
-    } else if (arg.find("--warn-uninitialized", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--warn-uninitialized")) {
       std::cout << "Warn about uninitialized values.\n";
       this->SetWarnUninitialized(true);
-    } else if (arg.find("--warn-unused-vars", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) {
       std::cout << "Finding unused variables.\n";
       this->SetWarnUnused(true);
-    } else if (arg.find("--no-warn-unused-cli", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) {
       std::cout << "Not searching for unused variables given on the "
                 << "command line.\n";
       this->SetWarnUnusedCli(false);
-    } else if (arg.find("--check-system-vars", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--check-system-vars")) {
       std::cout << "Also check system files when warning about unused and "
                 << "uninitialized variables.\n";
       this->SetCheckSystemVars(true);
-    } else if (arg.find("-A", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-A")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -808,7 +809,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       }
       this->SetGeneratorPlatform(value);
       havePlatform = true;
-    } else if (arg.find("-T", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-T")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -824,7 +825,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       }
       this->SetGeneratorToolset(value);
       haveToolset = true;
-    } else if (arg.find("-G", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-G")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -849,12 +850,12 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       }
       this->SetGlobalGenerator(std::move(gen));
 #if !defined(CMAKE_BOOTSTRAP)
-    } else if (arg.find("--profiling-format", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--profiling-format")) {
       profilingFormat = arg.substr(strlen("--profiling-format="));
       if (profilingFormat.empty()) {
         cmSystemTools::Error("No format specified for --profiling-format");
       }
-    } else if (arg.find("--profiling-output", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--profiling-output")) {
       profilingOutput = arg.substr(strlen("--profiling-output="));
       profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput);
       cmSystemTools::ConvertToUnixSlashes(profilingOutput);
@@ -886,7 +887,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         "--profiling-format specified but no --profiling-output!");
       return;
     }
-    if (profilingFormat == "google-trace") {
+    if (profilingFormat == "google-trace"_s) {
       try {
         this->ProfilingOutput =
           cm::make_unique<cmMakefileProfilingData>(profilingOutput);
@@ -1037,9 +1038,9 @@ void cmake::SetDirectoriesFromFile(const std::string& arg)
     std::string fullPath = cmSystemTools::CollapseFullPath(arg);
     std::string name = cmSystemTools::GetFilenameName(fullPath);
     name = cmSystemTools::LowerCase(name);
-    if (name == "cmakecache.txt") {
+    if (name == "cmakecache.txt"_s) {
       cachePath = cmSystemTools::GetFilenamePath(fullPath);
-    } else if (name == "cmakelists.txt") {
+    } else if (name == "cmakelists.txt"_s) {
       listPath = cmSystemTools::GetFilenamePath(fullPath);
     }
   } else {
@@ -1048,7 +1049,7 @@ void cmake::SetDirectoriesFromFile(const std::string& arg)
     std::string fullPath = cmSystemTools::CollapseFullPath(arg);
     std::string name = cmSystemTools::GetFilenameName(fullPath);
     name = cmSystemTools::LowerCase(name);
-    if (name == "cmakecache.txt" || name == "cmakelists.txt") {
+    if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) {
       argIsFile = true;
       listPath = cmSystemTools::GetFilenamePath(fullPath);
     } else {
@@ -1936,13 +1937,13 @@ void cmake::AddCacheEntry(const std::string& key, const char* value,
                              cmStateEnums::CacheEntryType(type));
   this->UnwatchUnusedCli(key);
 
-  if (key == "CMAKE_WARN_DEPRECATED") {
+  if (key == "CMAKE_WARN_DEPRECATED"_s) {
     this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(value));
-  } else if (key == "CMAKE_ERROR_DEPRECATED") {
+  } else if (key == "CMAKE_ERROR_DEPRECATED"_s) {
     this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value));
-  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS") {
+  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS"_s) {
     this->Messenger->SetSuppressDevWarnings(cmIsOn(value));
-  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS") {
+  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS"_s) {
     this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(value));
   }
 }
@@ -1978,9 +1979,10 @@ std::string cmake::StripExtension(const std::string& file) const
 {
   auto dotpos = file.rfind('.');
   if (dotpos != std::string::npos) {
-    auto ext = file.substr(dotpos + 1);
 #if defined(_WIN32) || defined(__APPLE__)
-    ext = cmSystemTools::LowerCase(ext);
+    auto ext = cmSystemTools::LowerCase(file.substr(dotpos + 1));
+#else
+    auto ext = cm::string_view(file).substr(dotpos + 1);
 #endif
     if (this->IsSourceExtension(ext) || this->IsHeaderExtension(ext)) {
       return file.substr(0, dotpos);
@@ -2480,7 +2482,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
   bool writeToStdout = true;
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-G", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-G")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;

+ 8 - 6
Source/cmake.h

@@ -16,6 +16,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmGeneratedFileStream.h"
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
@@ -138,13 +140,13 @@ public:
 
   struct FileExtensions
   {
-    bool Test(std::string const& ext) const
+    bool Test(cm::string_view ext) const
     {
       return (this->unordered.find(ext) != this->unordered.end());
     }
 
     std::vector<std::string> ordered;
-    std::unordered_set<std::string> unordered;
+    std::unordered_set<cm::string_view> unordered;
   };
 
   using InstalledFilesMap = std::map<std::string, cmInstalledFile>;
@@ -266,7 +268,7 @@ public:
     return this->SourceFileExtensions.ordered;
   }
 
-  bool IsSourceExtension(const std::string& ext) const
+  bool IsSourceExtension(cm::string_view ext) const
   {
     return this->SourceFileExtensions.Test(ext);
   }
@@ -276,7 +278,7 @@ public:
     return this->HeaderFileExtensions.ordered;
   }
 
-  bool IsHeaderExtension(const std::string& ext) const
+  bool IsHeaderExtension(cm::string_view ext) const
   {
     return this->HeaderFileExtensions.Test(ext);
   }
@@ -286,7 +288,7 @@ public:
     return this->CudaFileExtensions.ordered;
   }
 
-  bool IsCudaExtension(const std::string& ext) const
+  bool IsCudaExtension(cm::string_view ext) const
   {
     return this->CudaFileExtensions.Test(ext);
   }
@@ -296,7 +298,7 @@ public:
     return this->FortranFileExtensions.ordered;
   }
 
-  bool IsFortranExtension(const std::string& ext) const
+  bool IsFortranExtension(cm::string_view ext) const
   {
     return this->FortranFileExtensions.Test(ext);
   }

+ 26 - 32
Source/cmcldeps.cxx

@@ -25,6 +25,7 @@
 
 #include "cmsys/Encoding.hxx"
 
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 // We don't want any wildcard expansion.
@@ -63,7 +64,7 @@ static void usage(const char* msg)
         msg);
 }
 
-static std::string trimLeadingSpace(const std::string& cmdline)
+static cm::string_view trimLeadingSpace(cm::string_view cmdline)
 {
   int i = 0;
   for (; cmdline[i] == ' '; ++i)
@@ -81,34 +82,30 @@ static void replaceAll(std::string& str, const std::string& search,
   }
 }
 
-bool startsWith(const std::string& str, const std::string& what)
-{
-  return str.compare(0, what.size(), what) == 0;
-}
-
 // Strips one argument from the cmdline and returns it. "surrounding quotes"
 // are removed from the argument if there were any.
 static std::string getArg(std::string& cmdline)
 {
-  std::string ret;
   bool in_quoted = false;
   unsigned int i = 0;
 
-  cmdline = trimLeadingSpace(cmdline);
+  cm::string_view cmdview = trimLeadingSpace(cmdline);
+  size_t spaceCnt = cmdline.size() - cmdview.size();
 
   for (;; ++i) {
-    if (i >= cmdline.size())
+    if (i >= cmdview.size())
       usage("Couldn't parse arguments.");
-    if (!in_quoted && cmdline[i] == ' ')
+    if (!in_quoted && cmdview[i] == ' ')
       break; // "a b" "x y"
-    if (cmdline[i] == '"')
+    if (cmdview[i] == '"')
       in_quoted = !in_quoted;
   }
 
-  ret = cmdline.substr(0, i);
-  if (ret[0] == '"' && ret[i - 1] == '"')
-    ret = ret.substr(1, ret.size() - 2);
-  cmdline = cmdline.substr(i);
+  cmdview = cmdview.substr(0, i);
+  if (cmdview[0] == '"' && cmdview[i - 1] == '"')
+    cmdview = cmdview.substr(1, i - 2);
+  std::string ret(cmdview);
+  cmdline.erase(0, spaceCnt + i);
   return ret;
 }
 
@@ -127,7 +124,7 @@ static void parseCommandLine(LPWSTR wincmdline, std::string& lang,
   prefix = getArg(cmdline);
   clpath = getArg(cmdline);
   binpath = getArg(cmdline);
-  rest = trimLeadingSpace(cmdline);
+  rest = std::string(trimLeadingSpace(cmdline));
 }
 
 // Not all backslashes need to be escaped in a depfile, but it's easier that
@@ -169,8 +166,8 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile,
     // build.ninja file.  Therefore we need to canonicalize the path to use
     // backward slashes and relativize the path to the build directory.
     replaceAll(tmp, "/", "\\");
-    if (startsWith(tmp, cwd))
-      tmp = tmp.substr(cwd.size());
+    if (cmHasPrefix(tmp, cwd))
+      tmp.erase(0, cwd.size());
     escapePath(tmp);
     fprintf(out, "%s \\\n", tmp.c_str());
   }
@@ -194,7 +191,7 @@ std::string replace(const std::string& str, const std::string& what,
   return replaced.replace(pos, what.size(), replacement);
 }
 
-static int process(const std::string& srcfilename, const std::string& dfile,
+static int process(cm::string_view srcfilename, const std::string& dfile,
                    const std::string& objfile, const std::string& prefix,
                    const std::string& cmd, const std::string& dir = "",
                    bool quiet = false)
@@ -221,13 +218,14 @@ static int process(const std::string& srcfilename, const std::string& dfile,
   std::vector<std::string> includes;
   bool isFirstLine = true; // cl prints always first the source filename
   while (std::getline(ss, line)) {
-    if (startsWith(line, prefix)) {
-      std::string inc = trimLeadingSpace(line.substr(prefix.size()).c_str());
+    cm::string_view inc(line);
+    if (cmHasPrefix(inc, prefix)) {
+      inc = trimLeadingSpace(inc.substr(prefix.size()));
       if (inc.back() == '\r') // blech, stupid \r\n
         inc = inc.substr(0, inc.size() - 1);
-      includes.push_back(inc);
+      includes.emplace_back(std::string(inc));
     } else {
-      if (!isFirstLine || !startsWith(line, srcfilename)) {
+      if (!isFirstLine || !cmHasPrefix(inc, srcfilename)) {
         if (!quiet || exit_code != 0) {
           fprintf(stdout, "%s\n", line.c_str());
         }
@@ -258,14 +256,10 @@ int main()
                    cl, binpath, rest);
 
   // needed to suppress filename output of msvc tools
-  std::string srcfilename;
-  {
-    std::string::size_type pos = srcfile.rfind('\\');
-    if (pos == std::string::npos) {
-      srcfilename = srcfile;
-    } else {
-      srcfilename = srcfile.substr(pos + 1);
-    }
+  cm::string_view srcfilename(srcfile);
+  std::string::size_type pos = srcfile.rfind('\\');
+  if (pos != std::string::npos) {
+    srcfilename = srcfilename.substr(pos + 1);
   }
 
   std::string nol = " /nologo ";
@@ -286,7 +280,7 @@ int main()
     // call cl in object dir so the .i is generated there
     std::string objdir;
     {
-      std::string::size_type pos = objfile.rfind("\\");
+      pos = objfile.rfind("\\");
       if (pos != std::string::npos) {
         objdir = objfile.substr(0, pos);
       }

+ 5 - 6
Source/cmcmd.cxx

@@ -1054,8 +1054,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
         homeOutDir = args[5];
         startOutDir = args[6];
         depInfo = args[7];
-        if (args.size() >= 9 && args[8].length() >= 8 &&
-            args[8].substr(0, 8) == "--color=") {
+        if (args.size() >= 9 && cmHasLiteralPrefix(args[8], "--color=")) {
           // Enable or disable color based on the switch value.
           color = (args[8].size() == 8 || cmIsOn(args[8].substr(8)));
         }
@@ -1304,7 +1303,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
         } else if (arg == "--debug") {
           pipe.clear();
           isDebug = true;
-        } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) {
+        } else if (cmHasPrefix(arg, pipePrefix)) {
           isDebug = false;
           pipe = arg.substr(pipePrefix.size());
           if (pipe.empty()) {
@@ -1511,7 +1510,7 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args)
   bool newline = true;
   std::string progressDir;
   for (auto const& arg : cmMakeRange(args).advance(2)) {
-    if (arg.find("--switch=") == 0) {
+    if (cmHasLiteralPrefix(arg, "--switch=")) {
       // Enable or disable color based on the switch value.
       std::string value = arg.substr(9);
       if (!value.empty()) {
@@ -1566,7 +1565,7 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
   //   args[3] == --verbose=?
   bool verbose = false;
   if (args.size() >= 4) {
-    if (args[3].find("--verbose=") == 0) {
+    if (cmHasLiteralPrefix(args[3], "--verbose=")) {
       if (!cmIsOff(args[3].substr(10))) {
         verbose = true;
       }
@@ -1826,7 +1825,7 @@ int cmcmd::VisualStudioLink(std::vector<std::string> const& args, int type)
   std::vector<std::string> expandedArgs;
   for (std::string const& i : args) {
     // check for nmake temporary files
-    if (i[0] == '@' && i.find("@CMakeFiles") != 0) {
+    if (i[0] == '@' && !cmHasLiteralPrefix(i, "@CMakeFiles")) {
       cmsys::ifstream fin(i.substr(1).c_str());
       std::string line;
       while (cmSystemTools::GetLineFromStream(fin, line)) {

+ 3 - 3
Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp

@@ -32,14 +32,14 @@ void compare(const char* refName, const char* testName)
     // trailing null to the string that we need to strip before testing for a
     // trailing space.
     if (refLine.size() && refLine[refLine.size() - 1] == 0) {
-      refLine = refLine.substr(0, refLine.size() - 1);
+      refLine.resize(refLine.size() - 1);
     }
     if (testLine.size() && testLine[testLine.size() - 1] == 0) {
-      testLine = testLine.substr(0, testLine.size() - 1);
+      testLine.resize(testLine.size() - 1);
     }
     // The reference files never have trailing spaces:
     if (testLine.size() && testLine[testLine.size() - 1] == ' ') {
-      testLine = testLine.substr(0, testLine.size() - 1);
+      testLine.resize(testLine.size() - 1);
     }
     if (refLine != testLine) {
       std::cout << "Ref and test are not the same:\n  Ref:  \"" << refLine