Coverage Report

Created: 2026-07-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/build-dir/Source/cmsys/SystemTools.hxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
#ifndef cmsys_SystemTools_hxx
4
#define cmsys_SystemTools_hxx
5
6
#include <cmsys/Configure.hxx>
7
#include <cmsys/Status.hxx>
8
9
#include <ctime>
10
#include <iosfwd>
11
#include <map>
12
#include <string>
13
#include <vector>
14
15
#include <sys/types.h>
16
// include sys/stat.h after sys/types.h
17
#include <sys/stat.h>
18
19
#if !defined(_WIN32) || defined(__CYGWIN__)
20
#  include <unistd.h> // For access permissions for use with access()
21
#endif
22
23
// Required for va_list
24
#include <stdarg.h>
25
// Required for FILE*
26
#include <stdio.h>
27
#if !defined(va_list)
28
// Some compilers move va_list into the std namespace and there is no way to
29
// tell that this has been done. Playing with things being included before or
30
// after stdarg.h does not solve things because we do not have control over
31
// what the user does. This hack solves this problem by moving va_list to our
32
// own namespace that is local for kwsys.
33
namespace std {
34
} // Required for platforms that do not have std namespace
35
namespace cmsys_VA_LIST {
36
using namespace std;
37
typedef va_list hack_va_list;
38
}
39
namespace cmsys {
40
typedef cmsys_VA_LIST::hack_va_list va_list;
41
}
42
#endif // va_list
43
44
namespace cmsys {
45
46
class SystemToolsStatic;
47
48
/** \class SystemToolsManager
49
 * \brief Use to make sure SystemTools is initialized before it is used
50
 * and is the last static object destroyed
51
 */
52
class cmsys_EXPORT SystemToolsManager
53
{
54
public:
55
  SystemToolsManager();
56
  ~SystemToolsManager();
57
58
  SystemToolsManager(SystemToolsManager const&) = delete;
59
  SystemToolsManager& operator=(SystemToolsManager const&) = delete;
60
};
61
62
// This instance will show up in any translation unit that uses
63
// SystemTools. It will make sure SystemTools is initialized
64
// before it is used and is the last static object destroyed.
65
static SystemToolsManager SystemToolsManagerInstance;
66
67
// Flags for use with TestFileAccess.  Use a typedef in case any operating
68
// system in the future needs a special type.  These are flags that may be
69
// combined using the | operator.
70
typedef int TestFilePermissions;
71
#if defined(_WIN32) && !defined(__CYGWIN__)
72
// On Windows (VC), no system header defines these constants...
73
static TestFilePermissions const TEST_FILE_OK = 0;
74
static TestFilePermissions const TEST_FILE_READ = 4;
75
static TestFilePermissions const TEST_FILE_WRITE = 2;
76
static TestFilePermissions const TEST_FILE_EXECUTE = 1;
77
#else
78
// Standard POSIX constants
79
static TestFilePermissions const TEST_FILE_OK = F_OK;
80
static TestFilePermissions const TEST_FILE_READ = R_OK;
81
static TestFilePermissions const TEST_FILE_WRITE = W_OK;
82
static TestFilePermissions const TEST_FILE_EXECUTE = X_OK;
83
#endif
84
85
/** \class SystemTools
86
 * \brief A collection of useful platform-independent system functions.
87
 */
88
class cmsys_EXPORT SystemTools
89
{
90
public:
91
  /** -----------------------------------------------------------------
92
   *               String Manipulation Routines
93
   *  -----------------------------------------------------------------
94
   */
95
96
  /**
97
   * Replace symbols in str that are not valid in C identifiers as
98
   * defined by the 1999 standard, ie. anything except [A-Za-z0-9_].
99
   * They are replaced with `_' and if the first character is a digit
100
   * then an underscore is prepended.  Note that this can produce
101
   * identifiers that the standard reserves (_[A-Z].* and __.*).
102
   */
103
  static std::string MakeCidentifier(std::string const& s);
104
105
  static std::string MakeCindentifier(std::string const& s)
106
0
  {
107
0
    return MakeCidentifier(s);
108
0
  }
109
110
  /**
111
   * Replace replace all occurrences of the string in the source string.
112
   */
113
  static void ReplaceString(std::string& source, char const* replace,
114
                            char const* with);
115
  static void ReplaceString(std::string& source, std::string const& replace,
116
                            std::string const& with);
117
118
  /**
119
   * Return a capitalized string (i.e the first letter is uppercased,
120
   * all other are lowercased).
121
   */
122
  static std::string Capitalized(std::string const&);
123
124
  /**
125
   * Return a 'capitalized words' string (i.e the first letter of each word
126
   * is uppercased all other are left untouched though).
127
   */
128
  static std::string CapitalizedWords(std::string const&);
129
130
  /**
131
   * Return a 'uncapitalized words' string (i.e the first letter of each word
132
   * is lowercased all other are left untouched though).
133
   */
134
  static std::string UnCapitalizedWords(std::string const&);
135
136
  /** Return a lower-case string.  */
137
  static std::string LowerCase(std::string);
138
139
  /** Return an upper-case string.  */
140
  static std::string UpperCase(std::string);
141
142
  /**
143
   * Count char in string
144
   */
145
  static size_t CountChar(char const* str, char c);
146
147
  /**
148
   * Remove some characters from a string.
149
   * Return a pointer to the new resulting string (allocated with 'new')
150
   */
151
  static char* RemoveChars(char const* str, char const* toremove);
152
153
  /**
154
   * Remove remove all but 0->9, A->F characters from a string.
155
   * Return a pointer to the new resulting string (allocated with 'new')
156
   */
157
  static char* RemoveCharsButUpperHex(char const* str);
158
159
  /**
160
   * Replace some characters by another character in a string (in-place)
161
   * Return a pointer to string
162
   */
163
  static char* ReplaceChars(char* str, char const* toreplace,
164
                            char replacement);
165
166
  /**
167
   * Returns true if str1 starts (respectively ends) with str2
168
   */
169
  static bool StringStartsWith(char const* str1, char const* str2);
170
  static bool StringStartsWith(std::string const& str1, char const* str2);
171
  static bool StringEndsWith(char const* str1, char const* str2);
172
  static bool StringEndsWith(std::string const& str1, char const* str2);
173
174
  /**
175
   * Returns a pointer to the last occurrence of str2 in str1
176
   */
177
  static char const* FindLastString(char const* str1, char const* str2);
178
179
  /**
180
   * Make a duplicate of the string similar to the strdup C function
181
   * but use new to create the 'new' string, so one can use
182
   * 'delete' to remove it. Returns 0 if the input is empty.
183
   */
184
  static char* DuplicateString(char const* str);
185
186
  /**
187
   * Return the string cropped to a given length by removing chars in the
188
   * center of the string and replacing them with an ellipsis (...)
189
   */
190
  static std::string CropString(std::string const&, size_t max_len);
191
192
  /** split a path by separator into an array of strings, default is /.
193
      If isPath is true then the string is treated like a path and if
194
      s starts with a / then the first element of the returned array will
195
      be /, so /foo/bar will be [/, foo, bar]
196
  */
197
  static std::vector<std::string> SplitString(std::string const& s,
198
                                              char separator = '/',
199
                                              bool isPath = false);
200
  /**
201
   * Perform a case-independent string comparison.
202
   * Similar to POSIX's strcasecmp.
203
   */
204
  static int Strucmp(char const* s1, char const* s2);
205
206
  /**
207
   * Perform a case-independent string comparison, but compares at most n
208
   * characters. Similar to POSIX's strncasecmp.
209
   */
210
  static int Strnucmp(char const* s1, char const* s2, size_t n);
211
212
  /**
213
   * Split a string on its newlines into multiple lines
214
   * Return false only if the last line stored had no newline
215
   */
216
  static bool Split(std::string const& s, std::vector<std::string>& l);
217
  static bool Split(std::string const& s, std::vector<std::string>& l,
218
                    char separator);
219
220
  /**
221
   * Joins a vector of strings into a single string, with separator in between
222
   * each string.
223
   */
224
  static std::string Join(std::vector<std::string> const& list,
225
                          std::string const& separator);
226
227
  /**
228
   * Return string with space added between capitalized words
229
   * (i.e. EatMyShorts becomes Eat My Shorts )
230
   * (note that IEatShorts becomes IEat Shorts)
231
   */
232
  static std::string AddSpaceBetweenCapitalizedWords(std::string const&);
233
234
  /**
235
   * Append two or more strings and produce new one.
236
   * Programmer must 'delete []' the resulting string, which was allocated
237
   * with 'new'.
238
   * Return 0 if inputs are empty or there was an error
239
   */
240
  static char* AppendStrings(char const* str1, char const* str2);
241
  static char* AppendStrings(char const* str1, char const* str2,
242
                             char const* str3);
243
244
  /**
245
   * Estimate the length of the string that will be produced
246
   * from printing the given format string and arguments.  The
247
   * returned length will always be at least as large as the string
248
   * that will result from printing.
249
   * WARNING: since va_arg is called to iterate of the argument list,
250
   * you will not be able to use this 'ap' anymore from the beginning.
251
   * It's up to you to call va_end though.
252
   */
253
  static int EstimateFormatLength(char const* format, va_list ap);
254
255
  /**
256
   * Escape specific characters in 'str'.
257
   */
258
  static std::string EscapeChars(char const* str, char const* chars_to_escape,
259
                                 char escape_char = '\\');
260
261
  /** -----------------------------------------------------------------
262
   *               Filename Manipulation Routines
263
   *  -----------------------------------------------------------------
264
   */
265
266
  /**
267
   * Replace Windows file system slashes with Unix-style slashes.
268
   */
269
  static void ConvertToUnixSlashes(std::string& path);
270
271
#ifdef _WIN32
272
  /** Calls Encoding::ToWindowsExtendedPath.  */
273
  static std::wstring ConvertToWindowsExtendedPath(std::string const&);
274
#endif
275
276
  /**
277
   * For windows this calls ConvertToWindowsOutputPath and for unix
278
   * it calls ConvertToUnixOutputPath
279
   */
280
  static std::string ConvertToOutputPath(std::string const&);
281
282
  /**
283
   * Convert the path to a string that can be used in a unix makefile.
284
   * double slashes are removed, and spaces are escaped.
285
   */
286
  static std::string ConvertToUnixOutputPath(std::string const&);
287
288
  /**
289
   * Convert the path to string that can be used in a windows project or
290
   * makefile.   Double slashes are removed if they are not at the start of
291
   * the string, the slashes are converted to windows style backslashes, and
292
   * if there are spaces in the string it is double quoted.
293
   */
294
  static std::string ConvertToWindowsOutputPath(std::string const&);
295
296
  /**
297
   * Return true if a path with the given name exists in the current directory.
298
   */
299
  static bool PathExists(std::string const& path);
300
301
  /**
302
   * Return true if a file exists in the current directory.
303
   * If isFile = true, then make sure the file is a file and
304
   * not a directory.  If isFile = false, then return true
305
   * if it is a file or a directory.  Note that the file will
306
   * also be checked for read access.  (Currently, this check
307
   * for read access is only done on POSIX systems.)
308
   */
309
  static bool FileExists(char const* filename, bool isFile);
310
  static bool FileExists(std::string const& filename, bool isFile);
311
  static bool FileExists(char const* filename);
312
  static bool FileExists(std::string const& filename);
313
314
  /**
315
   * Test if a file exists and can be accessed with the requested
316
   * permissions.  Symbolic links are followed.  Returns true if
317
   * the access test was successful.
318
   *
319
   * On POSIX systems (including Cygwin), this maps to the access
320
   * function.  On Windows systems, all existing files are
321
   * considered readable, and writable files are considered to
322
   * have the read-only file attribute cleared.
323
   */
324
  static bool TestFileAccess(char const* filename,
325
                             TestFilePermissions permissions);
326
  static bool TestFileAccess(std::string const& filename,
327
                             TestFilePermissions permissions);
328
/**
329
 * Cross platform wrapper for stat struct
330
 */
331
#if defined(_WIN32) && !defined(__CYGWIN__)
332
  typedef struct _stat64 Stat_t;
333
#else
334
  typedef struct stat Stat_t;
335
#endif
336
337
  /**
338
   * Cross platform wrapper for stat system call
339
   *
340
   * On Windows this may not work for paths longer than 250 characters
341
   * due to limitations of the underlying '_wstat64' call.
342
   */
343
  static int Stat(char const* path, Stat_t* buf);
344
  static int Stat(std::string const& path, Stat_t* buf);
345
346
  /**
347
   * Return file length
348
   */
349
  static unsigned long FileLength(std::string const& filename);
350
351
  /**
352
     Change the modification time or create a file
353
  */
354
  static Status Touch(std::string const& filename, bool create);
355
356
  /**
357
   *  Compare file modification times.
358
   *  Return true for successful comparison and false for error.
359
   *  When true is returned, result has -1, 0, +1 for
360
   *  f1 older, same, or newer than f2.
361
   */
362
  static Status FileTimeCompare(std::string const& f1, std::string const& f2,
363
                                int* result);
364
365
  /**
366
   *  Get the file extension (including ".") needed for an executable
367
   *  on the current platform ("" for unix, ".exe" for Windows).
368
   */
369
  static char const* GetExecutableExtension();
370
371
  /**
372
   * Given a path on a Windows machine, return the actual case of
373
   * the path as it exists on disk.  Path components that do not
374
   * exist on disk are returned unchanged.  Relative paths are always
375
   * returned unchanged.  Drive letters are always made upper case.
376
   * This does nothing on non-Windows systems but return the path.
377
   */
378
  static std::string GetActualCaseForPath(std::string const& path);
379
380
  /**
381
   * Given the path to a program executable, get the directory part of
382
   * the path with the file stripped off.  If there is no directory
383
   * part, the empty string is returned.
384
   */
385
  static std::string GetProgramPath(std::string const&);
386
  static bool SplitProgramPath(std::string const& in_name, std::string& dir,
387
                               std::string& file, bool errorReport = true);
388
389
  /**
390
   * Given a path to a file or directory, convert it to a full path.
391
   * This collapses away relative paths relative to the cwd argument
392
   * (which defaults to the current working directory).  The full path
393
   * is returned.
394
   */
395
  static std::string CollapseFullPath(std::string const& in_path);
396
  static std::string CollapseFullPath(std::string const& in_path,
397
                                      char const* in_base);
398
  static std::string CollapseFullPath(std::string const& in_path,
399
                                      std::string const& in_base);
400
401
  /**
402
   * Get the real path for a given path, removing all symlinks.  In
403
   * the event of an error (non-existent path, permissions issue,
404
   * etc.) the original path is returned if errorMessage pointer is
405
   * nullptr.  Otherwise empty string is returned and errorMessage
406
   * contains error description.
407
   */
408
  static std::string GetRealPath(std::string const& path,
409
                                 std::string* errorMessage = nullptr);
410
411
  /**
412
   * Split a path name into its root component and the rest of the
413
   * path.  The root component is one of the following:
414
   *    "/"   = UNIX full path
415
   *    "c:/" = Windows full path (can be any drive letter)
416
   *    "c:"  = Windows drive-letter relative path (can be any drive letter)
417
   *    "//"  = Network path
418
   *    "~/"  = Home path for current user
419
   *    "~u/" = Home path for user 'u'
420
   *    ""    = Relative path
421
   *
422
   * A pointer to the rest of the path after the root component is
423
   * returned.  The root component is stored in the "root" string if
424
   * given.
425
   */
426
  static char const* SplitPathRootComponent(std::string const& p,
427
                                            std::string* root = nullptr);
428
429
  /**
430
   * Split a path name into its basic components.  The first component
431
   * always exists and is the root returned by SplitPathRootComponent.
432
   * The remaining components form the path.  If there is a trailing
433
   * slash then the last component is the empty string.  The
434
   * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to
435
   * produce the original path.  Home directory references are
436
   * automatically expanded if expand_home_dir is true and this
437
   * platform supports them.
438
   *
439
   * This does *not* normalize the input path.  All components are
440
   * preserved, including empty ones.  Typically callers should use
441
   * this only on paths that have already been normalized.
442
   */
443
  static void SplitPath(std::string const& p,
444
                        std::vector<std::string>& components,
445
                        bool expand_home_dir = true);
446
447
  /**
448
   * Join components of a path name into a single string.  See
449
   * SplitPath for the format of the components.
450
   *
451
   * This does *not* normalize the input path.  All components are
452
   * preserved, including empty ones.  Typically callers should use
453
   * this only on paths that have already been normalized.
454
   */
455
  static std::string JoinPath(std::vector<std::string> const& components);
456
  static std::string JoinPath(std::vector<std::string>::const_iterator first,
457
                              std::vector<std::string>::const_iterator last);
458
459
  /**
460
   * Compare a path or components of a path.
461
   */
462
  static bool ComparePath(std::string const& c1, std::string const& c2);
463
464
  /**
465
   * Return path of a full filename (no trailing slashes)
466
   */
467
  static std::string GetFilenamePath(std::string const&);
468
469
  /**
470
   * Return file name of a full filename (i.e. file name without path)
471
   */
472
  static std::string GetFilenameName(std::string const&);
473
474
  /**
475
   * Return longest file extension of a full filename (dot included)
476
   */
477
  static std::string GetFilenameExtension(std::string const&);
478
479
  /**
480
   * Return shortest file extension of a full filename (dot included)
481
   */
482
  static std::string GetFilenameLastExtension(std::string const& filename);
483
484
  /**
485
   * Return file name without extension of a full filename
486
   */
487
  static std::string GetFilenameWithoutExtension(std::string const&);
488
489
  /**
490
   * Return file name without its last (shortest) extension
491
   */
492
  static std::string GetFilenameWithoutLastExtension(std::string const&);
493
494
  /**
495
   * Return whether the path represents a full path (not relative)
496
   */
497
  static bool FileIsFullPath(std::string const&);
498
  static bool FileIsFullPath(char const*);
499
500
  /**
501
   * For windows return the short path for the given path,
502
   * Unix just a pass through
503
   */
504
  static Status GetShortPath(std::string const& path, std::string& result);
505
506
  /**
507
   * Read line from file. Make sure to read a full line and truncates it if
508
   * requested via sizeLimit. Returns true if any data were read before the
509
   * end-of-file was reached. If the has_newline argument is specified, it will
510
   * be true when the line read had a newline character.
511
   */
512
  static bool GetLineFromStream(
513
    std::istream& istr, std::string& line, bool* has_newline = nullptr,
514
    std::string::size_type sizeLimit = std::string::npos);
515
516
  /**
517
   * Get the parent directory of the directory or file
518
   */
519
  static std::string GetParentDirectory(std::string const& fileOrDir);
520
521
  /**
522
   * Check if the given file or directory is in subdirectory of dir
523
   */
524
  static bool IsSubDirectory(std::string const& fileOrDir,
525
                             std::string const& dir);
526
527
  /** -----------------------------------------------------------------
528
   *               File Manipulation Routines
529
   *  -----------------------------------------------------------------
530
   */
531
532
  /**
533
   * Open a file considering unicode. On Windows, if 'e' is present in
534
   * mode it is first discarded.
535
   */
536
  static FILE* Fopen(std::string const& file, char const* mode);
537
538
/**
539
 * Visual C++ does not define mode_t.
540
 */
541
#if defined(_MSC_VER)
542
  typedef unsigned short mode_t;
543
#endif
544
545
  /**
546
   * Make a new directory if it is not there.  This function
547
   * can make a full path even if none of the directories existed
548
   * prior to calling this function.
549
   */
550
  static Status MakeDirectory(char const* path, mode_t const* mode = nullptr);
551
  static Status MakeDirectory(std::string const& path,
552
                              mode_t const* mode = nullptr);
553
554
  /**
555
   * Represent the result of a file copy operation.
556
   * This is the result 'Status' and, if the operation failed,
557
   * an indication of whether the error occurred on the source
558
   * or destination path.
559
   */
560
  struct CopyStatus : public Status
561
  {
562
    enum WhichPath
563
    {
564
      NoPath,
565
      SourcePath,
566
      DestPath,
567
    };
568
0
    CopyStatus() = default;
569
    CopyStatus(Status s, WhichPath p)
570
0
      : Status(s)
571
0
      , Path(p)
572
0
    {
573
0
    }
574
    WhichPath Path = NoPath;
575
  };
576
577
  /**
578
   * Copy the source file to the destination file only
579
   * if the two files differ.
580
   */
581
  static CopyStatus CopyFileIfDifferent(std::string const& source,
582
                                        std::string const& destination);
583
584
  /**
585
   * Copy the source file to the destination file only
586
   * if the source file is newer than the destination file.
587
   */
588
  static CopyStatus CopyFileIfNewer(std::string const& source,
589
                                    std::string const& destination);
590
591
  /**
592
   * Compare the contents of two files.  Return true if different
593
   */
594
  static bool FilesDiffer(std::string const& source,
595
                          std::string const& destination);
596
597
  /**
598
   * Compare the contents of two files, ignoring line ending differences.
599
   * Return true if different
600
   */
601
  static bool TextFilesDiffer(std::string const& path1,
602
                              std::string const& path2);
603
604
  /**
605
   * Blockwise copy source to destination file
606
   */
607
  static CopyStatus CopyFileContentBlockwise(std::string const& source,
608
                                             std::string const& destination);
609
  /**
610
   * Clone the source file to the destination file
611
   */
612
  static CopyStatus CloneFileContent(std::string const& source,
613
                                     std::string const& destination);
614
615
  /**
616
   * Object encapsulating a unique identifier for a file
617
   * or directory
618
   */
619
#ifdef _WIN32
620
  class WindowsFileId
621
  {
622
  public:
623
    WindowsFileId() = default;
624
    WindowsFileId(unsigned long volumeSerialNumber,
625
                  unsigned long fileIndexHigh, unsigned long fileIndexLow);
626
627
    bool operator==(WindowsFileId const& o) const;
628
    bool operator!=(WindowsFileId const& o) const;
629
630
  private:
631
    unsigned long m_volumeSerialNumber;
632
    unsigned long m_fileIndexHigh;
633
    unsigned long m_fileIndexLow;
634
  };
635
  using FileId = WindowsFileId;
636
#else
637
  class UnixFileId
638
  {
639
  public:
640
    UnixFileId() = default;
641
    UnixFileId(dev_t volumeSerialNumber, ino_t fileSerialNumber,
642
               off_t fileSize);
643
644
    bool operator==(UnixFileId const& o) const;
645
    bool operator!=(UnixFileId const& o) const;
646
647
  private:
648
    dev_t m_volumeSerialNumber;
649
    ino_t m_fileSerialNumber;
650
    off_t m_fileSize;
651
  };
652
  using FileId = UnixFileId;
653
#endif
654
655
  /**
656
   * Outputs a FileId for the given file or directory.
657
   * Returns true on success, false on failure
658
   */
659
  static bool GetFileId(std::string const& file, FileId& id);
660
661
  /**
662
   * Return true if the two files are the same file
663
   */
664
  static bool SameFile(std::string const& file1, std::string const& file2);
665
666
  /**
667
   * Copy a file.
668
   */
669
  static CopyStatus CopyFileAlways(std::string const& source,
670
                                   std::string const& destination);
671
672
  enum class CopyWhen
673
  {
674
    Always,
675
    OnlyIfDifferent,
676
    OnlyIfNewer,
677
  };
678
679
  /**
680
   * Copy a file with specified copy behavior.
681
   */
682
  static CopyStatus CopyAFile(std::string const& source,
683
                              std::string const& destination,
684
                              CopyWhen when = CopyWhen::Always);
685
  static CopyStatus CopyAFile(std::string const& source,
686
                              std::string const& destination, bool always);
687
688
  /**
689
   * Copy content directory to another directory with all files and
690
   * subdirectories.  The "when" argument controls when files are copied:
691
   * Always: all files are always copied.
692
   * OnlyIfDifferent: only files that have changed are copied.
693
   * OnlyIfNewer: only files that are newer than the destination are copied.
694
   */
695
  static Status CopyADirectory(std::string const& source,
696
                               std::string const& destination,
697
                               CopyWhen when = CopyWhen::Always);
698
  static Status CopyADirectory(std::string const& source,
699
                               std::string const& destination, bool always);
700
701
  /**
702
   * Remove a file
703
   */
704
  static Status RemoveFile(std::string const& source);
705
706
  /**
707
   * Remove a directory
708
   */
709
  static Status RemoveADirectory(std::string const& source);
710
711
  /**
712
   * Get the maximum full file path length
713
   */
714
  static size_t GetMaximumFilePathLength();
715
716
  /**
717
   * Find a file in the system PATH, with optional extra paths
718
   */
719
  static std::string FindFile(
720
    std::string const& name,
721
    std::vector<std::string> const& path = std::vector<std::string>(),
722
    bool no_system_path = false);
723
724
  /**
725
   * Find a directory in the system PATH, with optional extra paths
726
   */
727
  static std::string FindDirectory(
728
    std::string const& name,
729
    std::vector<std::string> const& path = std::vector<std::string>(),
730
    bool no_system_path = false);
731
732
  /**
733
   * Find an executable in the system PATH, with optional extra paths
734
   */
735
  static std::string FindProgram(
736
    std::string const& name,
737
    std::vector<std::string> const& path = std::vector<std::string>(),
738
    bool no_system_path = false);
739
740
  /**
741
   * Return true if the file is a directory
742
   */
743
  static bool FileIsDirectory(std::string const& name);
744
745
  /**
746
   * Return true if the file is an executable
747
   */
748
  static bool FileIsExecutable(std::string const& name);
749
750
#if defined(_WIN32)
751
  /**
752
   * Return true if the file with FileAttributes `attr` is a symlink
753
   * Only available on Windows. This avoids an expensive `GetFileAttributesW`
754
   * call.
755
   */
756
  static bool FileIsSymlinkWithAttr(std::wstring const& path,
757
                                    unsigned long attr);
758
#endif
759
760
  /**
761
   * Return true if the file is a symlink
762
   */
763
  static bool FileIsSymlink(std::string const& name);
764
765
  /**
766
   * Return true if the file is a FIFO
767
   */
768
  static bool FileIsFIFO(std::string const& name);
769
770
  /**
771
   * Return true if the file has a given signature (first set of bytes)
772
   */
773
  static bool FileHasSignature(char const* filename, char const* signature,
774
                               long offset = 0);
775
776
  /**
777
   * Attempt to detect and return the type of a file.
778
   * Up to 'length' bytes are read from the file, if more than 'percent_bin' %
779
   * of the bytes are non-textual elements, the file is considered binary,
780
   * otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E]
781
   * range, but also \\n, \\r, \\t.
782
   * The algorithm is simplistic, and should probably check for usual file
783
   * extensions, 'magic' signature, unicode, etc.
784
   */
785
  enum FileTypeEnum
786
  {
787
    FileTypeUnknown,
788
    FileTypeBinary,
789
    FileTypeText
790
  };
791
  static SystemTools::FileTypeEnum DetectFileType(char const* filename,
792
                                                  unsigned long length = 256,
793
                                                  double percent_bin = 0.05);
794
795
  /**
796
   * Read the contents of a symbolic link.  Returns whether reading
797
   * succeeded.
798
   */
799
  static Status ReadSymlink(std::string const& newName, std::string& origName);
800
801
  /**
802
   * Try to locate the file 'filename' in the directory 'dir'.
803
   * If 'filename' is a fully qualified filename, the basename of the file is
804
   * used to check for its existence in 'dir'.
805
   * If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to
806
   * get its directory first (thus, you can pass a filename as 'dir', as
807
   * a convenience).
808
   * 'filename_found' is assigned the fully qualified name/path of the file
809
   * if it is found (not touched otherwise).
810
   * If 'try_filename_dirs' is true, try to find the file using the
811
   * components of its path, i.e. if we are looking for c:/foo/bar/bill.txt,
812
   * first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar
813
   * etc.
814
   * Return true if the file was found, false otherwise.
815
   */
816
  static bool LocateFileInDir(char const* filename, char const* dir,
817
                              std::string& filename_found,
818
                              int try_filename_dirs = 0);
819
820
  /** compute the relative path from local to remote.  local must
821
      be a directory.  remote can be a file or a directory.
822
      Both remote and local must be full paths.  Basically, if
823
      you are in directory local and you want to access the file in remote
824
      what is the relative path to do that.  For example:
825
      /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
826
      from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
827
  */
828
  static std::string RelativePath(std::string const& local,
829
                                  std::string const& remote);
830
831
  /**
832
   * Return file's modified time
833
   */
834
  static long int ModifiedTime(std::string const& filename);
835
836
  /**
837
   * Return file's creation time (Win32: works only for NTFS, not FAT)
838
   */
839
  static long int CreationTime(std::string const& filename);
840
841
  /**
842
   * Get and set permissions of the file.  If honor_umask is set, the umask
843
   * is queried and applied to the given permissions.  Returns false if
844
   * failure.
845
   *
846
   * WARNING:  A non-thread-safe method is currently used to get the umask
847
   * if a honor_umask parameter is set to true.
848
   */
849
  static Status GetPermissions(char const* file, mode_t& mode);
850
  static Status GetPermissions(std::string const& file, mode_t& mode);
851
  static Status SetPermissions(char const* file, mode_t mode,
852
                               bool honor_umask = false);
853
  static Status SetPermissions(std::string const& file, mode_t mode,
854
                               bool honor_umask = false);
855
856
  /** -----------------------------------------------------------------
857
   *               Time Manipulation Routines
858
   *  -----------------------------------------------------------------
859
   */
860
861
  /** Get time as local time (thread-safe).  */
862
  static std::tm LocalTime(std::time_t timep);
863
864
  /** Get time as UTC time (thread-safe).  */
865
  static std::tm GMTime(std::time_t timep);
866
867
  /** Get current time in seconds since Posix Epoch (Jan 1, 1970).  */
868
  static double GetTime();
869
870
  /**
871
   * Get current date/time
872
   */
873
  static std::string GetCurrentDateTime(char const* format);
874
875
  /** -----------------------------------------------------------------
876
   *               Registry Manipulation Routines
877
   *  -----------------------------------------------------------------
878
   */
879
880
  /**
881
   * Specify access to the 32-bit or 64-bit application view of
882
   * registry values.  The default is to match the currently running
883
   * binary type.
884
   */
885
  enum KeyWOW64
886
  {
887
    KeyWOW64_Default,
888
    KeyWOW64_32,
889
    KeyWOW64_64
890
  };
891
892
  /**
893
   * Get a list of subkeys.
894
   */
895
  static bool GetRegistrySubKeys(std::string const& key,
896
                                 std::vector<std::string>& subkeys,
897
                                 KeyWOW64 view = KeyWOW64_Default);
898
899
  /**
900
   * Read a registry value
901
   */
902
  static bool ReadRegistryValue(std::string const& key, std::string& value,
903
                                KeyWOW64 view = KeyWOW64_Default);
904
905
  /**
906
   * Write a registry value
907
   */
908
  static bool WriteRegistryValue(std::string const& key,
909
                                 std::string const& value,
910
                                 KeyWOW64 view = KeyWOW64_Default);
911
912
  /**
913
   * Delete a registry value
914
   */
915
  static bool DeleteRegistryValue(std::string const& key,
916
                                  KeyWOW64 view = KeyWOW64_Default);
917
918
  /** -----------------------------------------------------------------
919
   *               Environment Manipulation Routines
920
   *  -----------------------------------------------------------------
921
   */
922
923
  /**
924
   *  Add the paths from the environment variable PATH to the
925
   *  string vector passed in.  If env is set then the value
926
   *  of env will be used instead of PATH.
927
   */
928
  static void GetPath(std::vector<std::string>& path,
929
                      char const* env = nullptr);
930
931
  /**
932
   * Read an environment variable
933
   */
934
  static char const* GetEnv(char const* key);
935
  static char const* GetEnv(std::string const& key);
936
  static bool GetEnv(char const* key, std::string& result);
937
  static bool GetEnv(std::string const& key, std::string& result);
938
  static bool HasEnv(char const* key);
939
  static bool HasEnv(std::string const& key);
940
941
  /** Put a string into the environment
942
      of the form var=value */
943
  static bool PutEnv(std::string const& env);
944
945
  /** Remove a string from the environment.
946
      Input is of the form "var" or "var=value" (value is ignored). */
947
  static bool UnPutEnv(std::string const& env);
948
949
  /**
950
   * Get current working directory CWD
951
   */
952
  static std::string GetCurrentWorkingDirectory();
953
954
  /**
955
   * Change directory to the directory specified
956
   */
957
  static Status ChangeDirectory(std::string const& dir);
958
959
  /**
960
   * Get the result of strerror(errno)
961
   */
962
  static std::string GetLastSystemError();
963
964
  /**
965
   * When building DEBUG with MSVC, this enables a hook that prevents
966
   * error dialogs from popping up if the program is being run from
967
   * DART.
968
   */
969
  static void EnableMSVCDebugHook();
970
971
  /**
972
   * Get the width of the terminal window. The code may or may not work, so
973
   * make sure you have some reasonable defaults prepared if the code returns
974
   * some bogus size.
975
   */
976
  static int GetTerminalWidth();
977
978
  /**
979
   * Delay the execution for a specified amount of time specified
980
   * in milliseconds
981
   */
982
  static void Delay(unsigned int msec);
983
984
  /**
985
   * Get the operating system name and version
986
   * This is implemented for Win32 only for the moment
987
   */
988
  static std::string GetOperatingSystemNameAndVersion();
989
990
  /** -----------------------------------------------------------------
991
   *               URL Manipulation Routines
992
   *  -----------------------------------------------------------------
993
   */
994
995
  /**
996
   * Parse a character string :
997
   *       protocol://dataglom
998
   * and fill protocol as appropriate.
999
   * decode the dataglom using DecodeURL if set to true.
1000
   * Return false if the URL does not have the required form, true otherwise.
1001
   */
1002
  static bool ParseURLProtocol(std::string const& URL, std::string& protocol,
1003
                               std::string& dataglom, bool decode = false);
1004
1005
  /**
1006
   * Parse a string (a URL without protocol prefix) with the form:
1007
   *  protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath]
1008
   * and fill protocol, username, password, hostname, dataport, and datapath
1009
   * when values are found.
1010
   * decode all string except the protocol using DecodeUrl if set to true.
1011
   * Return true if the string matches the format; false otherwise.
1012
   */
1013
  static bool ParseURL(std::string const& URL, std::string& protocol,
1014
                       std::string& username, std::string& password,
1015
                       std::string& hostname, std::string& dataport,
1016
                       std::string& datapath, bool decode = false);
1017
1018
  /**
1019
   * Decode the percent-encoded string from an URL or an URI
1020
   * into their correct char values.
1021
   * Does not perform any other sort of validation.
1022
   * Return the decoded string
1023
   */
1024
  static std::string DecodeURL(std::string const& url);
1025
1026
private:
1027
  static void ClassInitialize();
1028
  static void ClassFinalize();
1029
1030
  /**
1031
   * This method prevents warning on SGI
1032
   */
1033
  SystemToolsManager* GetSystemToolsManager()
1034
0
  {
1035
0
    return &SystemToolsManagerInstance;
1036
0
  }
1037
1038
  friend class SystemToolsStatic;
1039
  friend class SystemToolsManager;
1040
};
1041
1042
} // namespace cmsys
1043
1044
#endif