From 6e5cdd6de72de0d9d8f91c9971f0c13e10511c73 Mon Sep 17 00:00:00 2001
From: Andy Cedilnik <andy.cedilnik@kitware.com>
Date: Mon, 17 Oct 2005 09:10:20 -0400
Subject: ENH: Add regular string replace (not regex), and relative path
 command. Also add tests

---
 Source/cmFileCommand.cxx            | 39 +++++++++++++++++++++++++++++++++++++
 Source/cmFileCommand.h              |  5 ++++-
 Source/cmStringCommand.cxx          | 30 ++++++++++++++++++++++++++++
 Source/cmStringCommand.h            | 10 ++++++++++
 Tests/StringFileTest/CMakeLists.txt |  5 +++++
 Tests/StringFileTest/StringFile.cxx |  2 ++
 6 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 8b9daa2..4a06cb4 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -58,6 +58,10 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args)
     {
     return this->HandleInstallCommand(args);
     }
+  else if ( subCommand == "RELATIVE_PATH" )
+    {
+    return this->HandleRelativePathCommand(args);
+    }
 
   std::string e = "does not recognize sub-command "+subCommand;
   this->SetError(e.c_str());
@@ -696,3 +700,38 @@ bool cmFileCommand::HandleInstallCommand(
 
   return true;
 }
+
+//----------------------------------------------------------------------------
+bool cmFileCommand::HandleRelativePathCommand(
+  std::vector<std::string> const& args)
+{
+  if(args.size() != 4 )
+    {
+    this->SetError("called with incorrect number of arguments");
+    return false;
+    }
+
+  const std::string& outVar = args[1];
+  const std::string& directoryName = args[2];
+  const std::string& fileName = args[3];
+
+  if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
+    {
+    std::string errstring = "RelativePath must be passed a full path to the directory: " + directoryName;
+    this->SetError(errstring.c_str());
+    return false;
+    }
+  if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
+    {
+    std::string errstring = "RelativePath must be passed a full path to the directory: " + directoryName;
+    this->SetError(errstring.c_str());
+    return false;
+    }
+
+  std::string res = cmSystemTools::RelativePath(directoryName.c_str(), fileName.c_str());
+  m_Makefile->AddDefinition(outVar.c_str(),
+    res.c_str());
+  return true;
+}
+
+
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
index 71bca90..9243180 100644
--- a/Source/cmFileCommand.h
+++ b/Source/cmFileCommand.h
@@ -70,6 +70,7 @@ public:
       "  FILE(GLOB variable [globbing expressions]...)\n"
       "  FILE(GLOB_RECURSE variable [globbing expressions]...)\n"
       "  FILE(MAKE_DIRECTORY [directory]...)\n"
+      "  FILE(RELATIVE_PATH variable directory file)\n"
       "WRITE will write a message into a file called 'filename'. It "
       "overwrites the file if it already exists, and creates the file "
       "if it does not exists.\n"
@@ -93,7 +94,8 @@ public:
       "match the files.\n"
       "Example of recursive globbing:\n"
       "   /dir/*.py  - match all python files /dir and subdirectories\n"
-      "MAKE_DIRECTORY will create a directory at the specified location"; 
+      "MAKE_DIRECTORY will create a directory at the specified location\n"
+      "RELATIVE_PATH will determine relative path from directory to the given file";
     }
   
   cmTypeMacro(cmFileCommand, cmCommand);
@@ -104,6 +106,7 @@ protected:
   bool HandleGlobCommand(std::vector<std::string> const& args, bool recurse);
   bool HandleMakeDirectoryCommand(std::vector<std::string> const& args);
   bool HandleInstallCommand(std::vector<std::string> const& args);
+  bool HandleRelativePathCommand(std::vector<std::string> const& args);
 };
 
 
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 76d60e0..dc592ba 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -16,6 +16,7 @@
 =========================================================================*/
 #include "cmStringCommand.h"
 #include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
 
 #include <stdlib.h> // required for atoi
 #include <ctype.h>
@@ -33,6 +34,10 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args)
     {
     return this->HandleRegexCommand(args);
     }
+  else if(subCommand == "REPLACE")
+    {
+    return this->HandleReplaceCommand(args);
+    }
   else if(subCommand == "TOLOWER")
     {
     return this->HandleToUpperLowerCommand(args, false);
@@ -492,3 +497,28 @@ bool cmStringCommand::HandleCompareCommand(std::vector<std::string> const& args)
   this->SetError(e.c_str());
   return false;
 }
