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 | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2017 OpenFOAM Foundation
9 Copyright (C) 2016-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "fileName.H"
30#include "wordRe.H"
31#include "wordList.H"
32#include "DynamicList.H"
33#include "OSspecific.H"
34#include "fileOperation.H"
35#include "stringOps.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39const char* const Foam::fileName::typeName = "fileName";
40
41int Foam::fileName::debug(Foam::debug::debugSwitch(fileName::typeName, 0));
42
44(
45 #ifdef _WIN32
46 1 // Windows: expect spaces to occur
47 #else
48 Foam::debug::infoSwitch("allowSpaceInFileName", 0)
49 #endif
50);
51
53
54
55// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
56
57namespace
58{
59
60// doClean:
61// - remove duplicate slashes, "/./" and "/../" components.
62//
63// checkValid:
64// - similar to stripInvalid (but silent)
65//
66// return True if the content changed
67static bool cleanFileName
68(
69 std::string& str,
70 const bool doClean,
71 const bool checkValid
72)
73{
74 const auto maxLen = str.length();
75 std::string::size_type nChar = 0;
76
77 // Preserve UNC \\server\path (windows)
78 // - MS-windows only, but handle for other systems
79 // since there is no collision with this pattern
80 if (maxLen > 2 && str[0] == '\\' && str[1] == '\\')
81 {
82 nChar += 2;
83 }
84
85 char prev = 0;
86 auto top = std::string::npos; // Not yet found
87 bool changed = false;
88
89 for (auto src = nChar; src < maxLen; /*nil*/)
90 {
91 char c = str[src++];
92
93 // Treat raw backslash like a path separator.
94 // There is no "normal" way for these to be there
95 // (except for an OS that uses them), but can cause issues
96 // when writing strings, shell commands etc.
97 if (c == '\\')
98 {
99 c = '/';
100 str[nChar] = c;
101 changed = true;
102 }
103 else if (checkValid && !Foam::fileName::valid(c))
104 {
105 // Ignore invalid chars
106 // Could explicitly allow space character or rely on
107 // allowSpaceInFileName via fileName::valid()
108 continue;
109 }
110
111 if (c == '/' && top == std::string::npos)
112 {
113 // Top-level slash not previously determined
114 top = (src-1);
115 }
116
117 if (doClean && prev == '/')
118 {
119 // Repeated '/' - skip it
120 if (c == '/')
121 {
122 continue;
123 }
124
125 // Could be "/./", "/../" or a trailing "/."
126 if (c == '.')
127 {
128 // Trailing "/." - skip it
129 if (src >= maxLen)
130 {
131 break;
132 }
133
134 // Peek at the next character
135 const char c1 = str[src];
136
137 // Found "/./" - skip over it
138 if (c1 == '/' || c1 == '\\')
139 {
140 ++src;
141 continue;
142 }
143
144 // Trailing "/.." or intermediate "/../"
145 if
146 (
147 c1 == '.'
148 &&
149 (
150 src+1 >= maxLen
151 || str[src+1] == '/' || str[src+1] == '\\'
152 )
153 )
154 {
155 // Backtrack to find the parent directory
156 // Minimum of 3 characters: '/x/../'
157 // Strip it, provided it is above the top point
158
159 std::string::size_type parent;
160 if
161 (
162 nChar > 2
163 && top != std::string::npos
164 && (parent = str.rfind('/', nChar-2)) != std::string::npos
165 && parent >= top
166 )
167 {
168 nChar = parent + 1; // Retain '/' from the parent
169 src += 2;
170 continue;
171 }
172
173 // Bad resolution, eg 'abc/../../'
174 // Retain the sequence, but move the top to avoid it being
175 // considered a valid parent later
176 top = nChar + 2;
177 }
178 }
179 }
180
181 str[nChar++] = prev = c;
182 }
183
184 // Remove trailing '/'
185 if (doClean && nChar > 1 && str[nChar-1] == '/')
186 {
187 --nChar;
188 }
189
190 str.erase(nChar);
191 return changed || (nChar != maxLen);
192}
193
194} // End namespace Foam
195
196
197// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
198
199bool Foam::fileName::clean(std::string& str)
200{
201 return cleanFileName(str, true, false); // clean, checkValid = false
202}
203
204
206(
207 const std::string& str,
208 const bool doClean
209)
210{
211 fileName out(str, false); // copy, no stripping
212 cleanFileName(out, doClean, true); // checkValid = true
213 return out;
214}
215
216
218(
219 const std::string& s1,
220 const std::string& s2,
221 const char delim
222)
223{
224 const auto n1 = s1.length();
225 const auto n2 = s2.length();
226
227 fileName out;
228 out.reserve(n1 + n2 + 1);
229
230 out += s1;
231
232 if (n1 && n2 && s1.back() != delim && s2.front() != delim)
233 {
234 // Add delimiter
235 out += delim;
236 }
237
238 out += s2;
239
240 // Could also remove trailing '/', if desired.
241 return out;
242}
243
244
245bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
246{
247 // Do not use (s1 == s2) or s1.compare(s2) first since this would
248 // potentially be doing the comparison twice.
249
250 std::string::size_type i1 = 0;
251 std::string::size_type i2 = 0;
252
253 const auto n1 = s1.length();
254 const auto n2 = s2.length();
255
256 //Info<< "compare " << s1 << " == " << s2 << endl;
257 while (i1 < n1 && i2 < n2)
258 {
259 //Info<< "check '" << s1[i1] << "' vs '" << s2[i2] << "'" << endl;
260
261 if (s1[i1] != s2[i2])
262 {
263 return false;
264 }
265
266 // Increment to next positions and also skip repeated slashes
267 do
268 {
269 ++i1;
270 }
271 while (s1[i1] == '/');
272
273 do
274 {
275 ++i2;
276 }
277 while (s2[i2] == '/');
278 }
279 //Info<< "return: " << Switch(i1 == n1 && i2 == n2) << endl;
280
281 // Equal if it made it all the way through both strings
282 return (i1 == n1 && i2 == n2);
283}
284
285
286bool Foam::fileName::isBackup(const std::string& s)
287{
288 if (s.empty())
289 {
290 return false;
291 }
292 else if (s.back() == '~')
293 {
294 return true;
295 }
296
297 // Now check the extension
298 auto dot = find_ext(s);
299
300 if (dot == npos)
301 {
302 return false;
303 }
304
305 ++dot;
306
307 return
308 (
309 !s.compare(dot, npos, "bak") || !s.compare(dot, npos, "BAK")
310 || !s.compare(dot, npos, "old") || !s.compare(dot, npos, "save")
311 );
312}
313
314
315// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
316
318{
319 size_type len = 0;
320 for (const word& item : list)
321 {
322 len += 1 + item.length(); // Include space for '/' needed
323 }
324 reserve(len);
325
326 for (const word& item : list)
327 {
328 if (item.length())
329 {
330 if (length()) operator+=('/');
331 operator+=(item);
332 }
333 }
334}
335
336
337Foam::fileName::fileName(std::initializer_list<word> list)
338{
339 size_type len = 0;
340 for (const word& item : list)
341 {
342 len += 1 + item.length(); // Include space for '/' needed
343 }
344 reserve(len);
345
346 for (const word& item : list)
347 {
348 if (item.length())
349 {
350 if (length()) operator+=('/');
351 operator+=(item);
352 }
353 }
354}
355
356
357// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
358
360(
361 bool followLink,
362 bool checkGzip
363) const
364{
365 Type t = ::Foam::type(*this, followLink);
366
367 if (checkGzip && (Type::UNDEFINED == t) && size())
368 {
369 // Also check for gzip file?
370 t = ::Foam::type(*this + ".gz", followLink);
371 }
372
373 return t;
374}
375
376
378{
379 if (!isAbsolute(*this))
380 {
381 fileName& f = *this;
382 f = cwd()/f;
383 f.clean(); // Remove unneeded ".."
384 }
385
386 return *this;
387}
388
389
391{
392 return fileName::clean(*this);
393}
394
395
396std::string Foam::fileName::nameLessExt(const std::string& str)
397{
398 auto beg = str.rfind('/');
399 auto dot = str.rfind('.');
400
401 if (beg == npos)
402 {
403 beg = 0;
404 }
405 else
406 {
407 ++beg;
408 }
409
410 if (dot != npos && dot <= beg)
411 {
412 dot = npos;
413 }
414
415 if (dot == npos)
416 {
417 return str.substr(beg);
418 }
419
420 return str.substr(beg, dot - beg);
421}
422
423
425(
426 const fileName& parent,
427 const bool caseTag
428) const
429{
430 const auto top = parent.length();
431 const fileName& f = *this;
432
433 // Everything after "parent/xxx/yyy" -> "xxx/yyy"
434 //
435 // case-relative:
436 // "parent/xxx/yyy" -> "<case>/xxx/yyy"
437 // "parent/constant/xxx/yyy" -> "<constant>/xxx/yyy"
438 // "parent/system/xxx/yyy" -> "<system>/xxx/yyy"
439 //
440 // as per stringOps::inplaceExpand()
441
442 if
443 (
444 top && (f.length() > (top+1)) && f[top] == '/'
445 && f.starts_with(parent)
446 )
447 {
448 if (caseTag)
449 {
450 const auto trailing = f.find('/', top+1);
451
452 if (npos != trailing)
453 {
454 switch (trailing-top-1)
455 {
456 case 6: // "system"
457 {
458 if (!compare((top+1), 6, "system"))
459 {
460 return "<system>"/f.substr(trailing+1);
461 }
462 break;
463 }
464 case 8: // "constant"
465 {
466 if (!compare((top+1), 8, "constant"))
467 {
468 return "<constant>"/f.substr(trailing+1);
469 }
470 break;
471 }
472 }
473 }
474 return "<case>"/f.substr(top+1);
475 }
476 else
477 {
478 return f.substr(top+1);
479 }
480 }
481 else if (caseTag && f.length() && !f.isAbsolute())
482 {
483 const auto trailing = f.find('/');
484
485 if (npos != trailing)
486 {
487 switch (trailing)
488 {
489 case 6: // "system"
490 {
491 if (!compare(0, 6, "system"))
492 {
493 return "<system>"/f.substr(trailing+1);
494 }
495 break;
496 }
497 case 8: // "constant"
498 {
499 if (!compare(0, 8, "constant"))
500 {
501 return "<constant>"/f.substr(trailing+1);
502 }
503 break;
504 }
505 }
506 }
507 return "<case>"/f;
508 }
509
510 return f;
511}
512
513
515{
516 const auto parsed = stringOps::split<string>(*this, delim);
517
518 wordList words(parsed.size());
519
520 label i = 0;
521 for (const auto& sub : parsed)
522 {
523 // Could easily filter out '.' here too
524 words[i] = sub.str();
525 ++i;
526 }
527
528 // As a plain wordList
529 return words;
530}
531
532
534(
535 const size_type cmpt,
536 const char delim
537) const
538{
539 const auto parsed = stringOps::split<string>(*this, delim);
540
541 if (parsed.size())
542 {
543 if (cmpt == std::string::npos)
544 {
545 return parsed.last().str();
546 }
547 else if (cmpt < parsed.size())
548 {
549 return parsed[cmpt].str();
550 }
551 }
552
553 return word();
554}
555
556
557// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
558
560{
561 fileName& s = *this;
562
563 if (s.size())
564 {
565 if (other.size())
566 {
567 // Two non-empty strings: can concatenate
568
569 if (s.back() != '/' && other.front() != '/')
570 {
571 s += '/';
572 }
573
574 s += other;
575 }
576 }
577 else if (other.size())
578 {
579 // The first string is empty
580 s = other;
581 }
582
583 return *this;
584}
585
586
587// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
588
589Foam::fileName Foam::operator/(const string& s1, const string& s2)
590{
591 if (s1.length())
592 {
593 if (s2.length())
594 {
595 // Two non-empty strings: can concatenate
596
597 if (s1.back() == '/' || s2.front() == '/')
598 {
599 return fileName(s1 + s2);
600 }
601 else
602 {
603 return fileName(s1 + '/' + s2);
604 }
605 }
606
607 // The second string was empty
608 return s1;
609 }
610
611 if (s2.length())
612 {
613 // The first string is empty
614 return s2;
615 }
616
617 // Both strings are empty
618 return fileName();
619}
620
621
622// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
623
624Foam::fileName Foam::search(const word& file, const fileName& directory)
625{
626 // Search current directory for the file
627 for
628 (
629 const fileName& item
630 : fileHandler().readDir(directory, fileName::FILE)
631 )
632 {
633 if (item == file)
634 {
635 return directory/item;
636 }
637 }
638
639 // If not found search each of the sub-directories
640 for
641 (
642 const fileName& item
644 )
645 {
646 fileName path = search(file, directory/item);
647 if (!path.empty())
648 {
649 return path;
650 }
651 }
652
653 return fileName();
654}
655
656
657// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:75
Correction limiting method based on the relative particle velocity.
Definition: relative.H:63
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:212
bool valid() const
True if all internal ids are non-negative.
A class for handling file names.
Definition: fileName.H:76
bool clean()
Cleanup filename (inplace)
Definition: fileName.C:390
Type
Enumerations to handle directory entry types.
Definition: fileName.H:81
@ FILE
A regular file.
Definition: fileName.H:83
@ DIRECTORY
A directory.
Definition: fileName.H:84
fileName()=default
Default construct.
fileName & operator/=(const string &other)
Append a path element with '/' separator.
Definition: fileName.C:559
static fileName concat(const std::string &s1, const std::string &s2, const char delim='/')
Join two strings with a path separator ('/' by default).
Definition: fileName.C:218
static bool equals(const std::string &s1, const std::string &s2)
Definition: fileName.C:245
static const fileName null
An empty fileName.
Definition: fileName.H:102
fileName & toAbsolute()
Convert from relative to absolute.
Definition: fileName.C:377
static int debug
Debugging.
Definition: fileName.H:96
bool isBackup() const
Return true if file name ends with "~", ".bak", ".old", ".save".
Definition: fileNameI.H:164
static int allowSpaceInFileName
Allow space character in fileName. To be used with caution.
Definition: fileName.H:99
word nameLessExt() const
Return basename, without extension.
Definition: fileNameI.H:224
static const char *const typeName
The typeName.
Definition: fileName.H:93
Extracts the components of elements of a field and outputs the result into new fields,...
Definition: components.H:188
virtual void validate()
Validate the turbulence fields after construction.
Definition: kkLOmega.C:597
type
Volume classification types.
Definition: volumeType.H:66
A class for handling words, derived from Foam::string.
Definition: word.H:68
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
const dimensionedScalar c
Speed of light in a vacuum.
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
Definition: debug.C:231
int debugSwitch(const char *name, const int deflt=0)
Lookup debug switch or add default value.
Definition: debug.C:225
const fileOperation & fileHandler()
Get current file handler.
fileName cwd()
The physical or logical current working directory path name.
Definition: MSwindows.C:476
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
void dot(FieldField< Field1, typename innerProduct< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
dimensionedScalar operator/(const scalar s1, const dimensionedScalar &ds2)
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: MSwindows.C:715
fileName search(const word &file, const fileName &directory)
Recursively search the given directory for the file.
Definition: fileName.C:624
labelList f(nPoints)