diff --git a/applications/test/fileNameClean/fileNameCleanTest.C b/applications/test/fileNameClean/fileNameCleanTest.C index 4a6824d5a4..b41cc434ca 100644 --- a/applications/test/fileNameClean/fileNameCleanTest.C +++ b/applications/test/fileNameClean/fileNameCleanTest.C @@ -40,137 +40,19 @@ Description using namespace Foam; -// -// * 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 fileNameCleanThis(fileName& This) -{ - // the top slash - we are never allowed to descend below this one - register string::size_type top = This.find('/'); - - // no slashes - nothing to do - if (top == string::npos) - { - return false; - } - - // start with the '/' found: - register char prev = '/'; - register string::size_type nChar = top+1; - register string::size_type maxLen = This.size(); - - for - ( - register string::size_type src = nChar; - src < maxLen; - /*nil*/ - ) - { - register char c = This[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 - register char c1 = This[src]; - - // found '/./' - skip it - if (c1 == '/') - { - src++; - continue; - } - - // it is '/..' or '/../' - if (c1 == '.' && (src+1 >= maxLen || This[src+1] == '/')) - { - // find a candidate for the parent directory - // minimum of 3 characters: '/x/../' - string::size_type parent = - ( - nChar > 2 - ? This.rfind('/', nChar-2) - : string::npos - ); - - - // strip parent directory, provided that it isn't below - // the current top edit point - if (parent != string::npos && parent >= top) - { - nChar = parent + 1; - src += 2; - continue; - } - - // bad resolution, eg 'abc/../../' - // retain it, but move the top to avoid it being - // considered a valid parent later - top += 3; - } - } - } - This[nChar++] = prev = c; - } - - // remove trailing slash - if (nChar > 1 && This[nChar-1] == '/') - { - nChar--; - } - - This.resize(nChar); - - return (nChar != maxLen); -} - - -fileName fileNameClean(fileName& This) -{ - fileName fName(This); - fileNameCleanThis(fName); - - return fName; -} - - void printCleaning(fileName& pathName) { Info<< "fileName = " << pathName << nl << " path() = " << pathName.path() << nl - << " name() = " << pathName.name() << nl << nl; + << " name() = " << pathName.name() << nl + << " joined = " << pathName.path()/pathName.name() << nl << nl; - fileNameCleanThis(pathName); + pathName.clean(); Info<< "cleaned = " << pathName << nl << " path() = " << pathName.path() << nl - << " name() = " << pathName.name() << nl << nl; + << " name() = " << pathName.name() << nl + << " joined = " << pathName.path()/pathName.name() << nl << nl; IOobject::writeDivider(Info); } @@ -195,7 +77,14 @@ int main(int argc, char *argv[]) if (args.optionFound("case")) { fileName pathName = args.option("case"); - Info<< "-case\n"; + Info<< nl + << "-case" << nl + << "path = " << args.path() << nl + << "root = " << args.rootPath() << nl + << "case = " << args.caseName() << nl + << "FOAM_CASE=" << getEnv("FOAM_CASE") << nl + << "FOAM_CASENAME=" << getEnv("FOAM_CASENAME") << nl + << endl; printCleaning(pathName); } @@ -206,7 +95,6 @@ int main(int argc, char *argv[]) printCleaning(pathName); } - Info<< "\nEnd" << endl; return 0; diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C index ac6dc75025..e157c15e34 100644 --- a/src/OpenFOAM/primitives/strings/fileName/fileName.C +++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C @@ -55,18 +55,115 @@ Foam::fileName::Type Foam::fileName::type() const } +// +// * 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() { - bool changed = false; + // the top slash - we are never allowed to go above it + register string::size_type top = this->find('/'); - changed = this->removeRepeated('/') || changed; - changed = this->removeTrailing('/') || changed; + // no slashes - nothing to do + if (top == string::npos) + { + return false; + } - return changed; + // start with the '/' found: + register char prev = '/'; + register string::size_type nChar = top+1; + register string::size_type maxLen = this->size(); + + for + ( + register string::size_type src = nChar; + src < maxLen; + /*nil*/ + ) + { + register 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 + register 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); } -// Return string with repeated characters removed Foam::fileName Foam::fileName::clean() const { fileName fName(*this);