+
+//----------------------------------------------------------------------------
+bool cmStringCommand::HandleReplaceCommand(std::vector<std::string> const& args)
+{
+  if(args.size() < 5)
+    {
+    this->SetError("sub-command REPLACE requires four arguments.");
+    return false;
+    }
+
+  const std::string& matchExpression = args[1];
+  const std::string& replaceExpression = args[2];
+  const std::string& variableName = args[3];
+
+  std::string input = args[4];
+  for(unsigned int i=5; i < args.size(); ++i)
+    {
+    input += args[i];
+    }
+
+  cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(), replaceExpression.c_str());
+
+  m_Makefile->AddDefinition(variableName.c_str(), input.c_str());
+  return true;
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 91463c4..cbdf811 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -71,6 +71,9 @@ public:
       "  STRING(REGEX REPLACE <regular_expression>\n"
       "         <replace_expression> <output variable>\n"
       "         <input> [<input>...])\n"
+      "  STRING(REPLACE <match_expression>\n"
+      "         <replace_expression> <output variable>\n"
+      "         <input> [<input>...])\n"
       "  STRING(COMPARE EQUAL <string1> <string2> <output variable>)\n"
       "  STRING(COMPARE NOTEQUAL <string1> <string2> <output variable>)\n"
       "  STRING(COMPARE LESS <string1> <string2> <output variable>)\n"
@@ -90,6 +93,12 @@ public:
       "subexpressions of the match using \\1, \\2, ..., \\9.  Note that "
       "two backslashes (\\\\1) are required in CMake code to get a "
       "backslash through argument parsing.\n"
+      "REPLACE will match the given expression "
+      "and substitute the replacement expression for the match "
+      "in the output.  The replace expression may refer to paren-delimited "
+      "subexpressions of the match using \\1, \\2, ..., \\9.  Note that "
+      "two backslashes (\\\\1) are required in CMake code to get a "
+      "backslash through argument parsing.\n"
       "COMPARE EQUAL/NOTEQUAL/LESS/GREATER will compare the strings and "
       "store true or false in the output variable.\n"
       "ASCII will convert all numbers into corresponding ASCII characters.\n"
@@ -108,6 +117,7 @@ protected:
   bool RegexReplace(std::vector<std::string> const& args);
   bool HandleToUpperLowerCommand(std::vector<std::string> const& args, bool toUpper);
   bool HandleCompareCommand(std::vector<std::string> const& args);
+  bool HandleReplaceCommand(std::vector<std::string> const& args);
   
   class RegexReplacement
   {
diff --git a/Tests/StringFileTest/CMakeLists.txt b/Tests/StringFileTest/CMakeLists.txt
index 298f694..373e811 100644
--- a/Tests/StringFileTest/CMakeLists.txt
+++ b/Tests/StringFileTest/CMakeLists.txt
@@ -20,6 +20,9 @@ STRING(COMPARE GREATER "max" "min" ncgvar)
 STRING(ASCII 67 109 97 107 101 savar)
 STRING(TOUPPER "CMake" tuvar)
 STRING(TOLOWER "CMake" tlvar)
+STRING(REPLACE "Autoconf" "CMake" repvar "People should use Autoconf")
+
+FILE(RELATIVE_PATH relpath "/usr/local/bin" "/usr/X11R6/bin/xnest")
 
 # Escaping test
 SET(var "\\ \" \  \t \n \r \# \( \) \0")
@@ -49,6 +52,8 @@ FOREACH(var
     rmvar
     rmallvar
     rrepvar
+    repvar
+    relpath
     nceqvar
     ceqvar
     cneqvar
diff --git a/Tests/StringFileTest/StringFile.cxx b/Tests/StringFileTest/StringFile.cxx
index bc2312b..67d7c5f 100644
--- a/Tests/StringFileTest/StringFile.cxx
+++ b/Tests/StringFileTest/StringFile.cxx
@@ -9,6 +9,7 @@ int main(int, char*[])
   res += CheckMethod(rmvar, "CMake");
   res += CheckMethod(rmallvar, "CMake;cmake;CMake");
   res += CheckMethod(rrepvar, "People should use CMake and CMake");
+  res += CheckMethod(repvar, "People should use CMake");
   res += CheckMethod(nceqvar, "0");
   res += CheckMethod(ceqvar, "1");
   res += CheckMethod(cneqvar, "1");
@@ -20,6 +21,7 @@ int main(int, char*[])
   res += CheckMethod(savar, "Cmake");
   res += CheckMethod(tuvar, "CMAKE");
   res += CheckMethod(tlvar, "cmake");
+  res += CheckMethod(relpath, "../../X11R6/bin/xnest");
   
   return res;
 }
-- 
cgit v0.12