Merge topic 'cmStringAlgorithms'

f71f7ce3f0 cmStringAlgorithms: Move string functions to the new cmStringAlgorithms.h

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3618
diff --git a/.gitattributes b/.gitattributes
index 24fd9c2..3854b73 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,4 @@
-.gitattributes   export-ignore
+.git*            export-ignore
 .hooks*          export-ignore
 
 # Custom attribute to mark sources as using our C code style.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5efa077..75ac8bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -626,8 +626,7 @@
 # The main section of the CMakeLists file
 #
 #-----------------------------------------------------------------------
-# Compute CMake_VERSION, etc.
-include(Source/CMakeVersionCompute.cmake)
+include(Source/CMakeVersion.cmake)
 
 # Include the standard Dart testing module
 enable_testing()
diff --git a/Source/.gitattributes b/Source/.gitattributes
index 7c160cc..d0aedc2 100644
--- a/Source/.gitattributes
+++ b/Source/.gitattributes
@@ -1,2 +1,4 @@
+CMakeVersion.cmake    export-subst
+
 # Do not format third-party sources.
 /kwsys/**                                  -format.clang-format-6.0
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 8f6bde0..041c606 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -1161,6 +1161,21 @@
 include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
 
 if(WIN32)
+  # Compute the binary version that appears in the RC file. Version
+  # components in the RC file are 16-bit integers so we may have to
+  # split the patch component.
+  if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$")
+    set(CMake_RCVERSION_YEAR "${CMAKE_MATCH_1}")
+    set(CMake_RCVERSION_MONTH_DAY "${CMAKE_MATCH_2}")
+    string(REGEX REPLACE "^0+" "" CMake_RCVERSION_MONTH_DAY "${CMake_RCVERSION_MONTH_DAY}")
+    set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_RCVERSION_YEAR},${CMake_RCVERSION_MONTH_DAY})
+    unset(CMake_RCVERSION_MONTH_DAY)
+    unset(CMake_RCVERSION_YEAR)
+  else()
+    set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH})
+  endif()
+  set(CMake_RCVERSION_STR ${CMake_VERSION})
+
   # Add Windows executable version information.
   configure_file("CMakeVersion.rc.in" "CMakeVersion.rc" @ONLY)
 
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index bbf8be0..63a4207 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,82 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 15)
-set(CMake_VERSION_PATCH 20190729)
+set(CMake_VERSION_PATCH 20190730)
 #set(CMake_VERSION_RC 0)
+set(CMake_VERSION_IS_DIRTY 0)
+
+# Start with the full version number used in tags.  It has no dev info.
+set(CMake_VERSION
+  "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
+if(DEFINED CMake_VERSION_RC)
+  set(CMake_VERSION "${CMake_VERSION}-rc${CMake_VERSION_RC}")
+endif()
+
+# Releases define a small patch level.
+if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000)
+  set(CMake_VERSION_IS_RELEASE 1)
+else()
+  set(CMake_VERSION_IS_RELEASE 0)
+endif()
+
+if(EXISTS ${CMake_SOURCE_DIR}/.git)
+  find_package(Git QUIET)
+  if(GIT_FOUND)
+    macro(_git)
+      execute_process(
+        COMMAND ${GIT_EXECUTABLE} ${ARGN}
+        WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+        RESULT_VARIABLE _git_res
+        OUTPUT_VARIABLE _git_out OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_VARIABLE _git_err ERROR_STRIP_TRAILING_WHITESPACE
+        )
+    endmacro()
+  endif()
+endif()
+
+# Try to identify the current development source version.
+if(COMMAND _git)
+  # Get the commit checked out in this work tree.
+  _git(log -n 1 HEAD "--pretty=format:%h %s" --)
+  set(git_info "${_git_out}")
+else()
+  # Get the commit exported by 'git archive'.
+  set(git_info [==[$Format:%h %s$]==])
+endif()
+
+# Extract commit information if available.
+if(git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* (.*)$")
+  # Have commit information.
+  set(git_hash "${CMAKE_MATCH_1}")
+  set(git_subject "${CMAKE_MATCH_2}")
+
+  # If this is not the exact commit of a release, add dev info.
+  if(NOT "${git_subject}" MATCHES "^[Cc][Mm]ake ${CMake_VERSION}$")
+    set(CMake_VERSION "${CMake_VERSION}-g${git_hash}")
+  endif()
+
+  # If this is a work tree, check whether it is dirty.
+  if(COMMAND _git)
+    _git(update-index -q --refresh)
+    _git(diff-index --name-only HEAD --)
+    if(_git_out)
+      set(CMake_VERSION_IS_DIRTY 1)
+    endif()
+  endif()
+else()
+  # No commit information.
+  if(NOT CMake_VERSION_IS_RELEASE)
+    # Generic development version.
+    set(CMake_VERSION "${CMake_VERSION}-git")
+  endif()
+endif()
+
+# Extract the version suffix component.
+if(CMake_VERSION MATCHES "-(.*)$")
+  set(CMake_VERSION_SUFFIX "${CMAKE_MATCH_1}")
+else()
+  set(CMake_VERSION_SUFFIX "")
+endif()
+if(CMake_VERSION_IS_DIRTY)
+  set(CMake_VERSION ${CMake_VERSION}-dirty)
+endif()
diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake
deleted file mode 100644
index 160f470..0000000
--- a/Source/CMakeVersionCompute.cmake
+++ /dev/null
@@ -1,44 +0,0 @@
-# Load version number components.
-include(${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake)
-
-# Releases define a small patch level.
-if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000)
-  set(CMake_VERSION_IS_DIRTY 0)
-  set(CMake_VERSION_IS_RELEASE 1)
-  set(CMake_VERSION_SOURCE "")
-else()
-  set(CMake_VERSION_IS_DIRTY 0) # may be set to 1 by CMakeVersionSource
-  set(CMake_VERSION_IS_RELEASE 0)
-  include(${CMake_SOURCE_DIR}/Source/CMakeVersionSource.cmake)
-endif()
-
-# Compute the full version string.
-set(CMake_VERSION ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH})
-if(CMake_VERSION_SOURCE)
-  set(CMake_VERSION_SUFFIX "${CMake_VERSION_SOURCE}")
-elseif(DEFINED CMake_VERSION_RC)
-  set(CMake_VERSION_SUFFIX "rc${CMake_VERSION_RC}")
-else()
-  set(CMake_VERSION_SUFFIX "")
-endif()
-if(CMake_VERSION_SUFFIX)
-  set(CMake_VERSION ${CMake_VERSION}-${CMake_VERSION_SUFFIX})
-endif()
-if(CMake_VERSION_IS_DIRTY)
-  set(CMake_VERSION ${CMake_VERSION}-dirty)
-endif()
-
-# Compute the binary version that appears in the RC file. Version
-# components in the RC file are 16-bit integers so we may have to
-# split the patch component.
-if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$")
-  set(CMake_RCVERSION_YEAR "${CMAKE_MATCH_1}")
-  set(CMake_RCVERSION_MONTH_DAY "${CMAKE_MATCH_2}")
-  string(REGEX REPLACE "^0+" "" CMake_RCVERSION_MONTH_DAY "${CMake_RCVERSION_MONTH_DAY}")
-  set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_RCVERSION_YEAR},${CMake_RCVERSION_MONTH_DAY})
-  unset(CMake_RCVERSION_MONTH_DAY)
-  unset(CMake_RCVERSION_YEAR)
-else()
-  set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH})
-endif()
-set(CMake_RCVERSION_STR ${CMake_VERSION})
diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake
deleted file mode 100644
index 5ea1de3..0000000
--- a/Source/CMakeVersionSource.cmake
+++ /dev/null
@@ -1,30 +0,0 @@
-# Try to identify the current development source version.
-set(CMake_VERSION_SOURCE "")
-if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD)
-  find_program(GIT_EXECUTABLE NAMES git git.cmd)
-  mark_as_advanced(GIT_EXECUTABLE)
-  if(GIT_EXECUTABLE)
-    execute_process(
-      COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=4 HEAD
-      OUTPUT_VARIABLE head
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      WORKING_DIRECTORY ${CMake_SOURCE_DIR}
-      )
-    if(head)
-      set(CMake_VERSION_SOURCE "g${head}")
-      execute_process(
-        COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
-        WORKING_DIRECTORY ${CMake_SOURCE_DIR}
-        )
-      execute_process(
-        COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
-        OUTPUT_VARIABLE dirty
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${CMake_SOURCE_DIR}
-        )
-      if(dirty)
-        set(CMake_VERSION_IS_DIRTY 1)
-      endif()
-    endif()
-  endif()
-endif()
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 0fb3237..8188ffa 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -3061,15 +3061,7 @@
     return false;
   }
 
-  // loop over all function blockers to see if any block this command
-  // evaluate in reverse, this is critical for balanced IF statements etc
-  for (auto const& pos : cmReverseRange(this->FunctionBlockers)) {
-    if (pos->IsFunctionBlocked(lff, *this, status)) {
-      return true;
-    }
-  }
-
-  return false;
+  return this->FunctionBlockers.top()->IsFunctionBlocked(lff, *this, status);
 }
 
 void cmMakefile::PushFunctionBlockerBarrier()
@@ -3084,8 +3076,8 @@
     this->FunctionBlockerBarriers.back();
   while (this->FunctionBlockers.size() > barrier) {
     std::unique_ptr<cmFunctionBlocker> fb(
-      std::move(this->FunctionBlockers.back()));
-    this->FunctionBlockers.pop_back();
+      std::move(this->FunctionBlockers.top()));
+    this->FunctionBlockers.pop();
     if (reportError) {
       // Report the context in which the unclosed block was opened.
       cmListFileContext const& lfc = fb->GetStartingContext();
@@ -3216,46 +3208,36 @@
     fb->SetStartingContext(this->GetExecutionContext());
   }
 
-  this->FunctionBlockers.push_back(std::move(fb));
+  this->FunctionBlockers.push(std::move(fb));
 }
 
 std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker(
   cmFunctionBlocker* fb, const cmListFileFunction& lff)
 {
-  // Find the function blocker stack barrier for the current scope.
-  // We only remove a blocker whose index is not less than the barrier.
-  FunctionBlockersType::size_type barrier = 0;
-  if (!this->FunctionBlockerBarriers.empty()) {
-    barrier = this->FunctionBlockerBarriers.back();
+  assert(!this->FunctionBlockers.empty());
+  assert(this->FunctionBlockers.top().get() == fb);
+  assert(this->FunctionBlockerBarriers.empty() ||
+         this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back());
+
+  // Warn if the arguments do not match, but always remove.
+  if (!fb->ShouldRemove(lff, *this)) {
+    cmListFileContext const& lfc = fb->GetStartingContext();
+    cmListFileContext closingContext =
+      cmListFileContext::FromCommandContext(lff, lfc.FilePath);
+    std::ostringstream e;
+    /* clang-format off */
+    e << "A logical block opening on the line\n"
+      << "  " << lfc << "\n"
+      << "closes on the line\n"
+      << "  " << closingContext << "\n"
+      << "with mis-matching arguments.";
+    /* clang-format on */
+    this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
   }
 
