diff --git a/SystemTools.cxx b/SystemTools.cxx
index 4d0d076f72fe6c3b1faf433b166355c8899eaa4b..a8e4a59ccd0898f2f73658032b93b21fa44e133d 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -1130,6 +1130,29 @@ kwsys_stl::string SystemTools::CropString(const kwsys_stl::string& s,
   return n;
 }
 
+//----------------------------------------------------------------------------
+std::vector<kwsys::String> SystemTools::SplitString(const char* p, char sep, bool isPath)
+{
+  std::string path = p;
+  std::vector<kwsys::String> paths;
+  if(isPath && path[0] == '/')
+    {
+    path.erase(path.begin());
+    paths.push_back("/"); 
+    }
+  std::string::size_type pos1 = 0;
+  std::string::size_type pos2 = path.find(sep, pos1+1);
+  while(pos2 != std::string::npos)
+    {
+    paths.push_back(path.substr(pos1, pos2-pos1));
+    pos1 = pos2+1;
+    pos2 = path.find(sep, pos1+1);
+    } 
+  paths.push_back(path.substr(pos1, pos2-pos1));
+  
+  return paths;
+}
+
 //----------------------------------------------------------------------------
 int SystemTools::EstimateFormatLength(const char *format, va_list ap)
 {
@@ -2395,6 +2418,85 @@ kwsys_stl::string SystemTools::CollapseFullPath(const char* in_path,
   return newPath;
 }
 
+// compute the relative path from here to there
+std::string SystemTools::RelativePath(const char* local, const char* remote)
+{
+  if(!SystemTools::FileIsFullPath(local))
+    {
+    return "";
+    }
+  if(!SystemTools::FileIsFullPath(remote))
+    {
+    return "";
+    }
+  
+  // split up both paths into arrays of strings using / as a separator
+  std::vector<kwsys::String> localSplit = SystemTools::SplitString(local, '/', true); 
+  std::vector<kwsys::String> remoteSplit = SystemTools::SplitString(remote, '/', true);
+  std::vector<kwsys::String> commonPath; // store shared parts of path in this array
+  std::vector<kwsys::String> finalPath;  // store the final relative path here
+  // count up how many matching directory names there are from the start
+  unsigned int sameCount = 0;
+  while(
+    ((sameCount <= (localSplit.size()-1)) && (sameCount <= (remoteSplit.size()-1)))
+    && 
+// for windows and apple do a case insensitive string compare    
+#if defined(_WIN32) || defined(__APPLE__)
+    cmSystemTools::Strucmp(localSplit[sameCount].c_str(),
+                           remoteSplit[sameCount].c_str()) == 0
+#else
+    localSplit[sameCount] == remoteSplit[sameCount]
+#endif
+    )
+    {
+    // put the common parts of the path into the commonPath array
+    commonPath.push_back(localSplit[sameCount]);
+    // erase the common parts of the path from the original path arrays
+    localSplit[sameCount] = "";
+    remoteSplit[sameCount] = "";
+    sameCount++;
+    }
+  // If there is nothing in common but the root directory, then just
+  // return the full path.
+  if(sameCount <= 1)
+    {
+    return remote;
+    }
+  
+  // for each entry that is not common in the local path
+  // add a ../ to the finalpath array, this gets us out of the local
+  // path into the remote dir
+  for(unsigned int i = 0; i < localSplit.size(); ++i)
+    {
+    if(localSplit[i].size())
+      {
+      finalPath.push_back("../");
+      }
+    }
+  // for each entry that is not common in the remote path add it
+  // to the final path.
+  for(std::vector<kwsys_stl::string>::iterator i = remoteSplit.begin();
+      i != remoteSplit.end(); ++i)
+    {
+    if(i->size())
+      {
+      finalPath.push_back(*i);
+      }
+    }
+  std::string relativePath;     // result string
+  // now turn the array of directories into a unix path by puttint / 
+  // between each entry that does not already have one
+  for(std::vector<kwsys_stl::string>::iterator i = finalPath.begin();
+      i != finalPath.end(); ++i)
+    {
+    if(relativePath.size() && relativePath[relativePath.size()-1] != '/')
+      {
+      relativePath += "/";
+      }
+    relativePath += *i;
+    }
+  return relativePath;
+}
 
 // OK, some fun stuff to get the actual case of a given path.
 // Basically, you just need to call ShortPath, then GetLongPathName,
diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in
index 7fa88f56e81086dc693a30f280bc3347928d37dc..9303d7146454184f9642d582f87ce6595070ae80 100644
--- a/SystemTools.hxx.in
+++ b/SystemTools.hxx.in
@@ -20,6 +20,7 @@
 #include <@KWSYS_NAMESPACE@/stl/map>
 
 #include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/String.hxx>
 
 #include <sys/types.h>
 
@@ -176,6 +177,13 @@ public:
    */
   static kwsys_stl::string CropString(const kwsys_stl::string&,size_t max_len);
   
+  /** split a path by separator into an array of strings, default is /.
+      If isPath is true then the string is treated like a path and if
+      s starts with a / then the first element of the returned array will
+      be /, so /foo/bar will be [/, foo, bar]
+  */  
+  static std::vector<String> SplitString(const char* s, char separator = '/', 
+                                         bool isPath = false);
   /**
    * Perform a case-independent string comparison
    */
@@ -574,6 +582,16 @@ public:
   static kwsys_stl::string FileExistsInParentDirectories(const char* fname,
     const char* directory, const char* toplevel);
 
+  /** compute the relative path from local to remote.  local must 
+      be a directory.  remote can be a file or a directory.  
+      Both remote and local must be full paths.  Basically, if
+      you are in directory local and you want to access the file in remote
+      what is the relative path to do that.  For example:
+      /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
+      from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
+  */
+  static std::string RelativePath(const char* local, const char* remote);
+  
   /**
    * Return file's modified time
    */