FreeFOAM The Cross-Platform CFD Toolkit
fileName.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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.
20 
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/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "fileName.H"
27 #include <OpenFOAM/wordList.H>
28 #include <OpenFOAM/DynamicList.H>
29 #include <OpenFOAM/debug.H>
30 #include <OpenFOAM/OSspecific.H>
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 const char* const Foam::fileName::typeName = "fileName";
35 int Foam::fileName::debug(debug::debugSwitch(fileName::typeName, 0));
37 
38 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
39 
41 {
42  forAll(lst, elemI)
43  {
44  operator=((*this)/lst[elemI]);
45  }
46 }
47 
48 
49 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
50 
52 {
53  return ::Foam::type(*this);
54 }
55 
56 
57 //
58 // * remove repeated slashes
59 // /abc////def --> /abc/def
60 //
61 // * remove '/./'
62 // /abc/def/./ghi/. --> /abc/def/./ghi
63 // abc/def/./ --> abc/def
64 //
65 // * remove '/../'
66 // /abc/def/../ghi/jkl/nmo/.. --> /abc/ghi/jkl
67 // abc/../def/ghi/../jkl --> abc/../def/jkl
68 //
69 // * remove trailing '/'
70 //
72 {
73  // the top slash - we are never allowed to go above it
74  register string::size_type top = this->find('/');
75 
76  // no slashes - nothing to do
77  if (top == string::npos)
78  {
79  return false;
80  }
81 
82  // start with the '/' found:
83  register char prev = '/';
84  register string::size_type nChar = top+1;
85  register string::size_type maxLen = this->size();
86 
87  for
88  (
89  register string::size_type src = nChar;
90  src < maxLen;
91  /*nil*/
92  )
93  {
94  register char c = operator[](src++);
95 
96  if (prev == '/')
97  {
98  // repeated '/' - skip it
99  if (c == '/')
100  {
101  continue;
102  }
103 
104  // could be '/./' or '/../'
105  if (c == '.')
106  {
107  // found trailing '/.' - skip it
108  if (src >= maxLen)
109  {
110  continue;
111  }
112 
113 
114  // peek at the next character
115  register char c1 = operator[](src);
116 
117  // found '/./' - skip it
118  if (c1 == '/')
119  {
120  src++;
121  continue;
122  }
123 
124  // it is '/..' or '/../'
125  if (c1 == '.' && (src+1 >= maxLen || operator[](src+1) == '/'))
126  {
127  string::size_type parent;
128 
129  // backtrack to find the parent directory
130  // minimum of 3 characters: '/x/../'
131  // strip it, provided it is above the top point
132  if
133  (
134  nChar > 2
135  && (parent = this->rfind('/', nChar-2)) != string::npos
136  && parent >= top
137  )
138  {
139  nChar = parent + 1; // retain '/' from the parent
140  src += 2;
141  continue;
142  }
143 
144  // bad resolution, eg 'abc/../../'
145  // retain the sequence, but move the top to avoid it being
146  // considered a valid parent later
147  top = nChar + 2;
148  }
149  }
150  }
151  operator[](nChar++) = prev = c;
152  }
153 
154  // remove trailing slash
155  if (nChar > 1 && operator[](nChar-1) == '/')
156  {
157  nChar--;
158  }
159 
160  this->resize(nChar);
161 
162  return (nChar != maxLen);
163 }
164 
165 
167 {
168  fileName fName(*this);
169  fName.clean();
170  return fName;
171 }
172 
173 
174 
175 // Return file name (part beyond last /)
176 //
177 // behaviour compared to /usr/bin/basename:
178 // input name() basename
179 // ----- ------ --------
180 // "foo" "foo" "foo"
181 // "/foo" "foo" "foo"
182 // "foo/bar" "bar" "bar"
183 // "/foo/bar" "bar" "bar"
184 // "/foo/bar/" "" "bar"
185 //
187 {
188  size_type i = rfind('/');
189 
190  if (i == npos)
191  {
192  return *this;
193  }
194  else
195  {
196  return substr(i+1, npos);
197  }
198 }
199 
200 
201 // Return directory path name (part before last /)
202 //
203 // behaviour compared to /usr/bin/dirname:
204 // input path() dirname
205 // ----- ------ -------
206 // "foo" "." "."
207 // "/foo" "/" "foo"
208 // "foo/bar" "foo" "foo"
209 // "/foo/bar" "/foo" "/foo"
210 // "/foo/bar/" "/foo/bar/" "/foo"
211 //
213 {
214  size_type i = rfind('/');
215 
216  if (i == npos)
217  {
218  return ".";
219  }
220  else if (i)
221  {
222  return substr(0, i);
223  }
224  else
225  {
226  return "/";
227  }
228 }
229 
230 
231 // Return file name without extension (part before last .)
233 {
234  size_type i = find_last_of("./");
235 
236  if (i == npos || i == 0 || operator[](i) == '/')
237  {
238  return *this;
239  }
240  else
241  {
242  return substr(0, i);
243  }
244 }
245 
246 
247 // Return file name extension (part after last .)
249 {
250  size_type i = find_last_of("./");
251 
252  if (i == npos || i == 0 || operator[](i) == '/')
253  {
254  return word::null;
255  }
256  else
257  {
258  return substr(i+1, npos);
259  }
260 }
261 
262 
263 // Return the components of the file name as a wordList
264 // note that concatenating the components will not necessarily retrieve
265 // the original input fileName
266 //
267 // behaviour
268 // input components()
269 // ----- ------
270 // "foo" 1("foo")
271 // "/foo" 1("foo")
272 // "foo/bar" 2("foo", "bar")
273 // "/foo/bar" 2("foo", "bar")
274 // "/foo/bar/" 2("foo", "bar")
275 //
276 Foam::wordList Foam::fileName::components(const char delimiter) const
277 {
278  DynamicList<word> wrdList(20);
279 
280  size_type start=0, end=0;
281 
282  while ((end = find(delimiter, start)) != npos)
283  {
284  // avoid empty element (caused by doubled slashes)
285  if (start < end)
286  {
287  wrdList.append(substr(start, end-start));
288  }
289  start = end + 1;
290  }
291 
292  // avoid empty trailing element
293  if (start < size())
294  {
295  wrdList.append(substr(start, npos));
296  }
297 
298  // transfer to wordList
299  return wordList(wrdList.xfer());
300 }
301 
302 
303 // Return a component of the file name
305 (
306  const size_type cmpt,
307  const char delimiter
308 ) const
309 {
310  return components(delimiter)[cmpt];
311 }
312 
313 
314 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
315 
317 {
318  string::operator=(str);
319  return *this;
320 }
321 
322 
324 {
325  string::operator=(str);
326  return *this;
327 }
328 
329 
330 const Foam::fileName& Foam::fileName::operator=(const string& str)
331 {
332  string::operator=(str);
333  stripInvalid();
334  return *this;
335 }
336 
337 
338 const Foam::fileName& Foam::fileName::operator=(const std::string& str)
339 {
340  string::operator=(str);
341  stripInvalid();
342  return *this;
343 }
344 
345 
347 {
348  string::operator=(str);
349  stripInvalid();
350  return *this;
351 }
352 
353 
354 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
355 
356 Foam::fileName Foam::operator/(const string& a, const string& b)
357 {
358  if (a.size()) // First string non-null
359  {
360  if (b.size()) // Second string non-null
361  {
362  return fileName(a + '/' + b);
363  }
364  else // Second string null
365  {
366  return a;
367  }
368  }
369  else // First string null
370  {
371  if (b.size()) // Second string non-null
372  {
373  return b;
374  }
375  else // Second string null
376  {
377  return fileName();
378  }
379  }
380 }
381 
382 
383 // ************************ vim: set sw=4 sts=4 et: ************************ //