A toolkit for working with phylogenetic data.
v0.24.0
fs.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include <cassert>
34 #include <cctype>
35 #include <dirent.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <fstream>
39 #include <functional>
40 #include <limits.h>
41 #include <regex>
42 #include <set>
43 #include <sstream>
44 #include <stdexcept>
45 #include <stdlib.h>
46 #include <streambuf>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <utility>
50 
59 
60 namespace genesis {
61 namespace utils {
62 
63 // =================================================================================================
64 // File Access
65 // =================================================================================================
66 
67 bool path_exists( std::string const& path )
68 {
69  struct stat info;
70  return ( stat( path.c_str(), &info ) == 0 );
71 }
72 
73 bool is_file( std::string const& path )
74 {
75  return file_exists( path );
76 }
77 
78 bool file_exists( std::string const& filename )
79 {
80  // There are plenty of discussions on stackoverflow on how to do this correctly,
81  // e.g., https://stackoverflow.com/a/12774387
82  // None of them worked for me, meaning that they also returned true for directories.
83  // Thus, we use a simple approach that does a basic check, and then also tests for dir...
84 
85  std::ifstream instream(filename);
86  instream.seekg( 0, std::ios::end);
87  return instream.good() && ! is_dir( filename );
88 }
89 
90 std::string file_read( std::string const& filename, bool detect_compression )
91 {
92  // Create string beforehand to enable copy elision.
93  std::string str;
94 
95  if( detect_compression && is_gzip_compressed_file( filename )) {
96 
97  // Open decompressing stream
98  GzipIFStream instream( filename );
99  if( !instream.good() ) {
100  throw std::runtime_error( "Cannot read from file '" + filename + "'." );
101  }
102 
103  // Can't assess file size for compressed files, so just read.
104  str.assign(
105  std::istreambuf_iterator<char>(instream),
106  std::istreambuf_iterator<char>()
107  );
108  return str;
109  }
110 
111  // Open normal stream
112  std::ifstream instream(filename);
113  if( !instream.good() ) {
114  throw std::runtime_error( "Cannot read from file '" + filename + "'." );
115  }
116 
117  // Get file size, so that we do not waste time and space for string concats.
118  instream.seekg(0, std::ios::end);
119  str.reserve(instream.tellg());
120  instream.seekg(0, std::ios::beg);
121 
122  // Read content
123  str.assign(
124  std::istreambuf_iterator<char>(instream),
125  std::istreambuf_iterator<char>()
126  );
127  return str;
128 }
129 
130 std::vector<std::string> file_read_lines( std::string const& filename, bool detect_compression )
131 {
132  std::vector<std::string> result;
133  utils::InputStream it( from_file( filename, detect_compression ));
134  while( it ) {
135  result.push_back( read_to_end_of_line( it ));
136  assert( !it || *it == '\n' );
137  ++it;
138  }
139  return result;
140 }
141 
142 void file_write( std::string const& content, std::string const& filename )
143 {
144  // TODO check if path exists, create if not (make a function for that)
145 
146  std::ofstream ofs;
147  utils::file_output_stream( filename, ofs );
148  ofs << content;
149 }
150 
151 void file_append( std::string const& content, std::string const& filename )
152 {
153  // TODO check if path exists, create if not (make a function for that)
154  // TODO maybe merge with file_write and use mode as optional parameter.
155 
156  std::ofstream out_stream( filename, std::ofstream::app );
157  if( out_stream.fail() ) {
158  throw std::runtime_error( "Cannot append to file '" + filename + "'." );
159  }
160  out_stream << content;
161 }
162 
163 // =================================================================================================
164 // Directory Access
165 // =================================================================================================
166 
167 bool is_dir( std::string const& path )
168 {
169  return dir_exists( path );
170 }
171 
172 bool dir_exists( std::string const& dir )
173 {
174  struct stat info;
175  if (stat (dir.c_str(), &info) != 0) {
176  return false;
177  }
178  return static_cast<bool>( info.st_mode & S_IFDIR );
179 
180  // alternative implementation:
181  // DIR* dp = opendir(dir);
182  // if (dp) {
183  // closedir(dir);
184  // return dp;
185  // } else {
186  // return false;
187  // }
188 }
189 
190 void dir_create( std::string const& path, bool with_parents )
191 {
192  mode_t mode = 0775;
193  struct stat info;
194 
195  // Checks. If it is the current dir, do nothing.
196  auto const path_no_bs = utils::trim_right( path, "/\\");
197  if( path_no_bs.empty() ) {
198  return;
199  }
200 
201  // Run recursively.
202  if( with_parents ) {
203  if( ! dir_exists( path_no_bs ) && path_no_bs.size() > 0 ) {
204  dir_create( file_path( path_no_bs ), true );
205  }
206  }
207 
208  // Try to make dir.
209  if( stat (path.c_str(), &info) != 0 ) {
210  if( mkdir( path.c_str(), mode ) != 0 && errno != EEXIST ) {
211  throw std::runtime_error( "Cannot create directory: " + path );
212  }
213  } else if( !S_ISDIR(info.st_mode) ) {
214  throw std::runtime_error( "Path exists, but is not a directory: " + path );
215  }
216 }
217 
218 std::string dir_normalize_path( std::string const& path )
219 {
220  return utils::trim_right( path, "/") + "/";
221 }
222 
223 static std::vector<std::string> dir_list_contents_(
224  std::string const& dir,
225  bool full_path,
226  std::string const& regex,
227  std::function<bool( std::string const& )> condition
228 ) {
229  std::vector<std::string> list;
230  auto const dir_path = dir_normalize_path( dir );
231  std::regex pattern( regex );
232 
233  DIR* dp;
234  struct dirent* dirp;
235 
236  if( ( dp = opendir( dir.c_str() )) == nullptr) {
237  throw std::runtime_error( "Cannot open directory '" + dir + "'." );
238  }
239  while ((dirp = readdir(dp)) != nullptr) {
240  auto const fn = std::string( dirp->d_name );
241 
242  if (fn == "." || fn == "..") {
243  continue;
244  }
245  if( ! regex.empty() && ! regex_match( fn, pattern ) ) {
246  continue;
247  }
248  if( ! condition( dir_path + fn ) ) {
249  continue;
250  }
251 
252  if( full_path ) {
253  list.push_back( dir_path + fn );
254  } else {
255  list.push_back( fn );
256  }
257  }
258  closedir(dp);
259 
260  //~ std::sort(list.begin(), list.end());
261  return list;
262 }
263 
264 std::vector<std::string> dir_list_contents(
265  std::string const& dir,
266  bool full_path,
267  std::string const& regex
268 ) {
269  return dir_list_contents_(
270  dir, full_path, regex,
271  []( std::string const& ){ return true; }
272  );
273 }
274 
275 std::vector<std::string> dir_list_files(
276  std::string const& dir,
277  bool full_path,
278  std::string const& regex
279 ) {
280  return dir_list_contents_(
281  dir, full_path, regex, is_file
282  );
283 }
284 
285 std::vector<std::string> dir_list_directories(
286  std::string const& dir,
287  bool full_path,
288  std::string const& regex
289 ) {
290  return dir_list_contents_(
291  dir, full_path, regex, is_dir
292  );
293 }
294 
295 // =================================================================================================
296 // Path Information
297 // =================================================================================================
298 
299 static std::string current_path_getcwd_()
300 {
301  // Wrapper for the standard getcwd() function to bring it into C++
302  // Adapted from https://stackoverflow.com/a/2203853/4184258
303 
304  // The local buffer of size PATH_MAX is fine for Windows, but pretty much no other OS.
305  char temp[ PATH_MAX ];
306  errno = 0;
307  if( getcwd( temp, PATH_MAX ) != nullptr ) {
308  return dir_normalize_path( std::string( temp ));
309  }
310 
311  int error = errno;
312  switch( error ) {
313  case EACCES:
314  throw std::runtime_error( "Cannot read current directory. Access denied." );
315 
316  case ENOMEM:
317  throw std::runtime_error( "Cannot read current directory. Insufficient storage." );
318 
319  default: {
320  std::ostringstream str;
321  str << "Cannot read current directory. Unrecognised error: " << error;
322  throw std::runtime_error( str.str() );
323  }
324  }
325 
326  // Make compilers happy.
327  return "";
328 }
329 
330 static std::string current_path_unix_()
331 {
332  // Code adapted from http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
333  // Does not work on Windows systems.
334 
335  std::string path;
336  typedef std::pair<dev_t, ino_t> file_id;
337 
338  // Keep track of start directory, so can jump back to it later
339  int start_fd = open(".", O_RDONLY);
340  if( start_fd == -1 ) {
341  throw std::runtime_error( "Cannot read current directory." );
342  }
343 
344  struct stat sb;
345  if( fstat(start_fd, &sb) ) {
346  throw std::runtime_error( "Cannot read current directory." );
347  }
348 
349  // Get info for root directory, so we can determine when we hit it
350  file_id current_id(sb.st_dev, sb.st_ino);
351  if( stat( "/", &sb )) {
352  throw std::runtime_error( "Cannot read current directory." );
353  }
354 
355  std::vector<std::string> path_components;
356  file_id root_id(sb.st_dev, sb.st_ino);
357 
358  // If they're equal, we've obtained enough info to build the path
359  while( current_id != root_id ) {
360  bool pushed = false;
361 
362  // Keep recursing towards root each iteration
363  if( ! chdir("..") ) {
364  DIR *dir = opendir(".");
365  if( dir ) {
366  dirent *entry;
367 
368  // We loop through each entry trying to find where we came from
369  while(( entry = readdir(dir) )) {
370  if(
371  strcmp(entry->d_name, ".")
372  && strcmp(entry->d_name, "..")
373  && !lstat(entry->d_name, &sb)
374  ) {
375  file_id child_id(sb.st_dev, sb.st_ino);
376 
377  // We found where we came from, add its name to the list
378  if( child_id == current_id ) {
379  path_components.push_back(entry->d_name);
380  pushed = true;
381  break;
382  }
383  }
384  }
385  closedir(dir);
386 
387  // If we have a reason to continue, we update the current dir id
388  if( pushed && !stat(".", &sb) ) {
389  current_id = file_id(sb.st_dev, sb.st_ino);
390  }
391  // Else, Uh oh, can't read information at this level
392  }
393  }
394 
395  // If we didn't obtain any info this pass, no reason to continue
396  if( ! pushed ) {
397  break;
398  }
399  }
400 
401  // Unless they're equal, we failed above
402  if( current_id == root_id ) {
403 
404  // Built the path, will always end with a slash
405  path = "/";
406  for( auto i = path_components.rbegin(); i != path_components.rend(); ++i ) {
407  path += *i + "/";
408  }
409  } else {
410  throw std::runtime_error( "Cannot read current directory." );
411  }
412 
413  if( fchdir(start_fd) ) {
414  throw std::runtime_error( "Cannot change directory." );
415  }
416  close(start_fd);
417 
418  return path;
419 }
420 
421 std::string current_path()
422 {
423  // We use our own implementations here, which depend on the OS.
424  #if defined( _WIN32 ) || defined( _WIN64 )
425  return current_path_getcwd_();
426  #else
427  return current_path_unix_();
428  #endif
429 
430  // We use conditional compilation. Silence compiler warnings about unused functions.
431  (void) current_path_getcwd_;
432  (void) current_path_unix_;
433 }
434 
435 // The following set of helper functions is adapted from
436 // http://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html
437 // See there for details.
438 
439 static void relative_dir_base_split_( std::string const& path, std::string& dir, std::string& base )
440 {
441  // Find the last slash
442  auto slash_pos = path.rfind("/");
443 
444  // If there is a slash
445  if (slash_pos != std::string::npos) {
446  slash_pos++;
447 
448  // Directory is before slash
449  dir = path.substr(0, slash_pos);
450 
451  // And obviously, the file is after
452  base = path.substr(slash_pos);
453  } else {
454  // Otherwise, there is no directory present
455  dir.clear();
456  base = path;
457  }
458 }
459 
460 static std::string chdir_getcwd_( std::string const& dir )
461 {
462  // Open current directory so we can save a handle to it
463  int start_fd = open(".", O_RDONLY);
464  if (start_fd == -1) {
465  throw std::runtime_error( "Cannot open current directory." );
466  }
467 
468  // Change to directory
469  if( chdir(dir.c_str()) ) {
470  throw std::runtime_error( "Cannot change directory." );
471  }
472 
473  // And get its path
474  auto const path = current_path();
475 
476  // And change back of course
477  if( fchdir(start_fd) ) {
478  throw std::runtime_error( "Cannot change directory." );
479  }
480  close(start_fd);
481 
482  return path;
483 }
484 
485 static std::string realpath_file_(const std::string& path )
486 {
487  std::string dir;
488  std::string base;
489  relative_dir_base_split_(path, dir, base);
490 
491  // If there is a directory, get the realpath() for it, otherwise the current directory
492  auto resolved_path = dir.size() ? chdir_getcwd_(dir) : current_path();
493  return resolved_path + base;
494 }
495 
496 static bool readlink_internal_(const std::string& path, std::string& buffer, ssize_t length)
497 {
498  bool success = false;
499  if (length > 0) {
500  // Room for Null
501  char *buf = new(std::nothrow) char[length+1];
502 
503  if (buf) {
504  // Give room for failure
505  ssize_t amount = ::readlink(path.c_str(), buf, length+1);
506 
507  // If > length, it was modified mid check
508  if ((amount > 0) && (amount <= length)) {
509  buf[amount] = 0;
510  buffer = buf;
511  success = true;
512  }
513  delete[] buf;
514  }
515  }
516 
517  return success;
518 }
519 
520 static void build_path_base_swap_(std::string &path, const std::string& newbase)
521 {
522  std::string dir;
523  std::string base;
524  relative_dir_base_split_(path, dir, base);
525 
526  if (dir.size()) {
527  path = dir + newbase;
528  } else {
529  path = newbase;
530  }
531 }
532 
533 static bool symlink_resolve_( const std::string& start, std::string& end )
534 {
535  typedef std::pair<dev_t, ino_t> file_id;
536 
537  bool success = false;
538  if (start.size()) {
539  // Need a modifyable copy
540  std::string path = start;
541  struct stat sb;
542  std::set<file_id> seen_links;
543 
544  bool resolved_link;
545  // The symlink resolve loop
546  do {
547  resolved_link = false;
548  if (!lstat(path.c_str(), &sb)) {
549  file_id current_id(sb.st_dev, sb.st_ino);
550  // Not a link we've seen
551  if (seen_links.find(current_id) == seen_links.end()) {
552  // Add to our set
553  seen_links.insert(current_id);
554 
555  // Another link
556  if (S_ISLNK(sb.st_mode)) {
557  std::string newpath;
558  if (readlink_internal_(path, newpath, sb.st_size)) {
559  // Absolute
560  if (newpath[0] == '/') {
561  path = newpath;
562  } else {
563  // We need to calculate the relative path in relation to the current
564  build_path_base_swap_(path, newpath);
565  }
566  resolved_link = true;
567  // Else, Link can't be read, time to quit
568  }
569  } else {
570  // Yay, it's not a link! got to the last part finally!
571  end = realpath_file_( path );
572  success = true;
573  }
574  // Else, Nice try, someone linked a link back into a previous link
575  // during the scan to try to trick us into an infinite loop.
576  }
577  // Else, Dangling link, can't resolve
578  }
579  } while (resolved_link);
580  }
581  return(success);
582 }
583 
584 static std::string real_path_unix_( std::string const& path, bool resolve_link )
585 {
586  // Custom implementation, using the above helper functions. Based on
587  // http://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html
588  // See there for details.
589 
590  // Edge case.
591  if( ! path.size()) {
592  return path;
593  }
594 
595  struct stat sb;
596  if( stat(path.c_str(), &sb) ) {
597  throw std::runtime_error( "Cannot read path." );
598  }
599 
600  if( S_ISDIR( sb.st_mode )) {
601  return chdir_getcwd_( path );
602  } else {
603  if( resolve_link ) {
604  std::string result;
605  if( ! symlink_resolve_( path, result ) ) {
606  throw std::runtime_error( "Cannot determine real path." );
607  }
608  return result;
609  } else {
610  return realpath_file_( path );
611  }
612  }
613 
614  // Make compilers happy.
615  return path;
616 }
617 
618 static std::string real_path_realpath_( std::string const& path, bool resolve_link )
619 {
620  // Wrapper for the standard realpath() function to bring it into C++
621  // Works on Windows.
622 
623  // Not supported in this function...
624  (void) resolve_link;
625 
626  errno = 0;
627  char resolved_path[PATH_MAX];
628  auto ptr = realpath( path.c_str(), resolved_path );
629  if( errno != 0 ) {
630  throw std::runtime_error( "Cannot determine real path." );
631  }
632  return std::string( ptr );
633 }
634 
635 std::string real_path( std::string const& path, bool resolve_link )
636 {
637  // We use our own implementations here, which depend on the OS.
638  #if defined( _WIN32 ) || defined( _WIN64 )
639  return real_path_realpath_( path, resolve_link );
640  #else
641  return real_path_unix_( path, resolve_link );
642  #endif
643 
644  // We use conditional compilation. Silence compiler warnings about unused functions.
645  (void) real_path_realpath_;
646  (void) real_path_unix_;
647 }
648 
649 // =================================================================================================
650 // File Information
651 // =================================================================================================
652 
653 std::unordered_map<std::string, std::string> file_info( std::string const& filename )
654 {
655  std::string basename = file_basename(filename);
656  std::unordered_map<std::string, std::string> res;
657 
658  res["path"] = file_path(filename);
659  res["basename"] = basename;
660  res["filename"] = file_filename(basename);
661  res["extension"] = file_extension(basename);
662 
663  return res;
664 }
665 
666 size_t file_size( std::string const& filename )
667 {
668  auto result = filename;
669  std::ifstream in(result, std::ifstream::ate | std::ifstream::binary);
670  return static_cast<size_t>(in.tellg());
671 }
672 
673 std::string file_path( std::string const& filename )
674 {
675  auto result = filename;
676  const size_t idx = result.find_last_of("\\/");
677  if( idx == std::string::npos ) {
678  return "";
679  }
680 
681  result.erase(idx);
682  return result;
683 }
684 
685 std::string file_basename( std::string const& filename )
686 {
687  auto result = filename;
688  const size_t idx = result.find_last_of("\\/");
689  if (idx != std::string::npos)
690  {
691  result.erase(0, idx + 1);
692  }
693  return result;
694 }
695 
696 std::string file_filename( std::string const& filename )
697 {
698  auto result = filename;
699  const size_t idx = result.rfind('.');
700  if (idx != 0 && idx != std::string::npos)
701  {
702  result.erase(idx);
703  }
704  return result;
705 }
706 
707 std::string file_extension( std::string const& filename )
708 {
709  auto result = filename;
710  const size_t idx = result.rfind('.');
711  if (idx != 0 && idx != std::string::npos)
712  {
713  result.erase(0, idx + 1);
714  }
715  return result;
716 }
717 
718 // =================================================================================================
719 // File Names
720 // =================================================================================================
721 
722 bool is_valid_filename( std::string const& filename )
723 {
724  // No empty filenames.
725  if( trim( filename ) == "" ) {
726  return false;
727  }
728 
729  // No space at beginning or end.
730  if( starts_with( filename, " " ) || ends_with( filename, " " )) {
731  return false;
732  }
733 
734  // Check forbidden chars of Win and Unix systems.
735  if( filename.find_first_of( "<>:\"\\/|?*" ) != std::string::npos ) {
736  return false;
737  }
738 
739  // Check for non-printable chars.
740  // They might be allowed on most systems, but better be conservative here.
741  for( auto c : filename ) {
742  if( ! isprint( c ) ) {
743  return false;
744  }
745  }
746 
747  return true;
748 }
749 
750 std::string sanitize_filename( std::string const& filename )
751 {
752  // Prepare result.
753  std::string result = "";
754  result.reserve( filename.size() );
755 
756  // Copy all printable chars, drop the others.
757  for( auto c : filename ) {
758  if( isprint( c ) ) {
759  result += c;
760  }
761  }
762 
763  // No spaces around the name, and replace all forbidden chars by underscores.
764  result = trim( result );
765  result = replace_all_chars( result, "<>:\"\\/|?*", '_' );
766 
767  if( result == "" ) {
768  throw std::runtime_error( "Invalid filename." );
769  }
770 
771  return result;
772 }
773 
774 } // namespace utils
775 } // namespace genesis
bool is_file(std::string const &path)
Return true iff the provided path is a file.
Definition: fs.cpp:73
void file_write(std::string const &content, std::string const &filename)
Write the content of a string to a file.
Definition: fs.cpp:142
static std::string realpath_file_(const std::string &path)
Definition: fs.cpp:485
std::unordered_map< std::string, std::string > file_info(std::string const &filename)
Return information about a file.
Definition: fs.cpp:653
Provides some valuable algorithms that are not part of the C++ 11 STL.
std::vector< std::string > dir_list_files(std::string const &dir, bool full_path, std::string const &regex)
Get a list of files in a directory.
Definition: fs.cpp:275
std::string file_extension(std::string const &filename)
Return the extension name of a file.
Definition: fs.cpp:707
static std::string real_path_realpath_(std::string const &path, bool resolve_link)
Definition: fs.cpp:618
bool starts_with(std::string const &text, std::string const &start)
Return whether a string starts with another string.
Definition: string.cpp:79
std::string file_path(std::string const &filename)
Return the path leading to a file.
Definition: fs.cpp:673
static std::string current_path_unix_()
Definition: fs.cpp:330
void file_output_stream(std::string const &filename, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out)
Helper function to obtain an output stream to a file.
std::string current_path()
Return the current (working) directory, simiar to getcwd().
Definition: fs.cpp:421
static void build_path_base_swap_(std::string &path, const std::string &newbase)
Definition: fs.cpp:520
void dir_create(std::string const &path, bool with_parents)
Create a directory.
Definition: fs.cpp:190
std::string file_read(std::string const &filename, bool detect_compression)
Return the contents of a file as a string.
Definition: fs.cpp:90
bool dir_exists(std::string const &dir)
Return true iff the directory exists.
Definition: fs.cpp:172
std::string file_filename(std::string const &filename)
Remove extension if present.
Definition: fs.cpp:696
std::string read_to_end_of_line(InputStream &source)
Lexing function that reads until the end of the line (i.e., to the new line char), and returns the read chars (excluding the new line char).
Definition: scanner.hpp:134
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
bool file_exists(std::string const &filename)
Return true iff the file exists.
Definition: fs.cpp:78
bool is_dir(std::string const &path)
Return true iff the provided path is a directory.
Definition: fs.cpp:167
size_t file_size(std::string const &filename)
Return the size of a file.
Definition: fs.cpp:666
std::vector< std::string > dir_list_directories(std::string const &dir, bool full_path, std::string const &regex)
Get a list of directories in a directory.
Definition: fs.cpp:285
static void relative_dir_base_split_(std::string const &path, std::string &dir, std::string &base)
Definition: fs.cpp:439
Input file stream that offers on-the-fly gzip-decompression if needed.
std::string file_basename(std::string const &filename)
Remove directory name from file name if present.
Definition: fs.cpp:685
utils::Range< IteratorPath< true > > path(ElementType const &start, ElementType const &finish)
Definition: path.hpp:337
static std::vector< std::string > dir_list_contents_(std::string const &dir, bool full_path, std::string const &regex, std::function< bool(std::string const &)> condition)
Definition: fs.cpp:223
std::string real_path(std::string const &path, bool resolve_link)
Return the real path of a file or directory, similar to realpath().
Definition: fs.cpp:635
static std::string real_path_unix_(std::string const &path, bool resolve_link)
Definition: fs.cpp:584
static bool symlink_resolve_(const std::string &start, std::string &end)
Definition: fs.cpp:533
bool is_valid_filename(std::string const &filename)
Check whether a file name is valid.
Definition: fs.cpp:722
std::string trim_right(std::string const &s, std::string const &delimiters)
Return a copy of the input string, with left trimmed white spaces.
Definition: string.cpp:370
std::string trim(std::string const &s, std::string const &delimiters)
Return a copy of the input string, with trimmed white spaces.
Definition: string.cpp:394
std::string replace_all_chars(std::string const &text, std::string const &search_chars, char replace)
Replace all occurrences of the search_chars in text by the replace char.
Definition: string.cpp:356
static std::string chdir_getcwd_(std::string const &dir)
Definition: fs.cpp:460
Provides some commonly used string utility functions.
Provides functions for accessing the file system.
bool ends_with(std::string const &text, std::string const &ending)
Return whether a string ends with another string.
Definition: string.cpp:87
static bool readlink_internal_(const std::string &path, std::string &buffer, ssize_t length)
Definition: fs.cpp:496
std::shared_ptr< BaseInputSource > from_file(std::string const &file_name, bool detect_compression=true)
Obtain an input source for reading from a file.
std::vector< std::string > dir_list_contents(std::string const &dir, bool full_path, std::string const &regex)
Get a list of files and directories in a directory.
Definition: fs.cpp:264
std::vector< std::string > file_read_lines(std::string const &filename, bool detect_compression)
Return the contents of a file as a vector of strings, one entry for each line.
Definition: fs.cpp:130
void file_append(std::string const &content, std::string const &filename)
Append the content of a string to a file.
Definition: fs.cpp:151
double length(Tree const &tree)
Get the length of the tree, i.e., the sum of all branch lengths.
std::string sanitize_filename(std::string const &filename)
Remove or replace all invalid parts of a filename.
Definition: fs.cpp:750
bool path_exists(std::string const &path)
Return whether a path exists, i.e., is a file or directory.
Definition: fs.cpp:67
std::string dir_normalize_path(std::string const &path)
Normalize a dir name, i.e., make sure that the given path ends with exaclty one slash.
Definition: fs.cpp:218
bool is_gzip_compressed_file(std::string const &file_name)
Return whether a given file is gzip-compressed.
Definition: gzip.cpp:58
static std::string current_path_getcwd_()
Definition: fs.cpp:299
Stream interface for reading data from an InputSource, that keeps track of line and column counters...