souffle  2.0.2-371-g6315b36
FileUtil.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file FileUtil.h
12  *
13  * @brief Datalog project utilities
14  *
15  ***********************************************************************/
16 
17 #pragma once
18 
19 #include <climits>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <fstream>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 #include <sys/stat.h>
27 
28 #ifndef _WIN32
29 #include <unistd.h>
30 #else
31 #include <fcntl.h>
32 #include <io.h>
33 #include <stdlib.h>
34 #include <windows.h>
35 
36 // -------------------------------------------------------------------------------
37 // File Utils
38 // -------------------------------------------------------------------------------
39 
40 #define X_OK 1 /* execute permission - unsupported in windows*/
41 
42 #define PATH_MAX 260
43 
44 /**
45  * access and realpath are missing on windows, we use their windows equivalents
46  * as work-arounds.
47  */
48 #define access _access
49 inline char* realpath(const char* path, char* resolved_path) {
50  return _fullpath(resolved_path, path, PATH_MAX);
51 }
52 
53 /**
54  * Define an alias for the popen and pclose functions on windows
55  */
56 #define popen _popen
57 #define pclose _pclose
58 #endif
59 
60 namespace souffle {
61 
62 /**
63  * Check whether a file exists in the file system
64  */
65 inline bool existFile(const std::string& name) {
66  struct stat buffer = {};
67  if (stat(name.c_str(), &buffer) == 0) {
68  if ((buffer.st_mode & S_IFMT) != 0) {
69  return true;
70  }
71  }
72  return false;
73 }
74 
75 /**
76  * Check whether a directory exists in the file system
77  */
78 inline bool existDir(const std::string& name) {
79  struct stat buffer = {};
80  if (stat(name.c_str(), &buffer) == 0) {
81  if ((buffer.st_mode & S_IFDIR) != 0) {
82  return true;
83  }
84  }
85  return false;
86 }
87 
88 /**
89  * Check whether a given file exists and it is an executable
90  */
91 inline bool isExecutable(const std::string& name) {
92  return existFile(name) && (access(name.c_str(), X_OK) == 0);
93 }
94 
95 /**
96  * Simple implementation of a which tool
97  */
98 inline std::string which(const std::string& name) {
99  // Check if name has path components in it and if so return it immediately
100  if (name.find('/') != std::string::npos) {
101  return name;
102  }
103  // Get PATH from environment, if it exists.
104  const char* syspath = ::getenv("PATH");
105  if (syspath == nullptr) {
106  return "";
107  }
108  char buf[PATH_MAX];
109  std::stringstream sstr;
110  sstr << syspath;
111  std::string sub;
112 
113  // Check for existence of a binary called 'name' in PATH
114  while (std::getline(sstr, sub, ':')) {
115  std::string path = sub + "/" + name;
116  if ((::realpath(path.c_str(), buf) != nullptr) && isExecutable(path) && !existDir(path)) {
117  return buf;
118  }
119  }
120  return "";
121 }
122 
123 /**
124  * C++-style dirname
125  */
126 inline std::string dirName(const std::string& name) {
127  if (name.empty()) {
128  return ".";
129  }
130  size_t lastNotSlash = name.find_last_not_of('/');
131  // All '/'
132  if (lastNotSlash == std::string::npos) {
133  return "/";
134  }
135  size_t leadingSlash = name.find_last_of('/', lastNotSlash);
136  // No '/'
137  if (leadingSlash == std::string::npos) {
138  return ".";
139  }
140  // dirname is '/'
141  if (leadingSlash == 0) {
142  return "/";
143  }
144  return name.substr(0, leadingSlash);
145 }
146 
147 /**
148  * C++-style realpath
149  */
150 inline std::string absPath(const std::string& path) {
151  char buf[PATH_MAX];
152  char* res = realpath(path.c_str(), buf);
153  return (res == nullptr) ? "" : std::string(buf);
154 }
155 
156 /**
157  * Join two paths together; note that this does not resolve overlaps or relative paths.
158  */
159 inline std::string pathJoin(const std::string& first, const std::string& second) {
160  unsigned firstPos = static_cast<unsigned>(first.size()) - 1;
161  while (first.at(firstPos) == '/') {
162  firstPos--;
163  }
164  unsigned secondPos = 0;
165  while (second.at(secondPos) == '/') {
166  secondPos++;
167  }
168  return first.substr(0, firstPos + 1) + '/' + second.substr(secondPos);
169 }
170 
171 /*
172  * Find out if an executable given by @p tool exists in the path given @p path
173  * relative to the directory given by @ base. A path here refers a
174  * colon-separated list of directories.
175  */
176 inline std::string findTool(const std::string& tool, const std::string& base, const std::string& path) {
177  std::string dir = dirName(base);
178  std::stringstream sstr(path);
179  std::string sub;
180 
181  while (std::getline(sstr, sub, ':')) {
182  std::string subpath = dir + "/" + sub + '/' + tool;
183  if (isExecutable(subpath)) {
184  return absPath(subpath);
185  }
186  }
187  return "";
188 }
189 
190 /*
191  * Get the basename of a fully qualified filename
192  */
193 inline std::string baseName(const std::string& filename) {
194  if (filename.empty()) {
195  return ".";
196  }
197 
198  size_t lastNotSlash = filename.find_last_not_of('/');
199  if (lastNotSlash == std::string::npos) {
200  return "/";
201  }
202 
203  size_t lastSlashBeforeBasename = filename.find_last_of('/', lastNotSlash - 1);
204  if (lastSlashBeforeBasename == std::string::npos) {
205  lastSlashBeforeBasename = static_cast<size_t>(-1);
206  }
207  return filename.substr(lastSlashBeforeBasename + 1, lastNotSlash - lastSlashBeforeBasename);
208 }
209 
210 /**
211  * File name, with extension removed.
212  */
213 inline std::string simpleName(const std::string& path) {
214  std::string name = baseName(path);
215  const size_t lastDot = name.find_last_of('.');
216  // file has no extension
217  if (lastDot == std::string::npos) {
218  return name;
219  }
220  const size_t lastSlash = name.find_last_of('/');
221  // last slash occurs after last dot, so no extension
222  if (lastSlash != std::string::npos && lastSlash > lastDot) {
223  return name;
224  }
225  // last dot after last slash, or no slash
226  return name.substr(0, lastDot);
227 }
228 
229 /**
230  * File extension, with all else removed.
231  */
232 inline std::string fileExtension(const std::string& path) {
233  std::string name = path;
234  const size_t lastDot = name.find_last_of('.');
235  // file has no extension
236  if (lastDot == std::string::npos) {
237  return std::string();
238  }
239  const size_t lastSlash = name.find_last_of('/');
240  // last slash occurs after last dot, so no extension
241  if (lastSlash != std::string::npos && lastSlash > lastDot) {
242  return std::string();
243  }
244  // last dot after last slash, or no slash
245  return name.substr(lastDot + 1);
246 }
247 
248 /**
249  * Generate temporary file.
250  */
251 inline std::string tempFile() {
252 #ifdef _WIN32
253  std::string templ;
254  std::FILE* f = nullptr;
255  while (f == nullptr) {
256  templ = std::tmpnam(nullptr);
257  f = fopen(templ.c_str(), "wx");
258  }
259  fclose(f);
260  return templ;
261 #else
262  char templ[40] = "./souffleXXXXXX";
263  close(mkstemp(templ));
264  return std::string(templ);
265 #endif
266 }
267 
268 inline std::stringstream execStdOut(char const* cmd) {
269  FILE* in = popen(cmd, "r");
270  std::stringstream data;
271  while (in != nullptr) {
272  int c = fgetc(in);
273  if (feof(in) != 0) {
274  break;
275  }
276  data << static_cast<char>(c);
277  }
278  pclose(in);
279  return data;
280 }
281 
282 inline std::stringstream execStdOut(std::string const& cmd) {
283  return execStdOut(cmd.c_str());
284 }
285 
286 class TempFileStream : public std::fstream {
287  std::string fileName;
288 
289 public:
290  TempFileStream(std::string fileName = tempFile())
291  : std::fstream(fileName), fileName(std::move(fileName)) {}
292  ~TempFileStream() override {
293  close();
294  remove(fileName.c_str());
295  }
296 
297  std::string const& getFileName() const {
298  return fileName;
299  }
300 };
301 
302 } // namespace souffle
souffle::baseName
std::string baseName(const std::string &filename)
Definition: FileUtil.h:199
souffle::tempFile
std::string tempFile()
Generate temporary file.
Definition: FileUtil.h:257
souffle::simpleName
std::string simpleName(const std::string &path)
File name, with extension removed.
Definition: FileUtil.h:219
souffle::existFile
bool existFile(const std::string &name)
Check whether a file exists in the file system.
Definition: FileUtil.h:71
souffle::execStdOut
std::stringstream execStdOut(char const *cmd)
Definition: FileUtil.h:274
souffle::ast::analysis::sub
std::shared_ptr< Constraint< Var > > sub(const Var &a, const Var &b, const std::string &symbol="⊑")
A generic factory for constraints of the form.
Definition: ConstraintSystem.h:228
souffle::TempFileStream::getFileName
std::string const & getFileName() const
Definition: FileUtil.h:303
souffle::dirName
std::string dirName(const std::string &name)
C++-style dirname.
Definition: FileUtil.h:132
base
T & base
Definition: Reader.h:60
souffle::fileExtension
std::string fileExtension(const std::string &path)
File extension, with all else removed.
Definition: FileUtil.h:238
IO.h
souffle::existDir
bool existDir(const std::string &name)
Check whether a directory exists in the file system.
Definition: FileUtil.h:84
souffle::isExecutable
bool isExecutable(const std::string &name)
Check whether a given file exists and it is an executable.
Definition: FileUtil.h:97
souffle::TempFileStream::~TempFileStream
~TempFileStream() override
Definition: FileUtil.h:298
souffle::TempFileStream::TempFileStream
TempFileStream(std::string fileName=tempFile())
Definition: FileUtil.h:296
souffle::findTool
std::string findTool(const std::string &tool, const std::string &base, const std::string &path)
Definition: FileUtil.h:182
souffle::which
std::string which(const std::string &name)
Simple implementation of a which tool.
Definition: FileUtil.h:104
souffle::pathJoin
std::string pathJoin(const std::string &first, const std::string &second)
Join two paths together; note that this does not resolve overlaps or relative paths.
Definition: FileUtil.h:165
souffle::absPath
std::string absPath(const std::string &path)
C++-style realpath.
Definition: FileUtil.h:156
std
Definition: Brie.h:3053
souffle
Definition: AggregateOp.h:25
souffle::TempFileStream::fileName
std::string fileName
Definition: FileUtil.h:293
TCB_SPAN_NAMESPACE_NAME::detail::data
constexpr auto data(C &c) -> decltype(c.data())
Definition: span.h:210