Hi, this is my first post to this list.

When generating a dependency graph of a large project with many external
libraries, there are so many external libs that one doesn't see the
important dependencies any more. On top of that they have also the full
absolute path in the graph.
So with this patch, I can define regex replace rules to group the
external libraries together. The replace rule I mentioned in the
documentation gives me only one graph node for all boost libraries, only
one graph node for the visualization library, and only one node for the
numerics library...

My first implementation was using std::regex, but since cmake has to
compile with older compilers, I extracted the RegexReplace functionality
from the string processor, and put it in a new file. For the moment I
commented out the error reporting. I'm not sure how that would be
handled best. That's where I could use some input.

The current state is attached as patch files, but you can also view it
at: 
https://github.com/Kitware/CMake/compare/master...ulrichard:compact_dependency_graph

Rgds
Richard



From d4221498597186d830c4f0fe4c3b4317cc657643 Mon Sep 17 00:00:00 2001
From: Richard Ulrich <[email protected]>
Date: Wed, 20 May 2015 22:32:59 +0200
Subject: [PATCH 1/3] started implementing

---
 Modules/CMakeGraphVizOptions.cmake | 16 ++++++++++++
 Source/CMakeLists.txt              |  2 ++
 Source/cmGraphVizWriter.cxx        | 52 +++++++++++++++++++++++++++++++++++---
 Source/cmGraphVizWriter.h          |  5 ++++
 4 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index ff18267..cd17782 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -107,6 +107,22 @@
 #
 #  * Mandatory : NO
 #  * Default   : TRUE
+#
+# .. variable:: GRAPHVIZ_NODE_FILTER
+#
+#  A list of regular replace expressions for chnging the name of nodes.
+#  This can be used to strip the path from external library names,
+#  or normalize the name of different files from the same library to one common name.
+#
+#  * Mandatory : NO
+#  * Default   : 
+#
+# .. variable:: GRAPHVIZ_NODE_GROUP
+#
+#  Set this to TRUE to group all nodes with the same name into one common node.
+#
+#  * Mandatory : NO
+#  * Default   : FALSE
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 6f12785..95c60f0 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -45,6 +45,8 @@ endif()
 
 set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
 
+add_definitions(-std=c++11)
+
 # ensure Unicode friendly APIs are used on Windows
 if(WIN32)
   add_definitions(-DUNICODE -D_UNICODE)
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index bbbfc24..4bc23c4 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -122,6 +122,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
   __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
   __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
   __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
+  __set_bool_if_set(this->GenerateGrouped, "GRAPHVIZ_NODE_GROUP");
 
   std::string ignoreTargetsRegexes;
   __set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
@@ -148,6 +149,40 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
       }
     }
 
+  std::string nodeNameFilterRegexes;
+  __set_if_set(nodeNameFilterRegexes, "GRAPHVIZ_NODE_FILTER");
+
+  this->GraphNodeNameFilters.clear();
+  if (!nodeNameFilterRegexes.empty())
+    {
+    std::vector<std::string> nodeNameFilterRegExVector;
+    cmSystemTools::ExpandListArgument(nodeNameFilterRegexes,
+                                      nodeNameFilterRegExVector);
+    for(std::vector<std::string>::const_iterator
+        itvIt = nodeNameFilterRegExVector.begin();
+        itvIt != nodeNameFilterRegExVector.end();
+        ++ itvIt )
+      {
+      const std::string currentRegexString(*itvIt);
+      const std::string currentReplaceString(*++itvIt);
+      try
+        {
+        std::regex currentRegex(currentRegexString, std::regex::extended);
+        this->GraphNodeNameFilters.push_back(
+            std::make_pair(currentRegex, currentReplaceString));
+        }
+      catch(std::regex_error& e)
+        {
+        std::cerr << "Could not compile bad regex \"" << currentRegexString
+                  << "\"" << std::endl
+                  << e.what() << std::endl;
+        }
+
+      if(itvIt == nodeNameFilterRegExVector.end())
+         break;
+      }
+    }
+
 }
 
 