-  // Search for the function blocker whose scope this command ends.
-  for (FunctionBlockersType::size_type i = this->FunctionBlockers.size();
-       i > barrier; --i) {
-    auto pos = this->FunctionBlockers.begin() + (i - 1);
-    if (pos->get() == fb) {
-      // Warn if the arguments do not match, but always remove.
-      if (!(*pos)->ShouldRemove(lff, *this)) {
-        cmListFileContext const& lfc = fb->GetStartingContext();
-        cmListFileContext closingContext =
-          cmListFileContext::FromCommandContext(lff, lfc.FilePath);
-        std::ostringstream e;
-        /* clang-format off */
-        e << "A logical block opening on the line\n"
-          << "  " << lfc << "\n"
-          << "closes on the line\n"
-          << "  " << closingContext << "\n"
-          << "with mis-matching arguments.";
-        /* clang-format on */
-        this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
-      }
-      std::unique_ptr<cmFunctionBlocker> b = std::move(*pos);
-      this->FunctionBlockers.erase(pos);
-      return b;
-    }
-  }
-
-  return std::unique_ptr<cmFunctionBlocker>();
+  auto b = std::move(this->FunctionBlockers.top());
+  this->FunctionBlockers.pop();
+  return b;
 }
 
 std::string const& cmMakefile::GetHomeDirectory() const
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 5d82843..dc196ac 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -20,7 +20,6 @@
 #include "cm_string_view.hxx"
 
 #include "cmAlgorithms.h"
