228 lines
6.3 KiB
C++
228 lines
6.3 KiB
C++
/*
|
|
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura, Gabriel Ebner
|
|
*/
|
|
#include "util/path.h"
|
|
#if defined(LEAN_WINDOWS) && !defined(LEAN_CYGWIN)
|
|
#include <windows.h>
|
|
#endif
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include "util/exception.h"
|
|
#include "util/sstream.h"
|
|
#include "util/optional.h"
|
|
|
|
namespace lean {
|
|
file_not_found_exception::file_not_found_exception(std::string const & fname):
|
|
exception(sstream() << "file '" << fname << "' not found"),
|
|
m_fname(fname) {}
|
|
|
|
#if defined(LEAN_EMSCRIPTEN)
|
|
// emscripten version
|
|
static char g_path_sep = ':';
|
|
static constexpr char g_sep = '/';
|
|
static char g_bad_sep = '\\';
|
|
bool is_path_sep(char c) { return c == g_path_sep; }
|
|
#elif defined(LEAN_WINDOWS) && !defined(LEAN_CYGWIN)
|
|
// Windows version
|
|
static char g_path_sep = ';';
|
|
static constexpr char g_sep = '\\';
|
|
static char g_bad_sep = '/';
|
|
std::string get_exe_location() {
|
|
HMODULE hModule = GetModuleHandleW(NULL);
|
|
WCHAR path[MAX_PATH];
|
|
GetModuleFileNameW(hModule, path, MAX_PATH);
|
|
std::wstring pathstr(path);
|
|
return std::string(pathstr.begin(), pathstr.end());
|
|
}
|
|
bool is_path_sep(char c) { return c == g_path_sep; }
|
|
#elif defined(__APPLE__)
|
|
// OSX version
|
|
#include <mach-o/dyld.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
static char g_path_sep = ':';
|
|
static constexpr char g_sep = '/';
|
|
static char g_bad_sep = '\\';
|
|
std::string get_exe_location() {
|
|
char buf1[PATH_MAX];
|
|
char buf2[PATH_MAX];
|
|
uint32_t bufsize = PATH_MAX;
|
|
if (_NSGetExecutablePath(buf1, &bufsize) != 0)
|
|
throw exception("failed to locate Lean executable location");
|
|
if (!realpath(buf1, buf2))
|
|
throw exception("failed to resolve symbolic links in " + std::string(buf1));
|
|
return std::string(buf2);
|
|
}
|
|
bool is_path_sep(char c) { return c == g_path_sep; }
|
|
#else
|
|
// Linux version
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <limits.h> // NOLINT
|
|
#include <stdio.h>
|
|
static char g_path_sep = ':';
|
|
static constexpr char g_sep = '/';
|
|
static char g_bad_sep = '\\';
|
|
std::string get_exe_location() {
|
|
char path[PATH_MAX];
|
|
char dest[PATH_MAX];
|
|
memset(dest, 0, PATH_MAX);
|
|
pid_t pid = getpid();
|
|
snprintf(path, PATH_MAX, "/proc/%d/exe", pid);
|
|
if (readlink(path, dest, PATH_MAX) == -1) {
|
|
throw exception("failed to locate Lean executable location");
|
|
} else {
|
|
return std::string(dest);
|
|
}
|
|
}
|
|
bool is_path_sep(char c) { return c == g_path_sep; }
|
|
#endif
|
|
|
|
#if defined(LEAN_WINDOWS)
|
|
std::string resolve(std::string const & rel_or_abs, std::string const & base) {
|
|
// TODO(gabriel): detect absolute pathnames
|
|
return base + g_sep + rel_or_abs;
|
|
}
|
|
#else
|
|
std::string resolve(std::string const & rel_or_abs, std::string const & base) {
|
|
if (!rel_or_abs.empty() && rel_or_abs[0] == g_sep) {
|
|
// absolute
|
|
return rel_or_abs;
|
|
} else {
|
|
// relative
|
|
return base + g_sep + rel_or_abs;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
std::string normalize_path(std::string f) {
|
|
for (auto & c : f) {
|
|
if (c == g_bad_sep)
|
|
c = g_sep;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
std::string get_path(std::string f) {
|
|
while (true) {
|
|
if (f.empty())
|
|
throw exception("failed to locate Lean executable location");
|
|
if (f.back() == g_sep) {
|
|
f.pop_back();
|
|
return f;
|
|
}
|
|
f.pop_back();
|
|
}
|
|
}
|
|
|
|
static char g_sep_str[2] = { g_sep, 0 };
|
|
|
|
char const * get_dir_sep() { return g_sep_str; }
|
|
char get_dir_sep_ch() { return g_sep; }
|
|
|
|
bool has_file_ext(std::string const & fname, char const * ext) {
|
|
unsigned ext_len = strlen(ext);
|
|
return fname.size() > ext_len && fname.substr(fname.size() - ext_len, ext_len) == ext;
|
|
}
|
|
|
|
void find_files(std::string const & base, char const * ext, std::vector<std::string> & files) {
|
|
for (auto & fn : read_dir(base)) {
|
|
if (auto i_d = is_dir(fn)) {
|
|
if (*i_d) {
|
|
find_files(fn, ext, files);
|
|
} else if (has_file_ext(fn, ext)) {
|
|
files.push_back(fn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string dirname(std::string const & fname) {
|
|
auto nfname = normalize_path(fname);
|
|
auto i = nfname.rfind(g_sep);
|
|
if (i == std::string::npos) {
|
|
return ".";
|
|
} else {
|
|
return nfname.substr(0, i);
|
|
}
|
|
}
|
|
|
|
std::string read_file(std::string const & fname, std::ios_base::openmode mode) {
|
|
std::ifstream in(fname, mode);
|
|
if (!in.good()) throw file_not_found_exception(fname);
|
|
std::stringstream buf;
|
|
buf << in.rdbuf();
|
|
return buf.str();
|
|
}
|
|
|
|
time_t get_mtime(std::string const &fname) {
|
|
struct stat st;
|
|
if (stat(fname.c_str(), &st) != 0)
|
|
return -1;
|
|
return st.st_mtime;
|
|
}
|
|
|
|
optional<bool> is_dir(std::string const & fn) {
|
|
struct stat st;
|
|
if (stat(fn.c_str(), &st) == 0)
|
|
return optional<bool>(S_ISDIR(st.st_mode));
|
|
return optional<bool>();
|
|
}
|
|
|
|
bool is_directory(std::string const & fn) {
|
|
if (auto res = is_dir(fn)) {
|
|
return *res;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> read_dir(std::string const &dirname) {
|
|
auto dir = opendir(dirname.c_str());
|
|
if (!dir) throw exception(sstream() << "could not open directory " << dirname << ": " << std::strerror(errno));
|
|
|
|
std::vector<std::string> files;
|
|
while (auto ep = readdir(dir)) { // NOLINT
|
|
// ^^ disabling readdir_r lint because glibc recommends using readdir now.
|
|
|
|
std::string fn = ep->d_name;
|
|
if (fn == "." || fn == "..") continue;
|
|
files.push_back(dirname + get_dir_sep() + fn);
|
|
}
|
|
closedir(dir);
|
|
return files;
|
|
}
|
|
|
|
std::string lrealpath(std::string const & fname) {
|
|
#if defined(LEAN_EMSCRIPTEN)
|
|
return fname;
|
|
#elif defined(LEAN_WINDOWS) && !defined(LEAN_CYGWIN)
|
|
constexpr unsigned BufferSize = 8192;
|
|
char buffer[BufferSize];
|
|
DWORD retval = GetFullPathName(fname.c_str(), BufferSize, buffer, nullptr);
|
|
if (retval == 0 || retval > BufferSize) {
|
|
return fname;
|
|
} else {
|
|
return std::string(buffer);
|
|
}
|
|
#else
|
|
char * tmp = realpath(fname.c_str(), nullptr);
|
|
if (tmp) {
|
|
std::string r(tmp);
|
|
::free(tmp);
|
|
return r;
|
|
} else {
|
|
throw file_not_found_exception(fname);
|
|
}
|
|
#endif
|
|
}
|
|
}
|