openMSX
foreach_file.hh
Go to the documentation of this file.
1 #ifndef FOREACH_FILE_HH
2 #define FOREACH_FILE_HH
3 
4 #include "FileOperations.hh"
5 #include "ReadDir.hh"
6 #include "StringOp.hh"
7 #include "one_of.hh"
8 #include <functional>
9 #include <string_view>
10 #include <tuple>
11 
49 namespace openmsx {
50  namespace detail {
51  using namespace FileOperations;
52 
53  // Take an action that accepts the following parameters:
54  // - a 'std::string&' or 'const std::string&' parameter
55  // - optionally a std::string_view parameter
56  // - optionally a 'FileOperations::Stat&' parameter
57  // And returns a wrapper that makes the 2nd and 3rd parameter
58  // non-optional, but (possibly) ignores those parameters when
59  // delegating to the wrapped action.
60  template<typename Action>
61  auto adaptParams(Action action) {
62  if constexpr (std::is_invocable_v<Action, std::string&, std::string_view, Stat&>) {
63  return std::tuple(action, true);
64  } else if constexpr (std::is_invocable_v<Action, std::string&, std::string_view>) {
65  return std::tuple([action](std::string& p, std::string_view f, Stat& /*st*/) {
66  return action(p, f);
67  }, false);
68  } else if constexpr (std::is_invocable_v<Action, std::string&, Stat&>) {
69  return std::tuple([action](std::string& p, std::string_view /*f*/, Stat& st) {
70  return action(p, st);
71  }, true);
72  } else if constexpr (std::is_invocable_v<Action, std::string&>) {
73  return std::tuple([action](std::string& p, std::string_view /*f*/, Stat& /*st*/) {
74  return action(p);
75  }, false);
76  } else {
77  static_assert((Action{}, false), "Wrong signature for action");
78  }
79  }
80 
81  // Take an action and
82  // - return it unchanged if it already returned a non-void result
83  // - otherwise return a wrapper that invokes the given action and then returns 'true'.
84  template<typename Action>
85  auto adaptReturn(Action action) {
86  using ResultType = std::invoke_result_t<Action, std::string&, std::string_view, Stat&>;
87  if constexpr (std::is_same_v<ResultType, void>) {
88  return [=](auto&&... params) {
89  action(std::forward<decltype(params)>(params)...);
90  return true; // continue directory-traversal
91  };
92  } else {
93  return action;
94  }
95  }
96 
97  template<typename FileAction, typename DirAction>
98  bool foreach_dirent(std::string& path, FileAction fileAction, DirAction dirAction) {
99  auto [invokeFile, statFile] = adaptParams(fileAction);
100  auto [invokeDir, statDir ] = adaptParams(dirAction);
101  auto invokeFileAction = adaptReturn(invokeFile);
102  auto invokeDirAction = adaptReturn(invokeDir);
103  bool needStat = statFile || statDir;
104 
105  ReadDir dir(path);
106  if (!path.empty() && (path.back() != '/')) path += '/';
107  auto origLen = path.size();
108  while (dirent* d = dir.getEntry()) {
109  std::string_view f(d->d_name);
110  if (f == one_of(".", "..")) continue;
111  path += f;
112  auto file = std::string_view(path).substr(origLen);
113 
114  // When the action is not interested in 'Stat' and on operation systems
115  // that support it: avoid doing an extra 'stat()' system call.
116  auto type = needStat ? static_cast<unsigned char>(DT_UNKNOWN) : d->d_type;
117  Stat st;
118  if (type == DT_REG) {
119  if (!invokeFileAction(path, file, st)) {
120  return false; // aborted
121  }
122  } else if (type == DT_DIR) {
123  if (!invokeDirAction(path, file, st)) {
124  return false;
125  }
126  } else {
127  if (getStat(path, st)) {
128  if (isRegularFile(st)) {
129  if (!invokeFileAction(path, file, st)) {
130  return false;
131  }
132  } else if (isDirectory(st)) {
133  if (!invokeDirAction(path, file, st)) {
134  return false;
135  }
136  }
137  }
138  }
139 
140  path.resize(origLen);
141  }
142  path.pop_back();
143 
144  return true; // finished normally
145  }
146  }
147 
148  template<typename FileAction>
149  bool foreach_file(std::string path, FileAction fileAction)
150  {
151  auto dirAction = [&](const std::string& /*dirPath*/) { /*nothing*/ };
152  return detail::foreach_dirent(path, fileAction, dirAction);
153  }
154 
155  template<typename FileAction, typename DirAction>
156  bool foreach_file_and_directory(std::string path, FileAction fileAction, DirAction dirAction)
157  {
158  return detail::foreach_dirent(path, fileAction, dirAction);
159  }
160 
161  template<typename FileAction>
162  bool foreach_file_recursive(std::string path, FileAction fileAction)
163  {
164  std::function<bool(std::string&)> dirAction;
165  dirAction = [&](std::string& dirPath) {
166  return detail::foreach_dirent(dirPath, fileAction, dirAction);
167  };
168  return dirAction(path);
169  }
170 
171 } // namespace openmsx
172 
173 #endif
one_of.hh
openmsx::detail::foreach_dirent
bool foreach_dirent(std::string &path, FileAction fileAction, DirAction dirAction)
Definition: foreach_file.hh:98
openmsx::ReadDir
Simple wrapper around opendir() / readdir() / closedir() functions.
Definition: ReadDir.hh:16
openmsx::FileOperations::getStat
bool getStat(const std::string &filename, Stat &st)
Call stat() and return the stat structure.
Definition: FileOperations.cc:626
openmsx::FileOperations::Stat
struct stat Stat
Definition: FileOperations.hh:218
openmsx::FileOperations::isRegularFile
bool isRegularFile(const Stat &st)
Definition: FileOperations.cc:644
detail
Definition: join.hh:10
openmsx::ReadDir::getEntry
struct dirent * getEntry()
Get directory entry for next file.
Definition: ReadDir.cc:17
ReadDir.hh
one_of
Definition: one_of.hh:7
openmsx::FileOperations::isDirectory
bool isDirectory(const Stat &st)
Definition: FileOperations.cc:654
FileOperations.hh
StringOp.hh
openmsx::foreach_file_and_directory
bool foreach_file_and_directory(std::string path, FileAction fileAction, DirAction dirAction)
Definition: foreach_file.hh:156
openmsx::foreach_file_recursive
bool foreach_file_recursive(std::string path, FileAction fileAction)
Definition: foreach_file.hh:162
openmsx::detail::adaptReturn
auto adaptReturn(Action action)
Definition: foreach_file.hh:85
openmsx::detail::adaptParams
auto adaptParams(Action action)
Definition: foreach_file.hh:61
openmsx::foreach_file
bool foreach_file(std::string path, FileAction fileAction)
Definition: foreach_file.hh:149
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5