@@ -542,14 +577,16 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
           continue;
           }
 
+        const std::string libNameMangled = this->MangleNodeName(libName);
+
         std::map<std::string, const cmTarget*>::const_iterator tarIt =
-                                                this->TargetPtrs.find(libName);
+                                                this->TargetPtrs.find(libNameMangled);
         if ( tarIt == this->TargetPtrs.end() )
           {
           std::ostringstream ostr;
           ostr << this->GraphNodePrefix << cnt++;
-          this->TargetNamesNodes[libName] = ostr.str();
-          this->TargetPtrs[libName] = NULL;
+          this->TargetNamesNodes[libNameMangled] = ostr.str();
+          this->TargetPtrs[libNameMangled] = NULL;
           // str << "    \"" << ostr.c_str() << "\" [ label=\"" << libName
           // <<  "\" shape=\"ellipse\"];" << std::endl;
           }
@@ -581,6 +618,15 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
 }
 
 
+std::string cmGraphVizWriter::MangleNodeName(std::string name)
+{
+  for(const auto& replacer : this->GraphNodeNameFilters)
+    name = std::regex_replace(name, replacer.first, replacer.second);
+
+  return name;
+}
+
+
 bool cmGraphVizWriter::GenerateForTargetType(cmTarget::TargetType targetType)
                                                                           const
 {
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index a7acd0e..477beff 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -16,6 +16,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmTarget.h"
 #include <cmsys/RegularExpression.hxx>
+#include <regex>
 
 
 /** This class implements writing files for graphviz (dot) for graphs
@@ -61,6 +62,7 @@ protected:
   void WriteFooter(cmGeneratedFileStream& str) const;
 
   bool IgnoreThisTarget(const std::string& name);
+  std::string MangleNodeName(std::string name);
 
   bool GenerateForTargetType(cmTarget::TargetType targetType) const;
 
@@ -76,8 +78,11 @@ protected:
   bool GenerateForExternals;
   bool GeneratePerTarget;
   bool GenerateDependers;
+  bool GenerateGrouped;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
+  typedef std::pair<std::regex, std::string> RegularReplace;
+  std::vector<RegularReplace> GraphNodeNameFilters;
 
   const std::vector<cmLocalGenerator*>& LocalGenerators;
 
-- 
2.1.4

From 9b2fd6ebeebefce03e79e83c77f419056911ff98 Mon Sep 17 00:00:00 2001
From: Richard Ulrich <[email protected]>
Date: Thu, 21 May 2015 23:51:22 +0200
Subject: [PATCH 2/3] working prototype

---
 Modules/CMakeGraphVizOptions.cmake | 12 +++++-------
 Source/cmGraphVizWriter.cxx        | 16 ++++++++++++----
 Source/cmGraphVizWriter.h          |  3 +--
 3 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index cd17782..2312658 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -110,19 +110,17 @@
 #
 # .. variable:: GRAPHVIZ_NODE_FILTER
 #
-#  A list of regular replace expressions for chnging the name of nodes.
+#  A list of regular replace expressions for chnging the name of external library nodes.
+#  They are organized in pairs of regex and replace expression.
 #  This can be used to strip the path from external library names,
 #  or normalize the name of different files from the same library to one common name.
+#  The following is an example of an expression pair to strip the path and group by
+#  library name such as "boost" or "sigc" : 
+#  "([A-Z]:)?/([^/]+/)*lib([A-Za-z]+).*\\.(lib|so|dll)" "$3"
 #
 #  * Mandatory : NO
 #  * Default   : 
 #
-# .. variable:: GRAPHVIZ_NODE_GROUP
-#
-#  Set this to TRUE to group all nodes with the same name into one common node.
-#
-#  * Mandatory : NO
-#  * Default   : FALSE
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 4bc23c4..1e8a95d 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -122,7 +122,6 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
   __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
   __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
   __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
-  __set_bool_if_set(this->GenerateGrouped, "GRAPHVIZ_NODE_GROUP");
 
   std::string ignoreTargetsRegexes;
   __set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
@@ -367,10 +366,16 @@ void cmGraphVizWriter::WriteConnections(const std::string& targetName,
        llit != ll->end();
        ++ llit )
     {
-    const char* libName = llit->first.c_str();
+    std::string libName = llit->first.c_str();
     std::map<std::string, std::string>::const_iterator libNameIt =
                                           this->TargetNamesNodes.find(libName);
 
+    if(libNameIt == this->TargetNamesNodes.end())
+      {
+      libName = this->MangleNodeName(libName);
+      libNameIt = this->TargetNamesNodes.find(libName);
+      }
+
     // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used
     if(libNameIt == this->TargetNamesNodes.end())
       {
@@ -618,10 +623,13 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
 }
 
 
-std::string cmGraphVizWriter::MangleNodeName(std::string name)
+std::string cmGraphVizWriter::MangleNodeName(std::string name) const
 {
   for(const auto& replacer : this->GraphNodeNameFilters)
-    name = std::regex_replace(name, replacer.first, replacer.second);
+    if(std::regex_search(name, replacer.first))
+      {
+      name = std::regex_replace(name, replacer.first, replacer.second); 
+      }
 
   return name;
 }
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index 477beff..c3b1427 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -62,7 +62,7 @@ protected:
   void WriteFooter(cmGeneratedFileStream& str) const;
 
   bool IgnoreThisTarget(const std::string& name);
-  std::string MangleNodeName(std::string name);
+  std::string MangleNodeName(std::string name) const;
 
   bool GenerateForTargetType(cmTarget::TargetType targetType) const;
 
@@ -78,7 +78,6 @@ protected:
   bool GenerateForExternals;
   bool GeneratePerTarget;
   bool GenerateDependers;
-  bool GenerateGrouped;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
   typedef std::pair<std::regex, std::string> RegularReplace;
-- 
2.1.4

From da2d579289d0bb537a3596bcc0f650615c43c65a Mon Sep 17 00:00:00 2001
From: Richard Ulrich <[email protected]>
Date: Mon, 25 May 2015 20:13:56 +0200
Subject: [PATCH 3/3] * compileable with C++98 * factored out RegexReplace into
 a separate file * error handling commented out -> need to find a way to pass
 the info

---
 Modules/CMakeGraphVizOptions.cmake |   2 +-
 Source/CMakeLists.txt              |   4 +-
 Source/cmGraphVizWriter.cxx        |  24 ++----
 Source/cmGraphVizWriter.h          |   3 +-
 Source/cmRegexTools.cxx            | 155 +++++++++++++++++++++++++++++++++++++
 Source/cmRegexTools.h              |  20 +++++
 Source/cmStringCommand.cxx         | 132 ++-----------------------------
 Source/cmStringCommand.h           |  10 ---
 8 files changed, 194 insertions(+), 156 deletions(-)
 create mode 100644 Source/cmRegexTools.cxx
 create mode 100644 Source/cmRegexTools.h

diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index 2312658..af6ddbb 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -116,7 +116,7 @@
 #  or normalize the name of different files from the same library to one common name.
 #  The following is an example of an expression pair to strip the path and group by
 #  library name such as "boost" or "sigc" : 
-#  "([A-Z]:)?/([^/]+/)*lib([A-Za-z]+).*\\.(lib|so|dll)" "$3"
+#  "([A-Z]:)?/([^/]+/)*lib([A-Za-z]+).*\\.(lib|so|dll)" "\\3"
 #
 #  * Mandatory : NO
 #  * Default   : 
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 95c60f0..efc9dd0 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -45,8 +45,6 @@ endif()
 
 set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
 
-add_definitions(-std=c++11)
-
 # ensure Unicode friendly APIs are used on Windows
 if(WIN32)
   add_definitions(-DUNICODE -D_UNICODE)
@@ -321,6 +319,8 @@ set(SRCS
   cmPropertyMap.h
   cmQtAutoGenerators.cxx
   cmQtAutoGenerators.h
+  cmRegexTools.h
+  cmRegexTools.cxx
   cmRST.cxx
   cmRST.h
   cmScriptGenerator.h
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 1e8a95d..bc40ffa 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -14,6 +14,7 @@
 #include "cmLocalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmGeneratedFileStream.h"
+#include "cmRegexTools.h"
 
 
 
@@ -164,18 +165,8 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
       {
       const std::string currentRegexString(*itvIt);
       const std::string currentReplaceString(*++itvIt);
-      try
-        {
-        std::regex currentRegex(currentRegexString, std::regex::extended);
-        this->GraphNodeNameFilters.push_back(
-            std::make_pair(currentRegex, currentReplaceString));
-        }
-      catch(std::regex_error& e)
-        {
-        std::cerr << "Could not compile bad regex \"" << currentRegexString
-                  << "\"" << std::endl
-                  << e.what() << std::endl;
-        }
+      this->GraphNodeNameFilters.push_back(
+            std::make_pair(currentRegexString, currentReplaceString));
 
       if(itvIt == nodeNameFilterRegExVector.end())
          break;
@@ -625,11 +616,10 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
 
 std::string cmGraphVizWriter::MangleNodeName(std::string name) const
 {
-  for(const auto& replacer : this->GraphNodeNameFilters)
-    if(std::regex_search(name, replacer.first))
-      {
-      name = std::regex_replace(name, replacer.first, replacer.second); 
-      }
+  for(std::vector<RegularReplace>::const_iterator it = this->GraphNodeNameFilters.begin();
+      it != this->GraphNodeNameFilters.end();
+      ++it)
+    name = RegexReplace(name, it->first, it->second); 
 
   return name;
 }
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index c3b1427..c5ca07d 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -16,7 +16,6 @@
 #include "cmGeneratedFileStream.h"
 #include "cmTarget.h"
 #include <cmsys/RegularExpression.hxx>
-#include <regex>
 
 
 /** This class implements writing files for graphviz (dot) for graphs
@@ -80,7 +79,7 @@ protected:
   bool GenerateDependers;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
-  typedef std::pair<std::regex, std::string> RegularReplace;
+  typedef std::pair<std::string, std::string> RegularReplace;
   std::vector<RegularReplace> GraphNodeNameFilters;
 
   const std::vector<cmLocalGenerator*>& LocalGenerators;
diff --git a/Source/cmRegexTools.cxx b/Source/cmRegexTools.cxx
new file mode 100644
index 0000000..80c44c7
--- /dev/null
+++ b/Source/cmRegexTools.cxx
@@ -0,0 +1,155 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmRegexTools.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <vector>
+
+//----------------------------------------------------------------------------
+namespace
+{
+  class RegexReplacement
+  {
+  public:
+    RegexReplacement(const char* s): number(-1), value(s) {}
+    RegexReplacement(const std::string& s): number(-1), value(s) {}
+    RegexReplacement(int n): number(n), value() {}
+    RegexReplacement() {}
+    int number;
+    std::string value;
+  };
+}
+//----------------------------------------------------------------------------
+std::string RegexReplace(std::string const& input, std::string const& regex, std::string const& replace)
+{
+  // Pull apart the replace expression to find the escaped [0-9] values.
+  std::vector<RegexReplacement> replacement;
+  std::string::size_type l = 0;
+  while(l < replace.length())
+    {
+    std::string::size_type r = replace.find("\\", l);
+    if(r == std::string::npos)
+      {
+      r = replace.length();
+      replacement.push_back(replace.substr(l, r-l));
+      }
+    else
+      {
+      if(r-l > 0)
+        {
+        replacement.push_back(replace.substr(l, r-l));
+        }
+      if(r == (replace.length()-1))
+        {
+//        this->SetError("sub-command REGEX, mode REPLACE: "
+//                       "replace-expression ends in a backslash.");
+        return input;
+        }
+      if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
+        {
+        replacement.push_back(replace[r+1]-'0');
+        }
+      else if(replace[r+1] == 'n')
+        {
+        replacement.push_back("\n");
+        }
+      else if(replace[r+1] == '\\')
+        {
+        replacement.push_back("\\");
+        }
+      else
+        {
+        std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
+        e += replace.substr(r, 2);
+        e += "\" in replace-expression.";
+//        this->SetError(e);
+        return input;
+        }
+      r += 2;
+      }
+    l = r;
+    }
+
+  // Compile the regular expression.
+  cmsys::RegularExpression re;
+  if(!re.compile(regex.c_str()))
+    {
+    std::string e =
+      "sub-command REGEX, mode REPLACE failed to compile regex \""+
+      regex+"\".";
+//    this->SetError(e);
+    return input;
+    }
+
+  // Scan through the input for all matches.
+  std::string output;
+  std::string::size_type base = 0;
+  while(re.find(input.c_str()+base))
+    {
+//    this->Makefile->StoreMatches(re);
+    std::string::size_type l2 = re.start();
+    std::string::size_type r = re.end();
+
+    // Concatenate the part of the input that was not matched.
+    output += input.substr(base, l2);
+
+    // Make sure the match had some text.
+    if(r-l2 == 0)
+      {
+      std::string e = "sub-command REGEX, mode REPLACE regex \""+
+        regex+"\" matched an empty string.";
+//      this->SetError(e);
+      return input;
+      }
+
+    // Concatenate the replacement for the match.
+    for(unsigned int i=0; i < replacement.size(); ++i)
+      {
+      if(replacement[i].number < 0)
+        {
+        // This is just a plain-text part of the replacement.
+        output += replacement[i].value;
+        }
+      else
+        {
+        // Replace with part of the match.
+        int n = replacement[i].number;
+        std::string::size_type start = re.start(n);
+        std::string::size_type end = re.end(n);
+        std::string::size_type len = input.length()-base;
+        if((start != std::string::npos) && (end != std::string::npos) &&
+           (start <= len) && (end <= len))
+          {
+          output += input.substr(base+start, end-start);
+          }
+        else
+          {
+          std::string e =
+            "sub-command REGEX, mode REPLACE: replace expression \""+
+            replace+"\" contains an out-of-range escape for regex \""+
+            regex+"\".";
+//          this->SetError(e);
+          return input;
+          }
+        }
+      }
+
+    // Move past the match.
+    base += r;
+    }
+
+  // Concatenate the text after the last match.
+  output += input.substr(base, input.length()-base);
+
+  return output;
+}
diff --git a/Source/cmRegexTools.h b/Source/cmRegexTools.h
new file mode 100644
index 0000000..fb5f4ef
--- /dev/null
+++ b/Source/cmRegexTools.h
@@ -0,0 +1,20 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmRegexTools_h
+#define cmRegexTools_h
+
+#include <string>
+
+std::string RegexReplace(std::string const& input, std::string const& regex, std::string const& replace);
+
+
+#endif
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index edc6afc..db09d52 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -11,6 +11,7 @@
 ============================================================================*/
 #include "cmStringCommand.h"
 #include "cmCryptoHash.h"
+#include "cmRegexTools.h"
 
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/SystemTools.hxx>
@@ -396,132 +397,15 @@ bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
 {
   //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
   // <output variable> <input> [<input>...])\n"
-  std::string regex = args[2];
-  std::string replace = args[3];
-  std::string outvar = args[4];
-
-  // Pull apart the replace expression to find the escaped [0-9] values.
-  std::vector<RegexReplacement> replacement;
-  std::string::size_type l = 0;
-  while(l < replace.length())
-    {
-    std::string::size_type r = replace.find("\\", l);
-    if(r == std::string::npos)
-      {
-      r = replace.length();
-      replacement.push_back(replace.substr(l, r-l));
-      }
-    else
-      {
-      if(r-l > 0)
-        {
-        replacement.push_back(replace.substr(l, r-l));
-        }
-      if(r == (replace.length()-1))
-        {
-        this->SetError("sub-command REGEX, mode REPLACE: "
-                       "replace-expression ends in a backslash.");
-        return false;
-        }
-      if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
-        {
-        replacement.push_back(replace[r+1]-'0');
-        }
-      else if(replace[r+1] == 'n')
-        {
-        replacement.push_back("\n");
-        }
-      else if(replace[r+1] == '\\')
-        {
-        replacement.push_back("\\");
-        }
-      else
-        {
-        std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
-        e += replace.substr(r, 2);
-        e += "\" in replace-expression.";
-        this->SetError(e);
-        return false;
-        }
-      r += 2;
-      }
-    l = r;
-    }
-
-  this->Makefile->ClearMatches();
-  // Compile the regular expression.
-  cmsys::RegularExpression re;
-  if(!re.compile(regex.c_str()))
-    {
-    std::string e =
-      "sub-command REGEX, mode REPLACE failed to compile regex \""+
-      regex+"\".";
-    this->SetError(e);
-    return false;
-    }
-
+  const std::string regex = args[2];
+  const std::string replace = args[3];
+  const std::string outvar = args[4];
   // Concatenate all the last arguments together.
-  std::string input = cmJoin(cmRange(args).advance(5), std::string());
+  const std::string input = cmJoin(cmRange(args).advance(5), std::string());
 
-  // Scan through the input for all matches.
-  std::string output;
-  std::string::size_type base = 0;
-  while(re.find(input.c_str()+base))
-    {
-    this->Makefile->StoreMatches(re);
-    std::string::size_type l2 = re.start();
-    std::string::size_type r = re.end();
-
-    // Concatenate the part of the input that was not matched.
-    output += input.substr(base, l2);
-
-    // Make sure the match had some text.
-    if(r-l2 == 0)
-      {
-      std::string e = "sub-command REGEX, mode REPLACE regex \""+
-        regex+"\" matched an empty string.";
-      this->SetError(e);
-      return false;
-      }
-
-    // Concatenate the replacement for the match.
-    for(unsigned int i=0; i < replacement.size(); ++i)
-      {
-      if(replacement[i].number < 0)
-        {
-        // This is just a plain-text part of the replacement.
-        output += replacement[i].value;
-        }
-      else
-        {
-        // Replace with part of the match.
-        int n = replacement[i].number;
-        std::string::size_type start = re.start(n);
-        std::string::size_type end = re.end(n);
-        std::string::size_type len = input.length()-base;
-        if((start != std::string::npos) && (end != std::string::npos) &&
-           (start <= len) && (end <= len))
-          {
-          output += input.substr(base+start, end-start);
-          }
-        else
-          {
-          std::string e =
-            "sub-command REGEX, mode REPLACE: replace expression \""+
-            replace+"\" contains an out-of-range escape for regex \""+
-            regex+"\".";
-          this->SetError(e);
-          return false;
-          }
-        }
-      }
-
-    // Move past the match.
-    base += r;
-    }
-
-  // Concatenate the text after the last match.
-  output += input.substr(base, input.length()-base);
+  this->Makefile->ClearMatches();
+  // Call the implementation that was factored out
+  const std::string output = ::RegexReplace(input, regex, replace);
 
   // Store the output in the provided variable.
   this->Makefile->AddDefinition(outvar, output.c_str());
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 9c75095..de4f93f 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -76,16 +76,6 @@ protected:
   bool HandleGenexStripCommand(std::vector<std::string> const& args);
   bool HandleUuidCommand(std::vector<std::string> const& args);
 
-  class RegexReplacement
-  {
-  public:
-    RegexReplacement(const char* s): number(-1), value(s) {}
-    RegexReplacement(const std::string& s): number(-1), value(s) {}
-    RegexReplacement(int n): number(n), value() {}
-    RegexReplacement() {}
-    int number;
-    std::string value;
-  };
 };
 
 
-- 
2.1.4

Attachment: signature.asc
Description: This is a digitally signed message part

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to