-#include "cmFunctionBlocker.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
 #include "cmNewLineStyle.h"
@@ -40,6 +39,7 @@
 class cmExecutionStatus;
 class cmExpandedCommandArgument;
 class cmExportBuildFileGenerator;
+class cmFunctionBlocker;
 class cmGeneratorExpressionEvaluationFile;
 class cmGlobalGenerator;
 class cmInstallGenerator;
@@ -964,7 +964,9 @@
   bool EnforceUniqueDir(const std::string& srcPath,
                         const std::string& binPath) const;
 
-  typedef std::vector<std::unique_ptr<cmFunctionBlocker>> FunctionBlockersType;
+  using FunctionBlockerPtr = std::unique_ptr<cmFunctionBlocker>;
+  using FunctionBlockersType =
+    std::stack<FunctionBlockerPtr, std::vector<FunctionBlockerPtr>>;
   FunctionBlockersType FunctionBlockers;
   std::vector<FunctionBlockersType::size_type> FunctionBlockerBarriers;
   void PushFunctionBlockerBarrier();
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index ce4cfaf..f52caed 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -7,7 +7,7 @@
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
-  include(${CMake_SOURCE_DIR}/Source/CMakeVersionCompute.cmake)
+  include(${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake)
   include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake)
   unset(CMAKE_DATA_DIR)
   unset(CMAKE_DATA_DIR CACHE)
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index e4e6e05..736a7c0 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -7,7 +7,7 @@
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
-  include(${CMake_SOURCE_DIR}/Source/CMakeVersionCompute.cmake)
+  include(${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake)
   include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake)
   unset(CMAKE_DATA_DIR)
   unset(CMAKE_DATA_DIR CACHE)