From 0564efb9e1f32043e0ca814a966220ba37c255df Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 26 May 2017 10:48:01 +0200
Subject: [PATCH] ENH: add basic support for file extensions to word

- when a plain word is used as a directory-local name for file.
  We don't have a full blown fileName, but still want to check/remove
  extensions etc.
---
 .../primitives/strings/fileName/fileName.C    | 83 +++----------------
 .../primitives/strings/fileName/fileName.H    | 19 ++---
 .../primitives/strings/fileName/fileNameI.H   | 33 ++++----
 .../primitives/strings/string/string.C        | 66 ++++++++++++++-
 .../primitives/strings/string/string.H        | 33 ++++++++
 .../primitives/strings/string/stringI.H       | 41 ++++++++-
 src/OpenFOAM/primitives/strings/word/word.C   | 42 ++++++++++
 src/OpenFOAM/primitives/strings/word/word.H   | 33 ++++++++
 src/OpenFOAM/primitives/strings/word/wordI.H  | 12 +++
 .../primitives/strings/wordRe/wordRe.H        |  4 +-
 10 files changed, 265 insertions(+), 101 deletions(-)

diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C
index 258167fc1e0..87ddec68b7c 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.C
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C
@@ -41,15 +41,15 @@ const Foam::fileName Foam::fileName::null;
 Foam::fileName::fileName(const UList<word>& lst)
 {
     // Estimate overall size
-    size_type sz = lst.size();
-    for (const word& item : lst)
+    size_type sz = lst.size();  // Approx number of '/' needed
+    for (const auto& item : lst)
     {
         sz += item.size();
     }
     reserve(sz);
 
     sz = 0;
-    for (const word& item : lst)
+    for (const auto& item : lst)
     {
         if (item.size())
         {
@@ -63,15 +63,15 @@ Foam::fileName::fileName(const UList<word>& lst)
 Foam::fileName::fileName(std::initializer_list<word> lst)
 {
     // Estimate overall size
-    size_type sz = lst.size();
-    for (const word& item : lst)
+    size_type sz = lst.size();  // Approx number of '/' needed
+    for (const auto& item : lst)
     {
         sz += item.size();
     }
     reserve(sz);
 
     sz = 0;
-    for (const word& item : lst)
+    for (const auto& item : lst)
     {
         if (item.size())
         {
@@ -90,12 +90,6 @@ Foam::fileName::Type Foam::fileName::type(const bool followLink) const
 }
 
 
-bool Foam::fileName::isAbsolute() const
-{
-    return !empty() && operator[](0) == '/';
-}
-
-
 Foam::fileName& Foam::fileName::toAbsolute()
 {
     fileName& f = *this;
@@ -294,81 +288,26 @@ Foam::fileName Foam::fileName::lessExt() const
 
 Foam::word Foam::fileName::ext() const
 {
-    const size_type i = find_ext();
-
-    if (i == npos)
-    {
-        return word::null;
-    }
-    else
-    {
-        return substr(i+1, npos);
-    }
+    return string::ext();
 }
 
 
 Foam::fileName& Foam::fileName::ext(const word& ending)
 {
-    if (!ending.empty() && !empty() && operator[](size()-1) != '/')
-    {
-        append(".");
-        append(ending);
-    }
-
+    string::ext(ending);
     return *this;
 }
 
 
-bool Foam::fileName::hasExt() const
-{
-    return (find_ext() != npos);
-}
-
-
 bool Foam::fileName::hasExt(const word& ending) const
 {
-    size_type i = find_ext();
-    if (i == npos)
-    {
-        return false;
-    }
-
-    ++i; // Do next comparison *after* the dot
-    return
-    (
-        // Lengths must match
-        ((size() - i) == ending.size())
-     && !compare(i, npos, ending)
-    );
+    return string::hasExt(ending);
 }
 
 
 bool Foam::fileName::hasExt(const wordRe& ending) const
 {
-    const size_type i = find_ext();
-    if (i == npos)
-    {
-        return false;
-    }
-
-    std::string end = substr(i+1, npos);
-    return ending.match(end);
-}
-
-
-bool Foam::fileName::removeExt()
-{
-    const size_type i = find_ext();
-
-    if (i == npos)
-    {
-        return false;
-    }
-    else
-    {
-        this->resize(i);
-        return true;
-    }
+    return string::hasExt(ending);
 }
 
 
@@ -444,7 +383,7 @@ void Foam::fileName::operator=(const char* str)
 }
 
 
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
 
 Foam::fileName Foam::operator/(const string& a, const string& b)
 {
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.H b/src/OpenFOAM/primitives/strings/fileName/fileName.H
index a8f17cf6b04..19cd295120f 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.H
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.H
@@ -74,10 +74,6 @@ class fileName
 {
     // Private Member Functions
 
-        //- Find position of the file extension dot, return npos on failure.
-        //  A wrapped version of find_last_of("./") with additional logic.
-        inline size_type find_ext() const;
-
         //- Strip invalid characters
         inline void stripInvalid();
 
@@ -154,6 +150,7 @@ public:
         //
         // * Removes trailing '/'
         //
+        // \return True if any contents changed
         bool clean();
 
         //- Cleanup file name
@@ -167,8 +164,8 @@ public:
         //  LINK (only if followLink=false)
         Type type(const bool followLink = true) const;
 
-        //- Return true if file name is absolute
-        bool isAbsolute() const;
+        //- Return true if file name is absolute (starts with a '/')
+        inline bool isAbsolute() const;
 
         //- Convert from relative to absolute
         fileName& toAbsolute();
@@ -194,8 +191,8 @@ public:
         word nameLessExt() const;
 
         //- Return basename, optionally without extension
-        // \deprecated in favour of name() or nameLessExt() which more
-        //  explicitly describe their behaviour (MAR-2017).
+        // \deprecated in favour of name() or nameLessExt() which describe
+        //  their behaviour more explicitly (MAR-2017).
         word name(const bool noExt) const
         {
             return noExt ? this->nameLessExt() : this->name();
@@ -227,7 +224,7 @@ public:
         fileName& ext(const word& ending);
 
         //- Return true if it has an extension or simply ends with a '.'
-        bool hasExt() const;
+        inline bool hasExt() const;
 
         //- Return true if the extension is the same as the given ending.
         bool hasExt(const word& ending) const;
@@ -236,7 +233,7 @@ public:
         bool hasExt(const wordRe& ending) const;
 
         //- Remove extension, returning true if string changed.
-        bool removeExt();
+        inline bool removeExt();
 
 
         //- Return path components as wordList
@@ -288,6 +285,8 @@ public:
 };
 
 
+// Global Operators
+
 //- Assemble words and fileNames as pathnames by adding a '/' separator.
 //  No '/' separator is added if either argument is an empty string.
 fileName operator/(const string& a, const string& b);
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
index e2055f74746..b1199263056 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
+++ b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H
@@ -25,21 +25,6 @@ License
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-inline std::string::size_type Foam::fileName::find_ext() const
-{
-    const size_type i = find_last_of("./");
-
-    if (i == npos || i == 0 || operator[](i) == '/')
-    {
-        return npos;
-    }
-    else
-    {
-        return i;
-    }
-}
-
-
 inline void Foam::fileName::stripInvalid()
 {
     // skip stripping unless debug is active to avoid
@@ -130,4 +115,22 @@ inline bool Foam::fileName::valid(char c)
 }
 
 
+inline bool Foam::fileName::isAbsolute() const
+{
+    return !empty() && operator[](0) == '/';
+}
+
+
+inline bool Foam::fileName::hasExt() const
+{
+    return string::hasExt();
+}
+
+
+inline bool Foam::fileName::removeExt()
+{
+    return string::removeExt();
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/string/string.C b/src/OpenFOAM/primitives/strings/string/string.C
index 5f03edeba1c..dff56264118 100644
--- a/src/OpenFOAM/primitives/strings/string/string.C
+++ b/src/OpenFOAM/primitives/strings/string/string.C
@@ -25,6 +25,8 @@ License
 
 #include "string.H"
 #include "stringOps.H"
+#include "word.H"
+#include "wordRe.H"
 
 /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
 
@@ -33,13 +35,75 @@ int Foam::string::debug(Foam::debug::debugSwitch(string::typeName, 0));
 const Foam::string Foam::string::null;
 
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+Foam::word Foam::string::ext() const
+{
+    const size_type i = find_ext();
+
+    if (i == npos)
+    {
+        return word::null;
+    }
+    else
+    {
+        return substr(i+1, npos);
+    }
+}
+
+
+bool Foam::string::ext(const Foam::word& ending)
+{
+    if (!ending.empty() && !empty() && operator[](size()-1) != '/')
+    {
+        append(1u, '.');
+        append(ending);
+
+        return true;
+    }
+
+    return false;
+}
+
+
+bool Foam::string::hasExt(const word& ending) const
+{
+    size_type i = find_ext();
+    if (i == npos)
+    {
+        return false;
+    }
+
+    ++i; // Compare *after* the dot
+    return
+    (
+        // Lengths must match
+        ((size() - i) == ending.size())
+     && !compare(i, npos, ending)
+    );
+}
+
+
+bool Foam::string::hasExt(const wordRe& ending) const
+{
+    const size_type i = find_ext();
+    if (i == npos)
+    {
+        return false;
+    }
+
+    const std::string end = substr(i+1, npos);  // Compare *after* the dot
+    return ending.match(end);
+}
+
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::string::size_type Foam::string::count(const char c) const
 {
     size_type cCount = 0;
 
-    for (const_iterator iter = begin(); iter != end(); ++iter)
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
     {
         if (*iter == c)
         {
diff --git a/src/OpenFOAM/primitives/strings/string/string.H b/src/OpenFOAM/primitives/strings/string/string.H
index 87cb00104b2..e624a684567 100644
--- a/src/OpenFOAM/primitives/strings/string/string.H
+++ b/src/OpenFOAM/primitives/strings/string/string.H
@@ -58,6 +58,8 @@ namespace Foam
 {
 
 // Forward declaration of classes
+class word;
+class wordRe;
 class Istream;
 class Ostream;
 
@@ -76,6 +78,37 @@ class string
 :
     public std::string
 {
+protected:
+
+    // Protected Member Functions
+
+        //- Find position of a file extension dot, return npos on failure.
+        //  A wrapped version of find_last_of("./") with additional logic.
+        inline size_type find_ext() const;
+
+        //- Return file name extension (part after last .)
+        word ext() const;
+
+        //- Append a '.' and the ending.
+        //  The '.' and ending will not be added when the ending is empty,
+        //  or when the object was or ended with a '/'.
+        //
+        //  \return True if append occurred.
+        bool ext(const word& ending);
+
+        //- Return true if it has an extension or simply ends with a '.'
+        inline bool hasExt() const;
+
+        //- Return true if the extension is the same as the given ending.
+        bool hasExt(const word& ending) const;
+
+        //- Return true if the extension matches the given ending.
+        bool hasExt(const wordRe& ending) const;
+
+        //- Remove extension, returning true if string changed.
+        inline bool removeExt();
+
+
 public:
 
     // Static data members
diff --git a/src/OpenFOAM/primitives/strings/string/stringI.H b/src/OpenFOAM/primitives/strings/string/stringI.H
index b23a71b2d53..bae33b3342f 100644
--- a/src/OpenFOAM/primitives/strings/string/stringI.H
+++ b/src/OpenFOAM/primitives/strings/string/stringI.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,6 +25,45 @@ License
 
 #include <iostream>
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+inline std::string::size_type Foam::string::find_ext() const
+{
+    const size_type i = find_last_of("./");
+
+    if (i == npos || i == 0 || operator[](i) == '/')
+    {
+        return npos;
+    }
+    else
+    {
+        return i;
+    }
+}
+
+
+inline bool Foam::string::hasExt() const
+{
+    return (find_ext() != npos);
+}
+
+
+inline bool Foam::string::removeExt()
+{
+    const size_type i = find_ext();
+
+    if (i == npos)
+    {
+        return false;
+    }
+    else
+    {
+        this->resize(i);
+        return true;
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 inline Foam::string::string()
diff --git a/src/OpenFOAM/primitives/strings/word/word.C b/src/OpenFOAM/primitives/strings/word/word.C
index bbd4050a338..2f418d721d2 100644
--- a/src/OpenFOAM/primitives/strings/word/word.C
+++ b/src/OpenFOAM/primitives/strings/word/word.C
@@ -91,4 +91,46 @@ Foam::word Foam::word::validated(const std::string& s)
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::word Foam::word::lessExt() const
+{
+    const size_type i = find_ext();
+
+    if (i == npos)
+    {
+        return *this;
+    }
+    else
+    {
+        return substr(0, i);
+    }
+}
+
+
+Foam::word Foam::word::ext() const
+{
+    return string::ext();
+}
+
+
+Foam::word& Foam::word::ext(const word& ending)
+{
+    string::ext(ending);
+    return *this;
+}
+
+
+bool Foam::word::hasExt(const word& ending) const
+{
+    return string::hasExt(ending);
+}
+
+
+bool Foam::word::hasExt(const wordRe& ending) const
+{
+    return string::hasExt(ending);
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/word/word.H b/src/OpenFOAM/primitives/strings/word/word.H
index 4561292ab90..ebff4c52350 100644
--- a/src/OpenFOAM/primitives/strings/word/word.H
+++ b/src/OpenFOAM/primitives/strings/word/word.H
@@ -117,13 +117,46 @@ public:
         static word validated(const std::string& s);
 
 
+      // File-like functions
+
+        //- Return word without extension (part before last .)
+        word lessExt() const;
+
+        //- Return file name extension (part after last .)
+        word ext() const;
+
+        //- Append a '.' and the ending, and return the object.
+        //  The '.' and ending will not be added when the ending is empty,
+        //  or when the file name is empty or ended with a '/'.
+        word& ext(const word& ending);
+
+        //- Return true if it has an extension or simply ends with a '.'
+        inline bool hasExt() const;
+
+        //- Return true if the extension is the same as the given ending.
+        bool hasExt(const word& ending) const;
+
+        //- Return true if the extension matches the given ending.
+        bool hasExt(const wordRe& ending) const;
+
+        //- Remove extension, returning true if string changed.
+        inline bool removeExt();
+
+
     // Member operators
 
       // Assignment
 
+        //- Copy, no character validation required
         inline void operator=(const word& w);
+
+        //- Copy, stripping invalid characters
         inline void operator=(const string& s);
+
+        //- Copy, stripping invalid characters
         inline void operator=(const std::string& s);
+
+        //- Copy, stripping invalid characters
         inline void operator=(const char* s);
 
 
diff --git a/src/OpenFOAM/primitives/strings/word/wordI.H b/src/OpenFOAM/primitives/strings/word/wordI.H
index 4c6c800b118..eb170970143 100644
--- a/src/OpenFOAM/primitives/strings/word/wordI.H
+++ b/src/OpenFOAM/primitives/strings/word/wordI.H
@@ -127,6 +127,18 @@ inline bool Foam::word::valid(char c)
 }
 
 
+inline bool Foam::word::hasExt() const
+{
+    return string::hasExt();
+}
+
+
+inline bool Foam::word::removeExt()
+{
+    return string::removeExt();
+}
+
+
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 inline void Foam::word::operator=(const word& w)
diff --git a/src/OpenFOAM/primitives/strings/wordRe/wordRe.H b/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
index ede0a7a047e..4df4325efda 100644
--- a/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
+++ b/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
@@ -25,8 +25,8 @@ Class
     Foam::wordRe
 
 Description
-    A wordRe is a word, but can also have a regular expression for matching
-    words.
+    A wordRe is a Foam::word, but can contain a regular expression for
+    matching words or strings.
 
     By default the constructors will generally preserve the argument as a
     string literal and the assignment operators will use the wordRe::DETECT
-- 
GitLab