From 46a2a73611c28708c10fc0552e68287fbcfdf087 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Wed, 2 Aug 2017 13:44:37 +0200 Subject: [PATCH] ENH: static versions of fileName clean(), path(), name() - useful operations for other string representations of fileName types. The return type is in general a std::string with any narrowing being done by the caller on the return value. --- .../primitives/strings/fileName/fileName.C | 112 +++++++++++------- .../primitives/strings/fileName/fileName.H | 63 +++++++--- .../primitives/strings/fileName/fileNameI.H | 8 +- 3 files changed, 123 insertions(+), 60 deletions(-) diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C index fe1b70da74..097da220f6 100644 --- a/src/OpenFOAM/primitives/strings/fileName/fileName.C +++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C @@ -104,25 +104,26 @@ Foam::fileName& Foam::fileName::toAbsolute() } -bool Foam::fileName::clean() +bool Foam::fileName::clean(std::string& str) { - // The top slash - we are never allowed to go above it - string::size_type top = this->find('/'); + // Start with the top slash found - we are never allowed to go above it + char prev = '/'; + auto top = str.find(prev); // No slashes - nothing to do - if (top == string::npos) + if (top == std::string::npos) { return false; } - // Start with the '/' found: - char prev = '/'; - string::size_type nChar = top+1; - string::size_type maxLen = this->size(); + // Number of output characters + std::string::size_type nChar = top+1; + + const string::size_type maxLen = str.size(); for (string::size_type src = nChar; src < maxLen; /*nil*/) { - const char c = operator[](src++); + const char c = str[src++]; if (prev == '/') { @@ -132,28 +133,27 @@ bool Foam::fileName::clean() continue; } - // Could be '/./' or '/../' + // Could be "/./", "/../" or a trailing "/." if (c == '.') { - // Found trailing '/.' - skip it + // Trailing "/." - skip it if (src >= maxLen) { - continue; + break; } - // Peek at the next character - const char c1 = operator[](src); + const char c1 = str[src]; - // Found '/./' - skip it + // Found "/./" - skip it if (c1 == '/') { ++src; continue; } - // It is '/..' or '/../' - if (c1 == '.' && (src+1 >= maxLen || operator[](src+1) == '/')) + // Trailing "/.." or intermediate "/../" + if (c1 == '.' && (src+1 >= maxLen || str[src+1] == '/')) { string::size_type parent; @@ -163,7 +163,7 @@ bool Foam::fileName::clean() if ( nChar > 2 - && (parent = this->rfind('/', nChar-2)) != string::npos + && (parent = str.rfind('/', nChar-2)) != string::npos && parent >= top ) { @@ -179,47 +179,60 @@ bool Foam::fileName::clean() } } } - operator[](nChar++) = prev = c; + str[nChar++] = prev = c; } // Remove trailing slash - if (nChar > 1 && operator[](nChar-1) == '/') + if (nChar > 1 && str[nChar-1] == '/') { nChar--; } - this->resize(nChar); + str.resize(nChar); return (nChar != maxLen); } +bool Foam::fileName::clean() +{ + return fileName::clean(*this); +} + + Foam::fileName Foam::fileName::clean() const { - fileName fName(*this); - fName.clean(); - return fName; + fileName cleaned(*this); + fileName::clean(cleaned); + return cleaned; +} + + +std::string Foam::fileName::name(const std::string& str) +{ + const auto beg = str.rfind('/'); + + if (beg == npos) + { + return str; + } + else + { + return str.substr(beg+1); + } } Foam::word Foam::fileName::name() const { - const size_type i = rfind('/'); - - if (i == npos) - { - return *this; - } - else - { - return substr(i+1); - } + return fileName::name(*this); } -Foam::word Foam::fileName::nameLessExt() const +std::string Foam::fileName::nameLessExt(const std::string& str) { - size_type beg = rfind('/'); + size_type beg = str.rfind('/'); + size_type dot = str.rfind('.'); if (beg == npos) { @@ -230,7 +243,6 @@ Foam::word Foam::fileName::nameLessExt() const ++beg; } - size_type dot = rfind('.'); if (dot != npos && dot <= beg) { dot = npos; @@ -238,18 +250,24 @@ Foam::word Foam::fileName::nameLessExt() const if (dot == npos) { - return substr(beg, npos); + return str.substr(beg); } else { - return substr(beg, dot - beg); + return str.substr(beg, dot - beg); } } -Foam::fileName Foam::fileName::path() const +Foam::word Foam::fileName::nameLessExt() const { - const size_type i = rfind('/'); + return nameLessExt(*this); +} + + +std::string Foam::fileName::path(const std::string& str) +{ + const auto i = str.rfind('/'); if (i == npos) { @@ -257,7 +275,7 @@ Foam::fileName Foam::fileName::path() const } else if (i) { - return substr(0, i); + return str.substr(0, i); } else { @@ -266,9 +284,15 @@ Foam::fileName Foam::fileName::path() const } +Foam::fileName Foam::fileName::path() const +{ + return path(*this); +} + + Foam::fileName Foam::fileName::lessExt() const { - const size_type i = find_ext(); + const auto i = find_ext(); if (i == npos) { @@ -325,7 +349,7 @@ Foam::wordList Foam::fileName::components(const char delimiter) const // Avoid empty trailing element if (beg < size()) { - wrdList.append(substr(beg, npos)); + wrdList.append(substr(beg)); } // Transfer to wordList diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.H b/src/OpenFOAM/primitives/strings/fileName/fileName.H index d134996178..841c0e35b2 100644 --- a/src/OpenFOAM/primitives/strings/fileName/fileName.H +++ b/src/OpenFOAM/primitives/strings/fileName/fileName.H @@ -135,26 +135,42 @@ public: //- Is this character valid for a fileName? inline static bool valid(char c); - //- Cleanup file name + //- Cleanup filename // - // * Removes repeated slashes + // Removes trailing \c / + // \verbatim + // / --> / + // /abc/ --> /abc + // \endverbatim + // + // Removes repeated slashes + // \verbatim // /abc////def --> /abc/def + // \endverbatim // - // * Removes '/./' - // /abc/def/./ghi/. --> /abc/def/./ghi + // Removes \c /./ (current directory) + // \verbatim + // /abc/def/./ghi/. --> /abc/def/ghi // abc/def/./ --> abc/def + // ./abc/ --> ./abc + // \endverbatim // - // * Removes '/../' + // Removes \c /../ (parent directory) + // \verbatim // /abc/def/../ghi/jkl/nmo/.. --> /abc/ghi/jkl // abc/../def/ghi/../jkl --> abc/../def/jkl + // \endverbatim // - // * Removes trailing '/' - // - // \return True if any contents changed + // \return True if the content changed + static bool clean(std::string& str); + + + //- Cleanup filename inplace + // \return True if any contents changed bool clean(); - //- Cleanup file name - // eg, remove repeated slashes, etc. + //- Cleanup filename + // \return cleaned copy of fileName fileName clean() const; @@ -164,6 +180,9 @@ public: // LINK (only if followLink=false) Type type(const bool followLink = true) const; + //- Return true if string starts with a '/' + inline static bool isAbsolute(const std::string& str); + //- Return true if file name is absolute (starts with a '/') inline bool isAbsolute() const; @@ -174,19 +193,28 @@ public: // Decomposition //- Return basename (part beyond last /), including its extension + // The result normally coresponds to a Foam::word // // Behaviour compared to /usr/bin/basename: // \verbatim // input name() basename // ----- ------ -------- // "foo" "foo" "foo" + // "/" "" "/" // "/foo" "foo" "foo" // "foo/bar" "bar" "bar" // "/foo/bar" "bar" "bar" // "/foo/bar/" "" "bar" // \endverbatim + static std::string name(const std::string& str); + + //- Return basename (part beyond last /), including its extension word name() const; + //- Return basename, without extension + // The result normally coresponds to a Foam::word + static std::string nameLessExt(const std::string& str); + //- Return basename, without extension word nameLessExt() const; @@ -199,17 +227,22 @@ public: } //- Return directory path name (part before last /) + // The result normally coresponds to a Foam::fileName // // Behaviour compared to /usr/bin/dirname: // \verbatim // input path() dirname // ----- ------ ------- // "foo" "." "." + // "/" "/" "/" // "/foo" "/" "foo" // "foo/bar" "foo" "foo" // "/foo/bar" "/foo" "/foo" // "/foo/bar/" "/foo/bar/" "/foo" // \endverbatim + static std::string path(const std::string& str); + + //- Return directory path name (part before last /) fileName path() const; //- Return file name without extension (part before last .) @@ -242,11 +275,11 @@ public: // \verbatim // Input components() // ----- ------ - // "foo" 1("foo") - // "/foo" 1("foo") - // "foo/bar" 2("foo", "bar") - // "/foo/bar" 2("foo", "bar") - // "/foo/bar/" 2("foo", "bar") + // "foo" ("foo") + // "/foo" ("foo") + // "foo/bar" ("foo", "bar") + // "/foo/bar" ("foo", "bar") + // "/foo/bar/" ("foo", "bar") // \endverbatim wordList components(const char delimiter = '/') const; diff --git a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H index e65d599e09..c3c82cc65d 100644 --- a/src/OpenFOAM/primitives/strings/fileName/fileNameI.H +++ b/src/OpenFOAM/primitives/strings/fileName/fileNameI.H @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -116,6 +116,12 @@ inline bool Foam::fileName::valid(char c) } +inline bool Foam::fileName::isAbsolute(const std::string& str) +{ + return !str.empty() && str[0] == '/'; +} + + inline bool Foam::fileName::isAbsolute() const { return !empty() && operator[](0) == '/';