BUG: UListIO: byteSize overflowing on really big faceLists
[OpenFOAM-2.0.x.git] / src / OpenFOAM / primitives / strings / fileName / fileName.C
blob8bacf62b90d8658f9cac3232ab1e735796cda5e2
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
11     OpenFOAM is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by
13     the Free Software Foundation, either version 3 of the License, or
14     (at your option) any later version.
16     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "fileName.H"
27 #include "wordList.H"
28 #include "DynamicList.H"
29 #include "debug.H"
30 #include "OSspecific.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 const char* const Foam::fileName::typeName = "fileName";
35 int Foam::fileName::debug(debug::debugSwitch(fileName::typeName, 0));
36 const Foam::fileName Foam::fileName::null;
38 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
40 Foam::fileName::fileName(const wordList& lst)
42     forAll(lst, elemI)
43     {
44         operator=((*this)/lst[elemI]);
45     }
49 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
51 Foam::fileName::Type Foam::fileName::type() const
53     return ::Foam::type(*this);
57 bool Foam::fileName::isAbsolute() const
59     return !empty() && operator[](0) == '/';
64 // * remove repeated slashes
65 //       /abc////def        -->   /abc/def
67 // * remove '/./'
68 //       /abc/def/./ghi/.   -->   /abc/def/./ghi
69 //       abc/def/./         -->   abc/def
71 // * remove '/../'
72 //       /abc/def/../ghi/jkl/nmo/..   -->   /abc/ghi/jkl
73 //       abc/../def/ghi/../jkl        -->   abc/../def/jkl
75 // * remove trailing '/'
77 bool Foam::fileName::clean()
79     // the top slash - we are never allowed to go above it
80     register string::size_type top = this->find('/');
82     // no slashes - nothing to do
83     if (top == string::npos)
84     {
85         return false;
86     }
88     // start with the '/' found:
89     register char prev = '/';
90     register string::size_type nChar  = top+1;
91     register string::size_type maxLen = this->size();
93     for
94     (
95         register string::size_type src = nChar;
96         src < maxLen;
97         /*nil*/
98     )
99     {
100         register char c = operator[](src++);
102         if (prev == '/')
103         {
104             // repeated '/' - skip it
105             if (c == '/')
106             {
107                 continue;
108             }
110             // could be '/./' or '/../'
111             if (c == '.')
112             {
113                 // found trailing '/.' - skip it
114                 if (src >= maxLen)
115                 {
116                     continue;
117                 }
120                 // peek at the next character
121                 register char c1 = operator[](src);
123                 // found '/./' - skip it
124                 if (c1 == '/')
125                 {
126                     src++;
127                     continue;
128                 }
130                 // it is '/..' or '/../'
131                 if (c1 == '.' && (src+1 >= maxLen || operator[](src+1) == '/'))
132                 {
133                     string::size_type parent;
135                     // backtrack to find the parent directory
136                     // minimum of 3 characters:  '/x/../'
137                     // strip it, provided it is above the top point
138                     if
139                     (
140                         nChar > 2
141                      && (parent = this->rfind('/', nChar-2)) != string::npos
142                      && parent >= top
143                     )
144                     {
145                         nChar = parent + 1;   // retain '/' from the parent
146                         src += 2;
147                         continue;
148                     }
150                     // bad resolution, eg 'abc/../../'
151                     // retain the sequence, but move the top to avoid it being
152                     // considered a valid parent later
153                     top = nChar + 2;
154                 }
155             }
156         }
157         operator[](nChar++) = prev = c;
158     }
160     // remove trailing slash
161     if (nChar > 1 && operator[](nChar-1) == '/')
162     {
163         nChar--;
164     }
166     this->resize(nChar);
168     return (nChar != maxLen);
172 Foam::fileName Foam::fileName::clean() const
174     fileName fName(*this);
175     fName.clean();
176     return fName;
181 //  Return file name (part beyond last /)
183 //  behaviour compared to /usr/bin/basename:
184 //    input           name()          basename
185 //    -----           ------          --------
186 //    "foo"           "foo"           "foo"
187 //    "/foo"          "foo"           "foo"
188 //    "foo/bar"       "bar"           "bar"
189 //    "/foo/bar"      "bar"           "bar"
190 //    "/foo/bar/"     ""              "bar"
192 Foam::word Foam::fileName::name() const
194     size_type i = rfind('/');
196     if (i == npos)
197     {
198         return *this;
199     }
200     else
201     {
202         return substr(i+1, npos);
203     }
207 Foam::word Foam::fileName::name(const bool noExt) const
209     if (noExt)
210     {
211         size_type beg = rfind('/');
212         if (beg == npos)
213         {
214             beg = 0;
215         }
216         else
217         {
218             ++beg;
219         }
221         size_type dot = rfind('.');
222         if (dot != npos && dot <= beg)
223         {
224             dot = npos;
225         }
227         if (dot == npos)
228         {
229             return substr(beg, npos);
230         }
231         else
232         {
233             return substr(beg, dot - beg);
234         }
235     }
236     else
237     {
238         return this->name();
239     }
243 //  Return directory path name (part before last /)
245 //  behaviour compared to /usr/bin/dirname:
246 //    input           path()          dirname
247 //    -----           ------          -------
248 //    "foo"           "."             "."
249 //    "/foo"          "/"             "foo"
250 //    "foo/bar"       "foo"           "foo"
251 //    "/foo/bar"      "/foo"          "/foo"
252 //    "/foo/bar/"     "/foo/bar/"     "/foo"
254 Foam::fileName Foam::fileName::path() const
256     size_type i = rfind('/');
258     if (i == npos)
259     {
260         return ".";
261     }
262     else if (i)
263     {
264         return substr(0, i);
265     }
266     else
267     {
268         return "/";
269     }
273 //  Return file name without extension (part before last .)
274 Foam::fileName Foam::fileName::lessExt() const
276     size_type i = find_last_of("./");
278     if (i == npos || i == 0 || operator[](i) == '/')
279     {
280         return *this;
281     }
282     else
283     {
284         return substr(0, i);
285     }
289 //  Return file name extension (part after last .)
290 Foam::word Foam::fileName::ext() const
292     size_type i = find_last_of("./");
294     if (i == npos || i == 0 || operator[](i) == '/')
295     {
296         return word::null;
297     }
298     else
299     {
300         return substr(i+1, npos);
301     }
305 // Return the components of the file name as a wordList
306 // note that concatenating the components will not necessarily retrieve
307 // the original input fileName
309 //  behaviour
310 //    input           components()
311 //    -----           ------
312 //    "foo"           1("foo")
313 //    "/foo"          1("foo")
314 //    "foo/bar"       2("foo", "bar")
315 //    "/foo/bar"      2("foo", "bar")
316 //    "/foo/bar/"     2("foo", "bar")
318 Foam::wordList Foam::fileName::components(const char delimiter) const
320     DynamicList<word> wrdList(20);
322     size_type beg=0, end=0;
324     while ((end = find(delimiter, beg)) != npos)
325     {
326         // avoid empty element (caused by doubled slashes)
327         if (beg < end)
328         {
329             wrdList.append(substr(beg, end-beg));
330         }
331         beg = end + 1;
332     }
334     // avoid empty trailing element
335     if (beg < size())
336     {
337         wrdList.append(substr(beg, npos));
338     }
340     // transfer to wordList
341     return wordList(wrdList.xfer());
345 // Return a component of the file name
346 Foam::word Foam::fileName::component
348     const size_type cmpt,
349     const char delimiter
350 ) const
352     return components(delimiter)[cmpt];
356 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
358 const Foam::fileName& Foam::fileName::operator=(const fileName& str)
360     string::operator=(str);
361     return *this;
365 const Foam::fileName& Foam::fileName::operator=(const word& str)
367     string::operator=(str);
368     return *this;
372 const Foam::fileName& Foam::fileName::operator=(const string& str)
374     string::operator=(str);
375     stripInvalid();
376     return *this;
380 const Foam::fileName& Foam::fileName::operator=(const std::string& str)
382     string::operator=(str);
383     stripInvalid();
384     return *this;
388 const Foam::fileName& Foam::fileName::operator=(const char* str)
390     string::operator=(str);
391     stripInvalid();
392     return *this;
396 // * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
398 Foam::fileName Foam::operator/(const string& a, const string& b)
400     if (a.size())           // First string non-null
401     {
402         if (b.size())       // Second string non-null
403         {
404             return fileName(a + '/' + b);
405         }
406         else                // Second string null
407         {
408             return a;
409         }
410     }
411     else                    // First string null
412     {
413         if (b.size())       // Second string non-null
414         {
415             return b;
416         }
417         else                // Second string null
418         {
419             return fileName();
420         }
421     }
425 // ************************************************************************* //