Files
OpenFOAM-6/src/OpenFOAM/primitives/strings/fileName/fileName.C

459 lines
10 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fileName.H"
#include "wordList.H"
#include "DynamicList.H"
#include "debug.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const char* const Foam::fileName::typeName = "fileName";
int Foam::fileName::debug(debug::debugSwitch(fileName::typeName, 0));
const Foam::fileName Foam::fileName::null;
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileName::fileName(const wordList& lst)
{
forAll(lst, elemI)
{
operator=((*this)/lst[elemI]);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::fileName::Type Foam::fileName::type() const
{
return ::Foam::type(*this);
}
bool Foam::fileName::isAbsolute() const
{
return !empty() && operator[](0) == '/';
}
Foam::fileName& Foam::fileName::toAbsolute()
{
fileName& f = *this;
if (!f.isAbsolute())
{
f = cwd()/f;
f.clean();
}
return f;
}
//
// * remove repeated slashes
// /abc////def --> /abc/def
//
// * remove '/./'
// /abc/def/./ghi/. --> /abc/def/./ghi
// abc/def/./ --> abc/def
//
// * remove '/../'
// /abc/def/../ghi/jkl/nmo/.. --> /abc/ghi/jkl
// abc/../def/ghi/../jkl --> abc/../def/jkl
//
// * remove trailing '/'
//
bool Foam::fileName::clean()
{
// the top slash - we are never allowed to go above it
string::size_type top = this->find('/');
// no slashes - nothing to do
if (top == string::npos)
{
return false;
}
// start with the '/' found:
char prev = '/';
string::size_type nChar = top+1;
string::size_type maxLen = this->size();
for
(
string::size_type src = nChar;
src < maxLen;
/*nil*/
)
{
char c = operator[](src++);
if (prev == '/')
{
// repeated '/' - skip it
if (c == '/')
{
continue;
}
// could be '/./' or '/../'
if (c == '.')
{
// found trailing '/.' - skip it
if (src >= maxLen)
{
continue;
}
// peek at the next character
char c1 = operator[](src);
// found '/./' - skip it
if (c1 == '/')
{
src++;
continue;
}
// it is '/..' or '/../'
if (c1 == '.' && (src+1 >= maxLen || operator[](src+1) == '/'))
{
string::size_type parent;
// backtrack to find the parent directory
// minimum of 3 characters: '/x/../'
// strip it, provided it is above the top point
if
(
nChar > 2
&& (parent = this->rfind('/', nChar-2)) != string::npos
&& parent >= top
)
{
nChar = parent + 1; // retain '/' from the parent
src += 2;
continue;
}
// bad resolution, eg 'abc/../../'
// retain the sequence, but move the top to avoid it being
// considered a valid parent later
top = nChar + 2;
}
}
}
operator[](nChar++) = prev = c;
}
// remove trailing slash
if (nChar > 1 && operator[](nChar-1) == '/')
{
nChar--;
}
this->resize(nChar);
return (nChar != maxLen);
}
Foam::fileName Foam::fileName::clean() const
{
fileName fName(*this);
fName.clean();
return fName;
}
// Return file name (part beyond last /)
//
// behaviour compared to /usr/bin/basename:
// input name() basename
// ----- ------ --------
// "foo" "foo" "foo"
// "/foo" "foo" "foo"
// "foo/bar" "bar" "bar"
// "/foo/bar" "bar" "bar"
// "/foo/bar/" "" "bar"
//
Foam::word Foam::fileName::name() const
{
size_type i = rfind('/');
if (i == npos)
{
return *this;
}
else
{
return substr(i+1, npos);
}
}
Foam::string Foam::fileName::caseName() const
{
string cName = *this;
const string caseStr(getEnv("FOAM_CASE"));
const size_type i = find(caseStr);
if (i == npos)
{
return cName;
}
else
{
return cName.replace(i, caseStr.size(), string("$FOAM_CASE"));
}
}
Foam::word Foam::fileName::name(const bool noExt) const
{
if (noExt)
{
size_type beg = rfind('/');
if (beg == npos)
{
beg = 0;
}
else
{
++beg;
}
size_type dot = rfind('.');
if (dot != npos && dot <= beg)
{
dot = npos;
}
if (dot == npos)
{
return substr(beg, npos);
}
else
{
return substr(beg, dot - beg);
}
}
else
{
return this->name();
}
}
// Return directory path name (part before last /)
//
// behaviour compared to /usr/bin/dirname:
// input path() dirname
// ----- ------ -------
// "foo" "." "."
// "/foo" "/" "foo"
// "foo/bar" "foo" "foo"
// "/foo/bar" "/foo" "/foo"
// "/foo/bar/" "/foo/bar/" "/foo"
//
Foam::fileName Foam::fileName::path() const
{
size_type i = rfind('/');
if (i == npos)
{
return ".";
}
else if (i)
{
return substr(0, i);
}
else
{
return "/";
}
}
// Return file name without extension (part before last .)
Foam::fileName Foam::fileName::lessExt() const
{
size_type i = find_last_of("./");
if (i == npos || i == 0 || operator[](i) == '/')
{
return *this;
}
else
{
return substr(0, i);
}
}
// Return file name extension (part after last .)
Foam::word Foam::fileName::ext() const
{
size_type i = find_last_of("./");
if (i == npos || i == 0 || operator[](i) == '/')
{
return word::null;
}
else
{
return substr(i+1, npos);
}
}
// Return the components of the file name as a wordList
// note that concatenating the components will not necessarily retrieve
// the original input fileName
//
// behaviour
// input components()
// ----- ------
// "foo" 1("foo")
// "/foo" 1("foo")
// "foo/bar" 2("foo", "bar")
// "/foo/bar" 2("foo", "bar")
// "/foo/bar/" 2("foo", "bar")
//
Foam::wordList Foam::fileName::components(const char delimiter) const
{
DynamicList<word> wrdList(20);
size_type beg=0, end=0;
while ((end = find(delimiter, beg)) != npos)
{
// avoid empty element (caused by doubled slashes)
if (beg < end)
{
wrdList.append(substr(beg, end-beg));
}
beg = end + 1;
}
// avoid empty trailing element
if (beg < size())
{
wrdList.append(substr(beg, npos));
}
// transfer to wordList
return wordList(wrdList.xfer());
}
// Return a component of the file name
Foam::word Foam::fileName::component
(
const size_type cmpt,
const char delimiter
) const
{
return components(delimiter)[cmpt];
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
const Foam::fileName& Foam::fileName::operator=(const fileName& str)
{
string::operator=(str);
return *this;
}
const Foam::fileName& Foam::fileName::operator=(const word& str)
{
string::operator=(str);
return *this;
}
const Foam::fileName& Foam::fileName::operator=(const string& str)
{
string::operator=(str);
stripInvalid();
return *this;
}
const Foam::fileName& Foam::fileName::operator=(const std::string& str)
{
string::operator=(str);
stripInvalid();
return *this;
}
const Foam::fileName& Foam::fileName::operator=(const char* str)
{
string::operator=(str);
stripInvalid();
return *this;
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
Foam::fileName Foam::operator/(const string& a, const string& b)
{
if (a.size()) // First string non-null
{
if (b.size()) // Second string non-null
{
return fileName(a + '/' + b);
}
else // Second string null
{
return a;
}
}
else // First string null
{
if (b.size()) // Second string non-null
{
return b;
}
else // Second string null
{
return fileName();
}
}
}
// ************************************************************************* //