From 2617c326d8bcc5139239f69ad0af3dc6e14873b8 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 14 Dec 2018 17:44:07 +0100
Subject: [PATCH] ENH: extend fileName::relative() method

- optionally replace stripped parent directory with the \<case\> shortcut

    "/this/path/and/subdirs/name"

    relative("/this/path")        -> "and/subdirs/name"
    relative("/this/path", true)  -> "\<case\>/and/subdirs/name"
---
 applications/test/fileName/Test-fileName.C    | 12 ++++++---
 .../primitives/strings/fileName/fileName.C    | 26 ++++++++++++++++---
 .../primitives/strings/fileName/fileName.H    | 14 ++++++++--
 3 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/applications/test/fileName/Test-fileName.C b/applications/test/fileName/Test-fileName.C
index 0300c5f8a73..600f3b0c290 100644
--- a/applications/test/fileName/Test-fileName.C
+++ b/applications/test/fileName/Test-fileName.C
@@ -204,11 +204,10 @@ unsigned testRelative(std::initializer_list<Pair<std::string>> tests)
         const std::string& dir    = test.first();
         const std::string& parent = test.second();
 
-        fileName relative = fileName(dir).relative(parent);
-
         Info<< "directory: " << dir << nl
             << "parent   : " << parent << nl
-            << "relative = " << relative << nl
+            << "relative = " << fileName(dir).relative(parent) << nl
+            << "case-rel = " << fileName(dir).relative(parent, true) << nl
             << endl;
     }
 
@@ -537,12 +536,17 @@ int main(int argc, char *argv[])
         nFail += testRelative
         (
             {
+                { "",  "" },
+                { "",  "/" },
+                { "",  "/some" },
+
                 { "/some/dir/subdir/name",  "" },
                 { "/some/dir/subdir/name",  "/" },
                 { "/some/dir/subdir/name",  "/some" },
                 { "/some/dir/subdir/name",  "/some/" },
                 { "/some/dir/subdir/name",  "/some/dir" },
                 { "/some/dir/subdir/name",  "/some/dir/" },
+                { "/some/dir/subdir/name",  "/some/dir/subdir" },
                 { "/some/dir/subdir/name",  "/some/dir/subdir/name" },
                 { "/some/dir/subdir/name",  "/some/dir/subdir/name/" },
                 { "/some/dir/subdir/name",  "/some/other" },
@@ -554,6 +558,7 @@ int main(int argc, char *argv[])
                 { "/some/dir/subdir/a",  "/some/" },
                 { "/some/dir/subdir/a",  "/some/dir" },
                 { "/some/dir/subdir/a",  "/some/dir/" },
+                { "/some/dir/subdir/a",  "/some/dir/subdir" },
                 { "/some/dir/subdir/a",  "/some/dir/subdir/a" },
                 { "/some/dir/subdir/a",  "/some/dir/subdir/a/" },
                 { "/some/dir/subdir/a",  "/some/other" },
@@ -565,6 +570,7 @@ int main(int argc, char *argv[])
                 { "/some/dir/subdir/a/",  "/some/" },
                 { "/some/dir/subdir/a/",  "/some/dir" },
                 { "/some/dir/subdir/a/",  "/some/dir/" },
+                { "/some/dir/subdir/a/",  "/some/dir/subdir/" },
                 { "/some/dir/subdir/a/",  "/some/dir/subdir/a" },
                 { "/some/dir/subdir/a/",  "/some/dir/subdir/a/" },
                 { "/some/dir/subdir/a/",  "/some/other" },
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C
index 58fe305d3b3..1ef148b3e76 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.C
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C
@@ -364,19 +364,37 @@ std::string Foam::fileName::nameLessExt(const std::string& str)
 }
 
 
-Foam::fileName Foam::fileName::relative(const fileName& parent) const
+Foam::fileName Foam::fileName::relative
+(
+    const fileName& parent,
+    const bool caseRelative
+) const
 {
     const auto top = parent.size();
     const fileName& f = *this;
 
-    // Everything after "parent/xxx" -> "xxx"
+    // Everything after "parent/xxx/yyy" -> "xxx/yyy"
+    //
+    // case-relative:
+    //     "parent/xxx/yyy" -> "<case>/xxx/yyy"
     if
     (
-        top && (f.size() > (top+1)) && (*this)[top] == '/'
+        top && (f.size() > (top+1)) && f[top] == '/'
      && f.startsWith(parent)
     )
     {
-        return f.substr(top+1);
+        if (caseRelative)
+        {
+            return "<case>"/f.substr(top+1);
+        }
+        else
+        {
+            return f.substr(top+1);
+        }
+    }
+    else if (caseRelative && f.size() && !f.isAbsolute())
+    {
+        return "<case>"/f;
     }
 
     return f;
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.H b/src/OpenFOAM/primitives/strings/fileName/fileName.H
index 0f7354d3ff9..c760d1956f0 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.H
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.H
@@ -290,8 +290,18 @@ public:
         //- Remove leading path, returning true if string changed.
         inline bool removePath();
 
-        //- Return name after stripping off the parent directory
-        fileName relative(const fileName& parent) const;
+        //- Return a relative name by stripping off the parent directory
+        //- where possible.
+        //
+        //  \param parent the parent directory
+        //  \param caseRelative replace the parent with \<case\> for later
+        //      use with expand(), or prefix \<case\> if the file name was
+        //      not an absolute location
+        fileName relative
+        (
+            const fileName& parent,
+            const bool caseRelative = false
+        ) const;
 
         //- Return file name without extension (part before last .)
         inline fileName lessExt() const;
-- 
GitLab