Loading...
Searching...
No Matches
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-2025 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);
193
194} // End namespace Foam
195
196
197// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
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)
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);
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 fileName& f = *this;
380
381 if (!f.isAbsolute())
382 {
383 f = Foam::cwd()/f;
384 }
386 f.clean(); // Remove unneeded ".."
387
388 return *this;
389}
390
393{
394 return fileName::clean(*this);
395}
396
397
398std::string Foam::fileName::stem(const std::string& str)
399{
400 auto beg = str.rfind('/');
401 auto dot = str.rfind('.');
402
403 if (beg == npos)
404 {
405 beg = 0;
406 }
407 else
408 {
409 ++beg;
410 }
411
412 if (dot != npos && dot <= beg)
413 {
414 dot = npos;
415 }
416
417 if (dot == npos)
418 {
419 return str.substr(beg);
420 }
421
422 return str.substr(beg, dot - beg);
423}
424
425
427{
428 const auto len = newName.length();
429
430 if (len)
431 {
432 auto beg = rfind('/');
433
434 if (beg == npos)
435 {
436 fileName::assign(newName);
437 }
438 else
439 {
440 ++beg;
441 replace(beg, length()-beg, newName);
443 }
444
445 return *this;
446}
447
448
449Foam::fileName Foam::fileName::relative
450(
451 const fileName& parent,
452 const bool caseTag
453) const
454{
455 const auto top = parent.length();
456 const fileName& f = *this;
457
458 // Everything after "parent/xxx/yyy" -> "xxx/yyy"
459 //
460 // case-relative:
461 // "parent/xxx/yyy" -> "<case>/xxx/yyy"
462 // "parent/constant/xxx/yyy" -> "<constant>/xxx/yyy"
463 // "parent/system/xxx/yyy" -> "<system>/xxx/yyy"
464 //
465 // as per stringOps::inplaceExpand()
466
467 if
468 (
469 top && (f.length() > (top+1)) && f[top] == '/'
470 && f.starts_with(parent)
471 )
472 {
473 if (caseTag)
474 {
475 const auto trailing = f.find('/', top+1);
476
477 if (npos != trailing)
478 {
479 switch (trailing-top-1)
480 {
481 case 6: // "system"
482 {
483 if (!compare((top+1), 6, "system"))
484 {
485 return "<system>"/f.substr(trailing+1);
486 }
487 break;
488 }
489 case 8: // "constant"
490 {
491 if (!compare((top+1), 8, "constant"))
492 {
493 return "<constant>"/f.substr(trailing+1);
494 }
495 break;
496 }
497 }
498 }
499 return "<case>"/f.substr(top+1);
500 }
501 else
502 {
503 return f.substr(top+1);
504 }
505 }
506 else if (caseTag && f.length() && !f.isAbsolute())
507 {
508 const auto trailing = f.find('/');
509
510 if (npos != trailing)
511 {
512 switch (trailing)
513 {
514 case 6: // "system"
515 {
516 if (!compare(0, 6, "system"))
517 {
518 return "<system>"/f.substr(trailing+1);
519 }
520 break;
521 }
522 case 8: // "constant"
523 {
524 if (!compare(0, 8, "constant"))
525 {
526 return "<constant>"/f.substr(trailing+1);
527 }
528 break;
529 }
530 }
531 }
532 return "<case>"/f;
533 }
534
535 return f;
536}
537
538
539Foam::wordList Foam::fileName::components(const char delim) const
540{
541 const auto parsed = stringOps::split(*this, delim);
542
543 wordList words(parsed.size());
544
545 label i = 0;
546 for (const auto& sub : parsed)
547 {
548 // Could easily filter out '.' here too
549 words[i] = sub.str();
550 ++i;
552
553 // As a plain wordList
554 return words;
555}
556
557
559(
560 const size_type cmpt,
561 const char delim
562) const
563{
564 const auto parsed = stringOps::split(*this, delim);
565
566 if (parsed.size())
567 {
568 if (cmpt == std::string::npos)
569 {
570 return parsed.back().str();
571 }
572 else if (cmpt < parsed.size())
573 {
574 return parsed[cmpt].str();
575 }
576 }
578 return word();
579}
580
581
582// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
583
584Foam::fileName& Foam::fileName::operator/=(const string& other)
585{
586 fileName& s = *this;
587
588 if (s.size())
589 {
590 if (other.size())
591 {
592 // Two non-empty strings: can concatenate
593
594 if (s.back() != '/' && other.front() != '/')
595 {
596 s += '/';
597 }
598
599 s += other;
600 }
601 }
602 else if (other.size())
603 {
604 // The first string is empty
605 s = other;
606 }
608 return *this;
609}
610
611
612// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
613
614Foam::fileName Foam::operator/(const string& s1, const string& s2)
615{
616 if (s1.length())
617 {
618 if (s2.length())
619 {
620 // Two non-empty strings: can concatenate
621
622 if (s1.back() == '/' || s2.front() == '/')
623 {
624 return fileName(s1 + s2);
625 }
626 else
627 {
628 return fileName(s1 + '/' + s2);
629 }
630 }
631
632 // The second string was empty
633 return s1;
634 }
635
636 if (s2.length())
637 {
638 // The first string is empty
639 return s2;
640 }
641
642 // Both strings are empty
643 return fileName();
644}
645
646
647// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
648
649Foam::fileName Foam::search(const word& file, const fileName& directory)
650{
651 // Search current directory for the file
652 for
653 (
654 const fileName& item
655 : fileHandler().readDir(directory, fileName::FILE)
656 )
657 {
658 if (item == file)
659 {
660 return directory/item;
661 }
662 }
663
664 // If not found search each of the sub-directories
665 for
666 (
667 const fileName& item
669 )
670 {
671 fileName path = search(file, directory/item);
672 if (!path.empty())
673 {
674 return path;
675 }
676 }
677
678 return fileName();
679}
680
681
682// ************************************************************************* //
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
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:89
label find(const T &val) const
Find index of the first occurrence of the value.
Definition UList.C:160
A class for handling file names.
Definition fileName.H:75
wordList components(const char delim='/') const
Return path components as wordList.
Definition fileName.C:532
fileName relative(const fileName &parent, const bool caseTag=false) const
Return a relative name by stripping off the parent directory where possible.
Definition fileName.C:443
static fileName validate(const std::string &, const bool doClean=true)
Construct fileName without invalid characters, possibly applying other transformations such as changi...
Definition fileName.C:199
bool assign(const token &tok)
Assign from word or string token.
Definition fileNameIO.C:35
bool clean()
Cleanup filename (inplace).
Definition fileName.C:385
Type
Enumerations to handle directory entry types.
Definition fileName.H:82
@ UNDEFINED
Undefined type.
Definition fileName.H:83
@ FILE
A regular file.
Definition fileName.H:84
@ DIRECTORY
A directory.
Definition fileName.H:85
Type type(bool followLink=true, bool checkGzip=false) const
Return the directory entry type: UNDEFINED, FILE, DIRECTORY (or SYMLINK).
Definition fileName.C:353
fileName()=default
Default construct.
fileName & operator/=(const string &other)
Append a path element with '/' separator.
Definition fileName.C:577
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:211
static bool equals(const std::string &s1, const std::string &s2)
This is a specialized (possibly slower) version of compare() that ignores duplicate or trailing slash...
Definition fileName.C:238
word component(const size_type cmpt, const char delim='/') const
Return a single component of the path or empty if out of range.
Definition fileName.C:552
static const fileName null
An empty fileName.
Definition fileName.H:111
static bool valid(char c)
Is this character valid for a fileName?
Definition fileNameI.H:95
fileName & toAbsolute()
Convert from relative to absolute.
Definition fileName.C:370
static int debug
Debugging.
Definition fileName.H:101
fileName & replace_name(const word &newName)
Replace basename (part beyond last /) with a new name.
Definition fileName.C:419
bool isBackup() const
Return true if file name ends with "~", ".bak", ".old", ".save".
Definition fileNameI.H:157
static int allowSpaceInFileName
Allow space character in fileName. To be used with caution.
Definition fileName.H:106
word stem() const
Return basename, without extension.
Definition fileNameI.H:217
static const char *const typeName
The typeName.
Definition fileName.H:96
static std::string::size_type length(const char *s)
Length of the character sequence (with nullptr protection).
Definition string.H:259
string & replace(const std::string &s1, const std::string &s2, size_type pos=0)
Replace first occurrence of sub-string s1 with s2, beginning at pos.
Definition string.C:101
static std::string::size_type find_ext(const std::string &str)
Find position of a file extension dot, return npos on failure.
Definition stringI.H:24
A class for handling words, derived from Foam::string.
Definition word.H:66
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:228
int debugSwitch(const char *name, const int deflt=0)
Lookup debug switch or add default value.
Definition debug.C:222
Foam::SubStrings split(const std::string &str, const char delim, std::string::size_type pos=0, const bool keepEmpty=false)
Split string into sub-strings at the delimiter character.
fileName cwd()
The physical or logical current working directory path name.
Definition POSIX.C:592
List< word > wordList
List of word.
Definition fileName.H:60
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler().
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
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)
fileName search(const word &file, const fileName &directory)
Recursively search the given directory for the file.
Definition fileName.C:642
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition POSIX.C:965
labelList f(nPoints)
triangles reserve(surf.size())