in Source/kwsys/SystemTools.cxx [2972:4786]
bool SystemTools::FileIsDirectory(const std::string& inName)
{
if (inName.empty()) {
return false;
}
size_t length = inName.size();
const char* name = inName.c_str();
// Remove any trailing slash from the name except in a root component.
char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
std::string string_buffer;
size_t last = length - 1;
if (last > 0 && (name[last] == '/' || name[last] == '\\') &&
strcmp(name, "/") != 0 && name[last - 1] != ':') {
if (last < sizeof(local_buffer)) {
memcpy(local_buffer, name, last);
local_buffer[last] = '\0';
name = local_buffer;
} else {
string_buffer.append(name, last);
name = string_buffer.c_str();
}
}
// Now check the file node type.
#if defined(_WIN32)
DWORD attr =
GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
if (attr != INVALID_FILE_ATTRIBUTES) {
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else
struct stat fs;
if (stat(name, &fs) == 0) {
return S_ISDIR(fs.st_mode);
#endif
} else {
return false;
}
}
bool SystemTools::FileIsExecutable(const std::string& name)
{
#if defined(_WIN32)
return SystemTools::FileExists(name, true);
#else
return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
#endif
}
bool SystemTools::FileIsSymlink(const std::string& name)
{
#if defined(_WIN32)
std::wstring path = Encoding::ToWindowsExtendedPath(name);
DWORD attr = GetFileAttributesW(path.c_str());
if (attr != INVALID_FILE_ATTRIBUTES) {
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
// FILE_ATTRIBUTE_REPARSE_POINT means:
// * a file or directory that has an associated reparse point, or
// * a file that is a symbolic link.
HANDLE hFile = CreateFileW(
path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned = 0;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
nullptr)) {
CloseHandle(hFile);
// Since FILE_ATTRIBUTE_REPARSE_POINT is set this file must be
// a symbolic link if it is not a reparse point.
return GetLastError() == ERROR_NOT_A_REPARSE_POINT;
}
CloseHandle(hFile);
ULONG reparseTag =
reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0])->ReparseTag;
return (reparseTag == IO_REPARSE_TAG_SYMLINK) ||
(reparseTag == IO_REPARSE_TAG_MOUNT_POINT);
}
return false;
} else {
return false;
}
#else
struct stat fs;
if (lstat(name.c_str(), &fs) == 0) {
return S_ISLNK(fs.st_mode);
} else {
return false;
}
#endif
}
bool SystemTools::FileIsFIFO(const std::string& name)
{
#if defined(_WIN32)
HANDLE hFile =
CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
const DWORD type = GetFileType(hFile);
CloseHandle(hFile);
return type == FILE_TYPE_PIPE;
#else
struct stat fs;
if (lstat(name.c_str(), &fs) == 0) {
return S_ISFIFO(fs.st_mode);
} else {
return false;
}
#endif
}
Status SystemTools::CreateSymlink(std::string const& origName,
std::string const& newName)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
DWORD flags;
if (FileIsDirectory(origName)) {
flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
} else {
flags = 0;
}
std::wstring origPath = Encoding::ToWindowsExtendedPath(origName);
std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
Status status;
if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(),
flags |
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
status = Status::Windows_GetLastError();
}
// Older Windows versions do not understand
// SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
if (status.GetWindows() == ERROR_INVALID_PARAMETER) {
status = Status::Success();
if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(), flags)) {
status = Status::Windows_GetLastError();
}
}
return status;
#else
if (symlink(origName.c_str(), newName.c_str()) < 0) {
return Status::POSIX_errno();
}
return Status::Success();
#endif
}
Status SystemTools::ReadSymlink(std::string const& newName,
std::string& origName)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
// FILE_ATTRIBUTE_REPARSE_POINT means:
// * a file or directory that has an associated reparse point, or
// * a file that is a symbolic link.
HANDLE hFile = CreateFileW(
newPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return Status::Windows_GetLastError();
}
byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned = 0;
Status status;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
nullptr)) {
status = Status::Windows_GetLastError();
}
CloseHandle(hFile);
if (!status.IsSuccess()) {
return status;
}
PREPARSE_DATA_BUFFER data =
reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]);
USHORT substituteNameLength;
PCWSTR substituteNameData;
if (data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
substituteNameLength =
data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
substituteNameData = data->SymbolicLinkReparseBuffer.PathBuffer +
data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
} else if (data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
substituteNameLength =
data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
substituteNameData = data->MountPointReparseBuffer.PathBuffer +
data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
} else {
return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
}
std::wstring substituteName(substituteNameData, substituteNameLength);
origName = Encoding::ToNarrow(substituteName);
#else
char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
int count = static_cast<int>(
readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
if (count < 0) {
return Status::POSIX_errno();
}
// Add null-terminator.
buf[count] = 0;
origName = buf;
#endif
return Status::Success();
}
Status SystemTools::ChangeDirectory(std::string const& dir)
{
if (Chdir(dir) < 0) {
return Status::POSIX_errno();
}
return Status::Success();
}
std::string SystemTools::GetCurrentWorkingDirectory()
{
char buf[2048];
const char* cwd = Getcwd(buf, 2048);
std::string path;
if (cwd) {
path = cwd;
SystemTools::ConvertToUnixSlashes(path);
}
return path;
}
std::string SystemTools::GetProgramPath(const std::string& in_name)
{
std::string dir, file;
SystemTools::SplitProgramPath(in_name, dir, file);
return dir;
}
bool SystemTools::SplitProgramPath(const std::string& in_name,
std::string& dir, std::string& file, bool)
{
dir = in_name;
file.clear();
SystemTools::ConvertToUnixSlashes(dir);
if (!SystemTools::FileIsDirectory(dir)) {
std::string::size_type slashPos = dir.rfind('/');
if (slashPos != std::string::npos) {
file = dir.substr(slashPos + 1);
dir.resize(slashPos);
} else {
file = dir;
dir.clear();
}
}
if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) {
std::string oldDir = in_name;
SystemTools::ConvertToUnixSlashes(oldDir);
dir = in_name;
return false;
}
return true;
}
bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut,
std::string& errorMsg, const char* exeName,
const char* buildDir,
const char* installPrefix)
{
std::vector<std::string> failures;
std::string self = argv0 ? argv0 : "";
failures.push_back(self);
SystemTools::ConvertToUnixSlashes(self);
self = SystemTools::FindProgram(self);
if (!SystemTools::FileIsExecutable(self)) {
if (buildDir) {
std::string intdir = ".";
#ifdef CMAKE_INTDIR
intdir = CMAKE_INTDIR;
#endif
self = buildDir;
self += "/bin/";
self += intdir;
self += "/";
self += exeName;
self += SystemTools::GetExecutableExtension();
}
}
if (installPrefix) {
if (!SystemTools::FileIsExecutable(self)) {
failures.push_back(self);
self = installPrefix;
self += "/bin/";
self += exeName;
}
}
if (!SystemTools::FileIsExecutable(self)) {
failures.push_back(self);
std::ostringstream msg;
msg << "Can not find the command line program ";
if (exeName) {
msg << exeName;
}
msg << "\n";
if (argv0) {
msg << " argv[0] = \"" << argv0 << "\"\n";
}
msg << " Attempted paths:\n";
for (std::string const& ff : failures) {
msg << " \"" << ff << "\"\n";
}
errorMsg = msg.str();
return false;
}
pathOut = self;
return true;
}
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
void SystemTools::AddTranslationPath(const std::string& a,
const std::string& b)
{
std::string path_a = a;
std::string path_b = b;
SystemTools::ConvertToUnixSlashes(path_a);
SystemTools::ConvertToUnixSlashes(path_b);
// First check this is a directory path, since we don't want the table to
// grow too fat
if (SystemTools::FileIsDirectory(path_a)) {
// Make sure the path is a full path and does not contain no '..'
// Ken--the following code is incorrect. .. can be in a valid path
// for example /home/martink/MyHubba...Hubba/Src
if (SystemTools::FileIsFullPath(path_b) &&
path_b.find("..") == std::string::npos) {
// Before inserting make sure path ends with '/'
if (!path_a.empty() && path_a.back() != '/') {
path_a += '/';
}
if (!path_b.empty() && path_b.back() != '/') {
path_b += '/';
}
if (!(path_a == path_b)) {
SystemToolsStatics->TranslationMap.insert(
SystemToolsStatic::StringMap::value_type(std::move(path_a),
std::move(path_b)));
}
}
}
}
void SystemTools::AddKeepPath(const std::string& dir)
{
std::string cdir;
Realpath(SystemTools::CollapseFullPath(dir), cdir);
SystemTools::AddTranslationPath(cdir, dir);
}
void SystemTools::CheckTranslationPath(std::string& path)
{
// Do not translate paths that are too short to have meaningful
// translations.
if (path.size() < 2) {
return;
}
// Always add a trailing slash before translation. It does not
// matter if this adds an extra slash, but we do not want to
// translate part of a directory (like the foo part of foo-dir).
path += '/';
// In case a file was specified we still have to go through this:
// Now convert any path found in the table back to the one desired:
for (auto const& pair : SystemToolsStatics->TranslationMap) {
// We need to check of the path is a substring of the other path
if (path.compare(0, pair.first.size(), pair.first) == 0) {
path = path.replace(0, pair.first.size(), pair.second);
}
}
// Remove the trailing slash we added before.
path.pop_back();
}
#endif
static void SystemToolsAppendComponents(
std::vector<std::string>& out_components,
std::vector<std::string>::iterator first,
std::vector<std::string>::iterator last)
{
static const std::string up = "..";
static const std::string cur = ".";
for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
if (*i == up) {
// Remove the previous component if possible. Ignore ../ components
// that try to go above the root. Keep ../ components if they are
// at the beginning of a relative path (base path is relative).
if (out_components.size() > 1 && out_components.back() != up) {
out_components.resize(out_components.size() - 1);
} else if (!out_components.empty() && out_components[0].empty()) {
out_components.emplace_back(std::move(*i));
}
} else if (!i->empty() && *i != cur) {
out_components.emplace_back(std::move(*i));
}
}
}
namespace {
std::string CollapseFullPathImpl(std::string const& in_path,
std::string const* in_base)
{
// Collect the output path components.
std::vector<std::string> out_components;
// Split the input path components.
std::vector<std::string> path_components;
SystemTools::SplitPath(in_path, path_components);
out_components.reserve(path_components.size());
// If the input path is relative, start with a base path.
if (path_components[0].empty()) {
std::vector<std::string> base_components;
if (in_base) {
// Use the given base path.
SystemTools::SplitPath(*in_base, base_components);
} else {
// Use the current working directory as a base path.
std::string cwd = SystemTools::GetCurrentWorkingDirectory();
SystemTools::SplitPath(cwd, base_components);
}
// Append base path components to the output path.
out_components.push_back(base_components[0]);
SystemToolsAppendComponents(out_components, base_components.begin() + 1,
base_components.end());
}
// Append input path components to the output path.
SystemToolsAppendComponents(out_components, path_components.begin(),
path_components.end());
// Transform the path back to a string.
std::string newPath = SystemTools::JoinPath(out_components);
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Update the translation table with this potentially new path. I am not
// sure why this line is here, it seems really questionable, but yet I
// would put good money that if I remove it something will break, basically
// from what I can see it created a mapping from the collapsed path, to be
// replaced by the input path, which almost completely does the opposite of
// this function, the only thing preventing this from happening a lot is
// that if the in_path has a .. in it, then it is not added to the
// translation table. So for most calls this either does nothing due to the
// .. or it adds a translation between identical paths as nothing was
// collapsed, so I am going to try to comment it out, and see what hits the
// fan, hopefully quickly.
// Commented out line below:
// SystemTools::AddTranslationPath(newPath, in_path);
SystemTools::CheckTranslationPath(newPath);
#endif
#ifdef _WIN32
newPath = SystemToolsStatics->GetActualCaseForPathCached(newPath);
SystemTools::ConvertToUnixSlashes(newPath);
#endif
// Return the reconstructed path.
return newPath;
}
}
std::string SystemTools::CollapseFullPath(std::string const& in_path)
{
return CollapseFullPathImpl(in_path, nullptr);
}
std::string SystemTools::CollapseFullPath(std::string const& in_path,
const char* in_base)
{
if (!in_base) {
return CollapseFullPathImpl(in_path, nullptr);
}
std::string tmp_base = in_base;
return CollapseFullPathImpl(in_path, &tmp_base);
}
std::string SystemTools::CollapseFullPath(std::string const& in_path,
std::string const& in_base)
{
return CollapseFullPathImpl(in_path, &in_base);
}
// compute the relative path from here to there
std::string SystemTools::RelativePath(const std::string& local,
const std::string& remote)
{
if (!SystemTools::FileIsFullPath(local)) {
return "";
}
if (!SystemTools::FileIsFullPath(remote)) {
return "";
}
std::string l = SystemTools::CollapseFullPath(local);
std::string r = SystemTools::CollapseFullPath(remote);
// split up both paths into arrays of strings using / as a separator
std::vector<std::string> localSplit = SystemTools::SplitString(l, '/', true);
std::vector<std::string> remoteSplit =
SystemTools::SplitString(r, '/', true);
std::vector<std::string>
commonPath; // store shared parts of path in this array
std::vector<std::string> finalPath; // store the final relative path here
// count up how many matching directory names there are from the start
unsigned int sameCount = 0;
while (((sameCount <= (localSplit.size() - 1)) &&
(sameCount <= (remoteSplit.size() - 1))) &&
// for Windows and Apple do a case insensitive string compare
#if defined(_WIN32) || defined(__APPLE__)
SystemTools::Strucmp(localSplit[sameCount].c_str(),
remoteSplit[sameCount].c_str()) == 0
#else
localSplit[sameCount] == remoteSplit[sameCount]
#endif
) {
// put the common parts of the path into the commonPath array
commonPath.push_back(localSplit[sameCount]);
// erase the common parts of the path from the original path arrays
localSplit[sameCount] = "";
remoteSplit[sameCount] = "";
sameCount++;
}
// If there is nothing in common at all then just return the full
// path. This is the case only on windows when the paths have
// different drive letters. On unix two full paths always at least
// have the root "/" in common so we will return a relative path
// that passes through the root directory.
if (sameCount == 0) {
return remote;
}
// for each entry that is not common in the local path
// add a ../ to the finalpath array, this gets us out of the local
// path into the remote dir
for (std::string const& lp : localSplit) {
if (!lp.empty()) {
finalPath.emplace_back("../");
}
}
// for each entry that is not common in the remote path add it
// to the final path.
for (std::string const& rp : remoteSplit) {
if (!rp.empty()) {
finalPath.push_back(rp);
}
}
std::string relativePath; // result string
// now turn the array of directories into a unix path by puttint /
// between each entry that does not already have one
for (std::string const& fp : finalPath) {
if (!relativePath.empty() && relativePath.back() != '/') {
relativePath += '/';
}
relativePath += fp;
}
return relativePath;
}
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
#ifdef _WIN32
return SystemToolsStatic::GetCasePathName(p);
#else
return p;
#endif
}
const char* SystemTools::SplitPathRootComponent(const std::string& p,
std::string* root)
{
// Identify the root component.
const char* c = p.c_str();
if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) {
// Network path.
if (root) {
*root = "//";
}
c += 2;
} else if (c[0] == '/' || c[0] == '\\') {
// Unix path (or Windows path w/out drive letter).
if (root) {
*root = "/";
}
c += 1;
} else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) {
// Windows path.
if (root) {
(*root) = "_:/";
(*root)[0] = c[0];
}
c += 3;
} else if (c[0] && c[1] == ':') {
// Path relative to a windows drive working directory.
if (root) {
(*root) = "_:";
(*root)[0] = c[0];
}
c += 2;
} else if (c[0] == '~') {
// Home directory. The returned root should always have a
// trailing slash so that appending components as
// c[0]c[1]/c[2]/... works. The remaining path returned should
// skip the first slash if it exists:
//
// "~" : root = "~/" , return ""
// "~/ : root = "~/" , return ""
// "~/x : root = "~/" , return "x"
// "~u" : root = "~u/", return ""
// "~u/" : root = "~u/", return ""
// "~u/x" : root = "~u/", return "x"
size_t n = 1;
while (c[n] && c[n] != '/') {
++n;
}
if (root) {
root->assign(c, n);
*root += '/';
}
if (c[n] == '/') {
++n;
}
c += n;
} else {
// Relative path.
if (root) {
*root = "";
}
}
// Return the remaining path.
return c;
}
void SystemTools::SplitPath(const std::string& p,
std::vector<std::string>& components,
bool expand_home_dir)
{
const char* c;
components.clear();
// Identify the root component.
{
std::string root;
c = SystemTools::SplitPathRootComponent(p, &root);
// Expand home directory references if requested.
if (expand_home_dir && !root.empty() && root[0] == '~') {
std::string homedir;
root.resize(root.size() - 1);
if (root.size() == 1) {
#if defined(_WIN32) && !defined(__CYGWIN__)
if (!SystemTools::GetEnv("USERPROFILE", homedir))
#endif
SystemTools::GetEnv("HOME", homedir);
}
#ifdef HAVE_GETPWNAM
else if (passwd* pw = getpwnam(root.c_str() + 1)) {
if (pw->pw_dir) {
homedir = pw->pw_dir;
}
}
#endif
if (!homedir.empty() &&
(homedir.back() == '/' || homedir.back() == '\\')) {
homedir.resize(homedir.size() - 1);
}
SystemTools::SplitPath(homedir, components);
} else {
components.push_back(root);
}
}
// Parse the remaining components.
const char* first = c;
const char* last = first;
for (; *last; ++last) {
if (*last == '/' || *last == '\\') {
// End of a component. Save it.
components.emplace_back(first, last);
first = last + 1;
}
}
// Save the last component unless there were no components.
if (last != c) {
components.emplace_back(first, last);
}
}
std::string SystemTools::JoinPath(const std::vector<std::string>& components)
{
return SystemTools::JoinPath(components.begin(), components.end());
}
std::string SystemTools::JoinPath(
std::vector<std::string>::const_iterator first,
std::vector<std::string>::const_iterator last)
{
// Construct result in a single string.
std::string result;
size_t len = 0;
for (auto i = first; i != last; ++i) {
len += 1 + i->size();
}
result.reserve(len);
// The first two components do not add a slash.
if (first != last) {
result.append(*first++);
}
if (first != last) {
result.append(*first++);
}
// All remaining components are always separated with a slash.
while (first != last) {
result.push_back('/');
result.append((*first++));
}
// Return the concatenated result.
return result;
}
bool SystemTools::ComparePath(const std::string& c1, const std::string& c2)
{
#if defined(_WIN32) || defined(__APPLE__)
# ifdef _MSC_VER
return _stricmp(c1.c_str(), c2.c_str()) == 0;
# elif defined(__APPLE__) || defined(__GNUC__)
return strcasecmp(c1.c_str(), c2.c_str()) == 0;
# else
return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0;
# endif
#else
return c1 == c2;
#endif
}
bool SystemTools::Split(const std::string& str,
std::vector<std::string>& lines, char separator)
{
std::string data(str);
std::string::size_type lpos = 0;
while (lpos < data.length()) {
std::string::size_type rpos = data.find_first_of(separator, lpos);
if (rpos == std::string::npos) {
// String ends at end of string without a separator.
lines.push_back(data.substr(lpos));
return false;
} else {
// String ends in a separator, remove the character.
lines.push_back(data.substr(lpos, rpos - lpos));
}
lpos = rpos + 1;
}
return true;
}
bool SystemTools::Split(const std::string& str,
std::vector<std::string>& lines)
{
std::string data(str);
std::string::size_type lpos = 0;
while (lpos < data.length()) {
std::string::size_type rpos = data.find_first_of('\n', lpos);
if (rpos == std::string::npos) {
// Line ends at end of string without a newline.
lines.push_back(data.substr(lpos));
return false;
}
if ((rpos > lpos) && (data[rpos - 1] == '\r')) {
// Line ends in a "\r\n" pair, remove both characters.
lines.push_back(data.substr(lpos, (rpos - 1) - lpos));
} else {
// Line ends in a "\n", remove the character.
lines.push_back(data.substr(lpos, rpos - lpos));
}
lpos = rpos + 1;
}
return true;
}
/**
* Return path of a full filename (no trailing slashes).
* Warning: returned path is converted to Unix slashes format.
*/
std::string SystemTools::GetFilenamePath(const std::string& filename)
{
std::string fn = filename;
SystemTools::ConvertToUnixSlashes(fn);
std::string::size_type slash_pos = fn.rfind('/');
if (slash_pos == 0) {
return "/";
}
if (slash_pos == 2 && fn[1] == ':') {
// keep the / after a drive letter
fn.resize(3);
return fn;
}
if (slash_pos == std::string::npos) {
return "";
}
fn.resize(slash_pos);
return fn;
}
/**
* Return file name of a full filename (i.e. file name without path).
*/
std::string SystemTools::GetFilenameName(const std::string& filename)
{
#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
const char* separators = "/\\";
#else
char separators = '/';
#endif
std::string::size_type slash_pos = filename.find_last_of(separators);
if (slash_pos != std::string::npos) {
return filename.substr(slash_pos + 1);
} else {
return filename;
}
}
/**
* Return file extension of a full filename (dot included).
* Warning: this is the longest extension (for example: .tar.gz)
*/
std::string SystemTools::GetFilenameExtension(const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find('.');
if (dot_pos != std::string::npos) {
name.erase(0, dot_pos);
return name;
} else {
return "";
}
}
/**
* Return file extension of a full filename (dot included).
* Warning: this is the shortest extension (for example: .gz of .tar.gz)
*/
std::string SystemTools::GetFilenameLastExtension(const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.rfind('.');
if (dot_pos != std::string::npos) {
name.erase(0, dot_pos);
return name;
} else {
return "";
}
}
/**
* Return file name without extension of a full filename (i.e. without path).
* Warning: it considers the longest extension (for example: .tar.gz)
*/
std::string SystemTools::GetFilenameWithoutExtension(
const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find('.');
if (dot_pos != std::string::npos) {
name.resize(dot_pos);
}
return name;
}
/**
* Return file name without extension of a full filename (i.e. without path).
* Warning: it considers the last extension (for example: removes .gz
* from .tar.gz)
*/
std::string SystemTools::GetFilenameWithoutLastExtension(
const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.rfind('.');
if (dot_pos != std::string::npos) {
name.resize(dot_pos);
}
return name;
}
bool SystemTools::FileHasSignature(const char* filename, const char* signature,
long offset)
{
if (!filename || !signature) {
return false;
}
FILE* fp = Fopen(filename, "rb");
if (!fp) {
return false;
}
fseek(fp, offset, SEEK_SET);
bool res = false;
size_t signature_len = strlen(signature);
char* buffer = new char[signature_len];
if (fread(buffer, 1, signature_len, fp) == signature_len) {
res = (!strncmp(buffer, signature, signature_len) ? true : false);
}
delete[] buffer;
fclose(fp);
return res;
}
SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename,
unsigned long length,
double percent_bin)
{
if (!filename || percent_bin < 0) {
return SystemTools::FileTypeUnknown;
}
if (SystemTools::FileIsDirectory(filename)) {
return SystemTools::FileTypeUnknown;
}
FILE* fp = Fopen(filename, "rb");
if (!fp) {
return SystemTools::FileTypeUnknown;
}
// Allocate buffer and read bytes
auto* buffer = new unsigned char[length];
size_t read_length = fread(buffer, 1, length, fp);
fclose(fp);
if (read_length == 0) {
delete[] buffer;
return SystemTools::FileTypeUnknown;
}
// Loop over contents and count
size_t text_count = 0;
const unsigned char* ptr = buffer;
const unsigned char* buffer_end = buffer + read_length;
while (ptr != buffer_end) {
if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == '\n' || *ptr == '\r' ||
*ptr == '\t') {
text_count++;
}
ptr++;
}
delete[] buffer;
double current_percent_bin = (static_cast<double>(read_length - text_count) /
static_cast<double>(read_length));
if (current_percent_bin >= percent_bin) {
return SystemTools::FileTypeBinary;
}
return SystemTools::FileTypeText;
}
bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
std::string& filename_found,
int try_filename_dirs)
{
if (!filename || !dir) {
return false;
}
// Get the basename of 'filename'
std::string filename_base = SystemTools::GetFilenameName(filename);
// Check if 'dir' is really a directory
// If win32 and matches something like C:, accept it as a dir
std::string real_dir;
if (!SystemTools::FileIsDirectory(dir)) {
#if defined(_WIN32)
size_t dir_len = strlen(dir);
if (dir_len < 2 || dir[dir_len - 1] != ':') {
#endif
real_dir = SystemTools::GetFilenamePath(dir);
dir = real_dir.c_str();
#if defined(_WIN32)
}
#endif
}
// Try to find the file in 'dir'
bool res = false;
if (!filename_base.empty() && dir) {
size_t dir_len = strlen(dir);
int need_slash =
(dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\');
std::string temp = dir;
if (need_slash) {
temp += "/";
}
temp += filename_base;
if (SystemTools::FileExists(temp)) {
res = true;
filename_found = temp;
}
// If not found, we can try harder by appending part of the file to
// to the directory to look inside.
// Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then
// try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc.
else if (try_filename_dirs) {
std::string filename_dir(filename);
std::string filename_dir_base;
std::string filename_dir_bases;
do {
filename_dir = SystemTools::GetFilenamePath(filename_dir);
filename_dir_base = SystemTools::GetFilenameName(filename_dir);
#if defined(_WIN32)
if (filename_dir_base.empty() || filename_dir_base.back() == ':')
#else
if (filename_dir_base.empty())
#endif
{
break;
}
filename_dir_bases = filename_dir_base + "/" + filename_dir_bases;
temp = dir;
if (need_slash) {
temp += "/";
}
temp += filename_dir_bases;
res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(),
filename_found, 0);
} while (!res && !filename_dir_base.empty());
}
}
return res;
}
bool SystemTools::FileIsFullPath(const std::string& in_name)
{
return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(const char* in_name)
{
return SystemToolsStatic::FileIsFullPath(
in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
// On Windows, the name must be at least two characters long.
if (len < 2) {
return false;
}
if (in_name[1] == ':') {
return true;
}
if (in_name[0] == '\\') {
return true;
}
#else
// On UNIX, the name must be at least one character long.
if (len < 1) {
return false;
}
#endif
#if !defined(_WIN32)
if (in_name[0] == '~') {
return true;
}
#endif
// On UNIX, the name must begin in a '/'.
// On Windows, if the name begins in a '/', then it is a full
// network path.
if (in_name[0] == '/') {
return true;
}
return false;
}
Status SystemTools::GetShortPath(std::string const& path,
std::string& shortPath)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
std::string tempPath = path; // create a buffer
// if the path passed in has quotes around it, first remove the quotes
if (!path.empty() && path[0] == '"' && path.back() == '"') {
tempPath.resize(path.length() - 1);
tempPath.erase(0, 1);
}
std::wstring wtempPath = Encoding::ToWide(tempPath);
DWORD ret = GetShortPathNameW(wtempPath.c_str(), nullptr, 0);
std::vector<wchar_t> buffer(ret);
if (ret != 0) {
ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0],
static_cast<DWORD>(buffer.size()));
}
if (ret == 0) {
return Status::Windows_GetLastError();
} else {
shortPath = Encoding::ToNarrow(&buffer[0]);
return Status::Success();
}
#else
shortPath = path;
return Status::Success();
#endif
}
std::string SystemTools::GetCurrentDateTime(const char* format)
{
char buf[1024];
time_t t;
time(&t);
strftime(buf, sizeof(buf), format, localtime(&t));
return std::string(buf);
}
std::string SystemTools::MakeCidentifier(const std::string& s)
{
std::string str(s);
if (str.find_first_of("0123456789") == 0) {
str = "_" + str;
}
std::string permited_chars("_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789");
std::string::size_type pos = 0;
while ((pos = str.find_first_not_of(permited_chars, pos)) !=
std::string::npos) {
str[pos] = '_';
}
return str;
}
// Convenience function around std::getline which removes a trailing carriage
// return and can truncate the buffer as needed. Returns true
// if any data were read before the end-of-file was reached.
bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
bool* has_newline /* = 0 */,
long sizeLimit /* = -1 */)
{
// Start with an empty line.
line = "";
// Early short circuit return if stream is no good. Just return
// false and the empty line. (Probably means caller tried to
// create a file stream with a non-existent file name...)
//
if (!is) {
if (has_newline) {
*has_newline = false;
}
return false;
}
std::getline(is, line);
bool haveData = !line.empty() || !is.eof();
if (!line.empty()) {
// Avoid storing a carriage return character.
if (line.back() == '\r') {
line.resize(line.size() - 1);
}
// if we read too much then truncate the buffer
if (sizeLimit >= 0 && line.size() >= static_cast<size_t>(sizeLimit)) {
line.resize(sizeLimit);
}
}
// Return the results.
if (has_newline) {
*has_newline = !is.eof();
}
return haveData;
}
int SystemTools::GetTerminalWidth()
{
int width = -1;
#ifdef HAVE_TTY_INFO
struct winsize ws;
std::string columns; /* Unix98 environment variable */
if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0 && ws.ws_row > 0) {
width = ws.ws_col;
}
if (!isatty(STDOUT_FILENO)) {
width = -1;
}
if (SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) {
long t;
char* endptr;
t = strtol(columns.c_str(), &endptr, 0);
if (endptr && !*endptr && (t > 0) && (t < 1000)) {
width = static_cast<int>(t);
}
}
if (width < 9) {
width = -1;
}
#endif
return width;
}
Status SystemTools::GetPermissions(const char* file, mode_t& mode)
{
if (!file) {
return Status::POSIX(EINVAL);
}
return SystemTools::GetPermissions(std::string(file), mode);
}
Status SystemTools::GetPermissions(std::string const& file, mode_t& mode)
{
#if defined(_WIN32)
DWORD attr =
GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str());
if (attr == INVALID_FILE_ATTRIBUTES) {
return Status::Windows_GetLastError();
}
if ((attr & FILE_ATTRIBUTE_READONLY) != 0) {
mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
} else {
mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) |
(_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
} else {
mode |= S_IFREG;
}
size_t dotPos = file.rfind('.');
const char* ext = dotPos == std::string::npos ? 0 : (file.c_str() + dotPos);
if (ext &&
(Strucmp(ext, ".exe") == 0 || Strucmp(ext, ".com") == 0 ||
Strucmp(ext, ".cmd") == 0 || Strucmp(ext, ".bat") == 0)) {
mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
}
#else
struct stat st;
if (stat(file.c_str(), &st) < 0) {
return Status::POSIX_errno();
}
mode = st.st_mode;
#endif
return Status::Success();
}
Status SystemTools::SetPermissions(const char* file, mode_t mode,
bool honor_umask)
{
if (!file) {
return Status::POSIX(EINVAL);
}
return SystemTools::SetPermissions(std::string(file), mode, honor_umask);
}
Status SystemTools::SetPermissions(std::string const& file, mode_t mode,
bool honor_umask)
{
if (!SystemTools::PathExists(file)) {
return Status::POSIX(ENOENT);
}
if (honor_umask) {
mode_t currentMask = umask(0);
umask(currentMask);
mode &= ~currentMask;
}
#ifdef _WIN32
if (_wchmod(Encoding::ToWindowsExtendedPath(file).c_str(), mode) < 0)
#else
if (chmod(file.c_str(), mode) < 0)
#endif
{
return Status::POSIX_errno();
}
return Status::Success();
}
std::string SystemTools::GetParentDirectory(const std::string& fileOrDir)
{
return SystemTools::GetFilenamePath(fileOrDir);
}
bool SystemTools::IsSubDirectory(const std::string& cSubdir,
const std::string& cDir)
{
if (cDir.empty()) {
return false;
}
std::string subdir = cSubdir;
std::string dir = cDir;
SystemTools::ConvertToUnixSlashes(subdir);
SystemTools::ConvertToUnixSlashes(dir);
if (subdir.size() <= dir.size() || dir.empty()) {
return false;
}
bool isRootPath = dir.back() == '/'; // like "/" or "C:/"
size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size();
if (subdir[expectedSlashPosition] != '/') {
return false;
}
subdir.resize(dir.size());
return SystemTools::ComparePath(subdir, dir);
}
void SystemTools::Delay(unsigned int msec)
{
#ifdef _WIN32
Sleep(msec);
#else
// The sleep function gives 1 second resolution and the usleep
// function gives 1e-6 second resolution but on some platforms has a
// maximum sleep time of 1 second. This could be re-implemented to
// use select with masked signals or pselect to mask signals
// atomically. If select is given empty sets and zero as the max
// file descriptor but a non-zero timeout it can be used to block
// for a precise amount of time.
if (msec >= 1000) {
sleep(msec / 1000);
usleep((msec % 1000) * 1000);
} else {
usleep(msec * 1000);
}
#endif
}
std::string SystemTools::GetOperatingSystemNameAndVersion()
{
std::string res;
#ifdef _WIN32
char buffer[256];
OSVERSIONINFOEXA osvi;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
# elif defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
# endif
bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi);
if (!bOsVersionInfoEx) {
return "";
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# ifdef __clang__
# pragma clang diagnostic pop
# else
# pragma warning(pop)
# endif
# endif
switch (osvi.dwPlatformId) {
// Test for the Windows NT product family.
case VER_PLATFORM_WIN32_NT:
// Test for the specific product family.
if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 10";
} else {
res += "Microsoft Windows Server 2016 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 8.1";
} else {
res += "Microsoft Windows Server 2012 R2 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 8";
} else {
res += "Microsoft Windows Server 2012 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 7";
} else {
res += "Microsoft Windows Server 2008 R2 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows Vista";
} else {
res += "Microsoft Windows Server 2008 family";
}
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
res += "Microsoft Windows Server 2003 family";
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
res += "Microsoft Windows XP";
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
res += "Microsoft Windows 2000";
}
if (osvi.dwMajorVersion <= 4) {
res += "Microsoft Windows NT";
}
// Test for specific product on Windows NT 4.0 SP6 and later.
if (bOsVersionInfoEx) {
// Test for the workstation type.
if (osvi.wProductType == VER_NT_WORKSTATION) {
if (osvi.dwMajorVersion == 4) {
res += " Workstation 4.0";
} else if (osvi.dwMajorVersion == 5) {
if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
res += " Home Edition";
} else {
res += " Professional";
}
}
}
// Test for the server type.
else if (osvi.wProductType == VER_NT_SERVER) {
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
res += " Datacenter Edition";
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Enterprise Edition";
} else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
res += " Web Edition";
} else {
res += " Standard Edition";
}
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
res += " Datacenter Server";
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Advanced Server";
} else {
res += " Server";
}
}
else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0
{
if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Server 4.0, Enterprise Edition";
} else {
res += " Server 4.0";
}
}
}
}
// Test for specific product on Windows NT 4.0 SP5 and earlier
else {
HKEY hKey;
# define BUFSIZE 80
wchar_t szProductType[BUFSIZE];
DWORD dwBufLen = BUFSIZE;
LONG lRet;
lRet =
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
0, KEY_QUERY_VALUE, &hKey);
if (lRet != ERROR_SUCCESS) {
return "";
}
lRet = RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr,
(LPBYTE)szProductType, &dwBufLen);
if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) {
return "";
}
RegCloseKey(hKey);
if (lstrcmpiW(L"WINNT", szProductType) == 0) {
res += " Workstation";
}
if (lstrcmpiW(L"LANMANNT", szProductType) == 0) {
res += " Server";
}
if (lstrcmpiW(L"SERVERNT", szProductType) == 0) {
res += " Advanced Server";
}
res += " ";
sprintf(buffer, "%ld", osvi.dwMajorVersion);
res += buffer;
res += ".";
sprintf(buffer, "%ld", osvi.dwMinorVersion);
res += buffer;
}
// Display service pack (if any) and build number.
if (osvi.dwMajorVersion == 4 &&
lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) {
HKEY hKey;
LONG lRet;
// Test for SP6 versus SP6a.
lRet = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
0, KEY_QUERY_VALUE, &hKey);
if (lRet == ERROR_SUCCESS) {
res += " Service Pack 6a (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
} else // Windows NT 4.0 prior to SP6a
{
res += " ";
res += osvi.szCSDVersion;
res += " (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
}
RegCloseKey(hKey);
} else // Windows NT 3.51 and earlier or Windows 2000 and later
{
res += " ";
res += osvi.szCSDVersion;
res += " (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
}
break;
// Test for the Windows 95 product family.
case VER_PLATFORM_WIN32_WINDOWS:
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
res += "Microsoft Windows 95";
if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
res += " OSR2";
}
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
res += "Microsoft Windows 98";
if (osvi.szCSDVersion[1] == 'A') {
res += " SE";
}
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
res += "Microsoft Windows Millennium Edition";
}
break;
case VER_PLATFORM_WIN32s:
res += "Microsoft Win32s";
break;
}
#endif
return res;
}
bool SystemTools::ParseURLProtocol(const std::string& URL,
std::string& protocol,
std::string& dataglom, bool decode)
{
// match 0 entire url
// match 1 protocol
// match 2 dataglom following protocol://
kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX);
if (!urlRe.find(URL))
return false;
protocol = urlRe.match(1);
dataglom = urlRe.match(2);
if (decode) {
dataglom = DecodeURL(dataglom);
}
return true;
}
bool SystemTools::ParseURL(const std::string& URL, std::string& protocol,
std::string& username, std::string& password,
std::string& hostname, std::string& dataport,
std::string& database, bool decode)
{
kwsys::RegularExpression urlRe(VTK_URL_REGEX);
if (!urlRe.find(URL))
return false;
// match 0 URL
// match 1 protocol
// match 2 mangled user
// match 3 username
// match 4 mangled password
// match 5 password
// match 6 hostname
// match 7 mangled port
// match 8 dataport
// match 9 database name
protocol = urlRe.match(1);
username = urlRe.match(3);
password = urlRe.match(5);
hostname = urlRe.match(6);
dataport = urlRe.match(8);
database = urlRe.match(9);
if (decode) {
username = DecodeURL(username);
password = DecodeURL(password);
hostname = DecodeURL(hostname);
dataport = DecodeURL(dataport);
database = DecodeURL(database);
}
return true;
}
// ----------------------------------------------------------------------
std::string SystemTools::DecodeURL(const std::string& url)
{
kwsys::RegularExpression urlByteRe(VTK_URL_BYTE_REGEX);
std::string ret;
for (size_t i = 0; i < url.length(); i++) {
if (urlByteRe.find(url.substr(i, 3))) {
char bytes[] = { url[i + 1], url[i + 2], '\0' };
ret += static_cast<char>(strtoul(bytes, nullptr, 16));
i += 2;
} else {
ret += url[i];
}
}
return ret;
}
// ----------------------------------------------------------------------
// Do NOT initialize. Default initialization to zero is necessary.
static unsigned int SystemToolsManagerCount;
// SystemToolsManager manages the SystemTools singleton.
// SystemToolsManager should be included in any translation unit
// that will use SystemTools or that implements the singleton
// pattern. It makes sure that the SystemTools singleton is created
// before and destroyed after all other singletons in CMake.
SystemToolsManager::SystemToolsManager()
{
if (++SystemToolsManagerCount == 1) {
SystemTools::ClassInitialize();
}
}
SystemToolsManager::~SystemToolsManager()
{
if (--SystemToolsManagerCount == 0) {
SystemTools::ClassFinalize();
}
}
#if defined(__VMS)
// On VMS we configure the run time C library to be more UNIX like.
// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html
extern "C" int decc$feature_get_index(char* name);
extern "C" int decc$feature_set_value(int index, int mode, int value);
static int SetVMSFeature(char* name, int value)
{
int i;
errno = 0;
i = decc$feature_get_index(name);
return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
}
#endif
void SystemTools::ClassInitialize()
{
#ifdef __VMS
SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
#endif
// Create statics singleton instance
SystemToolsStatics = new SystemToolsStatic;
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Add some special translation paths for unix. These are not added
// for windows because drive letters need to be maintained. Also,
// there are not sym-links and mount points on windows anyway.
# if !defined(_WIN32) || defined(__CYGWIN__)
// The tmp path is frequently a logical path so always keep it:
SystemTools::AddKeepPath("/tmp/");
// If the current working directory is a logical path then keep the
// logical name.
std::string pwd_str;
if (SystemTools::GetEnv("PWD", pwd_str)) {
char buf[2048];
if (const char* cwd = Getcwd(buf, 2048)) {
// The current working directory may be a logical path. Find
// the shortest logical path that still produces the correct
// physical path.
std::string cwd_changed;
std::string pwd_changed;
// Test progressively shorter logical-to-physical mappings.
std::string cwd_str = cwd;
std::string pwd_path;
Realpath(pwd_str, pwd_path);
while (cwd_str == pwd_path && cwd_str != pwd_str) {
// The current pair of paths is a working logical mapping.
cwd_changed = cwd_str;
pwd_changed = pwd_str;
// Strip off one directory level and see if the logical
// mapping still works.
pwd_str = SystemTools::GetFilenamePath(pwd_str);
cwd_str = SystemTools::GetFilenamePath(cwd_str);
Realpath(pwd_str, pwd_path);
}
// Add the translation to keep the logical path name.
if (!cwd_changed.empty() && !pwd_changed.empty()) {
SystemTools::AddTranslationPath(cwd_changed, pwd_changed);
}
}
}
# endif
#endif
}
void SystemTools::ClassFinalize()
{
delete SystemToolsStatics;
}
} // namespace KWSYS_NAMESPACE