| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ |
| #ifdef __osf__ |
| # define _OSF_SOURCE |
| # define _POSIX_C_SOURCE 199506L |
| # define _XOPEN_SOURCE_EXTENDED |
| #endif |
| |
| #if defined(_WIN32) && \ |
| (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ |
| defined(__MINGW32__)) |
| # define KWSYS_WINDOWS_DIRS |
| #else |
| # if defined(__SUNPRO_CC) |
| # include <fcntl.h> |
| # endif |
| #endif |
| |
| #include "kwsysPrivate.h" |
| #include KWSYS_HEADER(RegularExpression.hxx) |
| #include KWSYS_HEADER(SystemTools.hxx) |
| #include KWSYS_HEADER(Directory.hxx) |
| #include KWSYS_HEADER(FStream.hxx) |
| #include KWSYS_HEADER(Encoding.h) |
| #include KWSYS_HEADER(Encoding.hxx) |
| |
| #include <fstream> |
| #include <iostream> |
| #include <set> |
| #include <sstream> |
| #include <utility> |
| #include <vector> |
| |
| // Work-around CMake dependency scanning limitation. This must |
| // duplicate the above list of headers. |
| #if 0 |
| # include "Directory.hxx.in" |
| # include "Encoding.hxx.in" |
| # include "FStream.hxx.in" |
| # include "RegularExpression.hxx.in" |
| # include "SystemTools.hxx.in" |
| #endif |
| |
| #ifdef _MSC_VER |
| # pragma warning(disable : 4786) |
| #endif |
| |
| #if defined(__sgi) && !defined(__GNUC__) |
| # pragma set woff 1375 /* base class destructor not virtual */ |
| #endif |
| |
| #include <ctype.h> |
| #include <errno.h> |
| #ifdef __QNX__ |
| # include <malloc.h> /* for malloc/free on QNX */ |
| #endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| |
| #if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) |
| # include <strings.h> /* for strcasecmp */ |
| #endif |
| |
| #ifdef _MSC_VER |
| # define umask _umask // Note this is still umask on Borland |
| #endif |
| |
| // support for realpath call |
| #ifndef _WIN32 |
| # include <limits.h> |
| # include <pwd.h> |
| # include <sys/ioctl.h> |
| # include <sys/time.h> |
| # include <sys/wait.h> |
| # include <unistd.h> |
| # include <utime.h> |
| # ifndef __VMS |
| # include <sys/param.h> |
| # include <termios.h> |
| # endif |
| # include <signal.h> /* sigprocmask */ |
| #endif |
| |
| #ifdef __linux |
| # include <linux/fs.h> |
| #endif |
| |
| // Windows API. |
| #if defined(_WIN32) |
| # include <windows.h> |
| # include <winioctl.h> |
| # ifndef INVALID_FILE_ATTRIBUTES |
| # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) |
| # endif |
| # if defined(_MSC_VER) && _MSC_VER >= 1800 |
| # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx |
| # endif |
| #elif defined(__CYGWIN__) |
| # include <windows.h> |
| # undef _WIN32 |
| #endif |
| |
| #if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H |
| extern char** environ; |
| #endif |
| |
| #ifdef __CYGWIN__ |
| # include <sys/cygwin.h> |
| #endif |
| |
| // getpwnam doesn't exist on Windows and Cray Xt3/Catamount |
| // same for TIOCGWINSZ |
| #if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \ |
| (defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0) |
| # undef HAVE_GETPWNAM |
| # undef HAVE_TTY_INFO |
| #else |
| # define HAVE_GETPWNAM 1 |
| # define HAVE_TTY_INFO 1 |
| #endif |
| |
| #define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)" |
| #define VTK_URL_REGEX \ |
| "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/" \ |
| "(.+)?" |
| |
| #ifdef _MSC_VER |
| # include <sys/utime.h> |
| #else |
| # include <utime.h> |
| #endif |
| |
| // This is a hack to prevent warnings about these functions being |
| // declared but not referenced. |
| #if defined(__sgi) && !defined(__GNUC__) |
| # include <sys/termios.h> |
| namespace KWSYS_NAMESPACE { |
| class SystemToolsHack |
| { |
| public: |
| enum |
| { |
| Ref1 = sizeof(cfgetospeed(0)), |
| Ref2 = sizeof(cfgetispeed(0)), |
| Ref3 = sizeof(tcgetattr(0, 0)), |
| Ref4 = sizeof(tcsetattr(0, 0, 0)), |
| Ref5 = sizeof(cfsetospeed(0, 0)), |
| Ref6 = sizeof(cfsetispeed(0, 0)) |
| }; |
| }; |
| } |
| #endif |
| |
| #if defined(_WIN32) && \ |
| (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ |
| defined(__MINGW32__)) |
| # include <direct.h> |
| # include <io.h> |
| # define _unlink unlink |
| #endif |
| |
| /* The maximum length of a file name. */ |
| #if defined(PATH_MAX) |
| # define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX |
| #elif defined(MAXPATHLEN) |
| # define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN |
| #else |
| # define KWSYS_SYSTEMTOOLS_MAXPATH 16384 |
| #endif |
| #if defined(__WATCOMC__) |
| # include <direct.h> |
| # define _mkdir mkdir |
| # define _rmdir rmdir |
| # define _getcwd getcwd |
| # define _chdir chdir |
| #endif |
| |
| #if defined(__BEOS__) && !defined(__ZETA__) |
| # include <be/kernel/OS.h> |
| # include <be/storage/Path.h> |
| |
| // BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. |
| static inline void usleep(unsigned int msec) |
| { |
| ::snooze(msec); |
| } |
| |
| // BeOS 5 also doesn't have realpath(), but its C++ API offers something close. |
| static inline char* realpath(const char* path, char* resolved_path) |
| { |
| const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH; |
| snprintf(resolved_path, maxlen, "%s", path); |
| BPath normalized(resolved_path, nullptr, true); |
| const char* resolved = normalized.Path(); |
| if (resolved != nullptr) // nullptr == No such file. |
| { |
| if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) { |
| return resolved_path; |
| } |
| } |
| return nullptr; // something went wrong. |
| } |
| #endif |
| |
| #ifdef _WIN32 |
| static time_t windows_filetime_to_posix_time(const FILETIME& ft) |
| { |
| LARGE_INTEGER date; |
| date.HighPart = ft.dwHighDateTime; |
| date.LowPart = ft.dwLowDateTime; |
| |
| // removes the diff between 1970 and 1601 |
| date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000); |
| |
| // converts back from 100-nanoseconds to seconds |
| return date.QuadPart / 10000000; |
| } |
| #endif |
| |
| #ifdef KWSYS_WINDOWS_DIRS |
| # include <wctype.h> |
| |
| inline int Mkdir(const std::string& dir) |
| { |
| return _wmkdir( |
| KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); |
| } |
| inline int Rmdir(const std::string& dir) |
| { |
| return _wrmdir( |
| KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); |
| } |
| inline const char* Getcwd(char* buf, unsigned int len) |
| { |
| std::vector<wchar_t> w_buf(len); |
| if (_wgetcwd(&w_buf[0], len)) { |
| size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); |
| if (nlen == static_cast<size_t>(-1)) { |
| return 0; |
| } |
| if (nlen < len) { |
| // make sure the drive letter is capital |
| if (nlen > 1 && buf[1] == ':') { |
| buf[0] = toupper(buf[0]); |
| } |
| return buf; |
| } |
| } |
| return 0; |
| } |
| inline int Chdir(const std::string& dir) |
| { |
| # if defined(__BORLANDC__) |
| return chdir(dir.c_str()); |
| # else |
| return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); |
| # endif |
| } |
| inline void Realpath(const std::string& path, std::string& resolved_path, |
| std::string* errorMessage = 0) |
| { |
| std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path); |
| wchar_t* ptemp; |
| wchar_t fullpath[MAX_PATH]; |
| DWORD bufferLen = GetFullPathNameW( |
| tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp); |
| if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) { |
| resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath); |
| KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path); |
| } else if (errorMessage) { |
| if (bufferLen) { |
| *errorMessage = "Destination path buffer size too small."; |
| } else if (unsigned int errorId = GetLastError()) { |
| LPSTR message = nullptr; |
| DWORD size = FormatMessageA( |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
| FORMAT_MESSAGE_IGNORE_INSERTS, |
| nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| (LPSTR)&message, 0, nullptr); |
| *errorMessage = std::string(message, size); |
| LocalFree(message); |
| } else { |
| *errorMessage = "Unknown error."; |
| } |
| |
| resolved_path = ""; |
| } else { |
| resolved_path = path; |
| } |
| } |
| #else |
| # include <sys/types.h> |
| |
| # include <fcntl.h> |
| # include <unistd.h> |
| inline int Mkdir(const std::string& dir) |
| { |
| return mkdir(dir.c_str(), 00777); |
| } |
| inline int Rmdir(const std::string& dir) |
| { |
| return rmdir(dir.c_str()); |
| } |
| inline const char* Getcwd(char* buf, unsigned int len) |
| { |
| return getcwd(buf, len); |
| } |
| |
| inline int Chdir(const std::string& dir) |
| { |
| return chdir(dir.c_str()); |
| } |
| inline void Realpath(const std::string& path, std::string& resolved_path, |
| std::string* errorMessage = nullptr) |
| { |
| char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH]; |
| |
| errno = 0; |
| char* ret = realpath(path.c_str(), resolved_name); |
| if (ret) { |
| resolved_path = ret; |
| } else if (errorMessage) { |
| if (errno) { |
| *errorMessage = strerror(errno); |
| } else { |
| *errorMessage = "Unknown error."; |
| } |
| |
| resolved_path = ""; |
| } else { |
| // if path resolution fails, return what was passed in |
| resolved_path = path; |
| } |
| } |
| #endif |
| |
| #if !defined(_WIN32) && defined(__COMO__) |
| // Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE. |
| extern "C" { |
| extern FILE* popen(__const char* __command, __const char* __modes) __THROW; |
| extern int pclose(FILE* __stream) __THROW; |
| extern char* realpath(__const char* __restrict __name, |
| char* __restrict __resolved) __THROW; |
| extern char* strdup(__const char* __s) __THROW; |
| extern int putenv(char* __string) __THROW; |
| } |
| #endif |
| |
| namespace KWSYS_NAMESPACE { |
| |
| double SystemTools::GetTime(void) |
| { |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| FILETIME ft; |
| GetSystemTimeAsFileTime(&ft); |
| return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime - |
| 11644473600.0); |
| #else |
| struct timeval t; |
| gettimeofday(&t, nullptr); |
| return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec); |
| #endif |
| } |
| |
| /* Type of character storing the environment. */ |
| #if defined(_WIN32) |
| typedef wchar_t envchar; |
| #else |
| typedef char envchar; |
| #endif |
| |
| /* Order by environment key only (VAR from VAR=VALUE). */ |
| struct kwsysEnvCompare |
| { |
| bool operator()(const envchar* l, const envchar* r) const |
| { |
| #if defined(_WIN32) |
| const wchar_t* leq = wcschr(l, L'='); |
| const wchar_t* req = wcschr(r, L'='); |
| size_t llen = leq ? (leq - l) : wcslen(l); |
| size_t rlen = req ? (req - r) : wcslen(r); |
| if (llen == rlen) { |
| return wcsncmp(l, r, llen) < 0; |
| } else { |
| return wcscmp(l, r) < 0; |
| } |
| #else |
| const char* leq = strchr(l, '='); |
| const char* req = strchr(r, '='); |
| size_t llen = leq ? static_cast<size_t>(leq - l) : strlen(l); |
| size_t rlen = req ? static_cast<size_t>(req - r) : strlen(r); |
| if (llen == rlen) { |
| return strncmp(l, r, llen) < 0; |
| } else { |
| return strcmp(l, r) < 0; |
| } |
| #endif |
| } |
| }; |
| |
| class kwsysEnvSet : public std::set<const envchar*, kwsysEnvCompare> |
| { |
| public: |
| class Free |
| { |
| const envchar* Env; |
| |
| public: |
| Free(const envchar* env) |
| : Env(env) |
| { |
| } |
| ~Free() { free(const_cast<envchar*>(this->Env)); } |
| |
| Free(const Free&) = delete; |
| Free& operator=(const Free&) = delete; |
| }; |
| |
| const envchar* Release(const envchar* env) |
| { |
| const envchar* old = nullptr; |
| iterator i = this->find(env); |
| if (i != this->end()) { |
| old = *i; |
| this->erase(i); |
| } |
| return old; |
| } |
| }; |
| |
| #ifdef _WIN32 |
| struct SystemToolsPathCaseCmp |
| { |
| bool operator()(std::string const& l, std::string const& r) const |
| { |
| # ifdef _MSC_VER |
| return _stricmp(l.c_str(), r.c_str()) < 0; |
| # elif defined(__GNUC__) |
| return strcasecmp(l.c_str(), r.c_str()) < 0; |
| # else |
| return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0; |
| # endif |
| } |
| }; |
| #endif |
| |
| /** |
| * SystemTools static variables singleton class. |
| */ |
| class SystemToolsStatic |
| { |
| public: |
| typedef std::map<std::string, std::string> StringMap; |
| #if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP |
| /** |
| * Path translation table from dir to refdir |
| * Each time 'dir' will be found it will be replace by 'refdir' |
| */ |
| StringMap TranslationMap; |
| #endif |
| #ifdef _WIN32 |
| static std::string GetCasePathName(std::string const& pathIn); |
| static std::string GetActualCaseForPathCached(std::string const& path); |
| static const char* GetEnvBuffered(const char* key); |
| std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap; |
| std::map<std::string, std::string> EnvMap; |
| #endif |
| #ifdef __CYGWIN__ |
| StringMap Cyg2Win32Map; |
| #endif |
| |
| /** |
| * Actual implementation of ReplaceString. |
| */ |
| static void ReplaceString(std::string& source, const char* replace, |
| size_t replaceSize, const std::string& with); |
| |
| /** |
| * Actual implementation of FileIsFullPath. |
| */ |
| static bool FileIsFullPath(const char*, size_t); |
| |
| /** |
| * Find a filename (file or directory) in the system PATH, with |
| * optional extra paths. |
| */ |
| static std::string FindName( |
| const std::string& name, |
| const std::vector<std::string>& path = std::vector<std::string>(), |
| bool no_system_path = false); |
| }; |
| |
| #ifdef _WIN32 |
| std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn) |
| { |
| std::string casePath; |
| |
| // First check if the file is relative. We don't fix relative paths since the |
| // real case depends on the root directory and the given path fragment may |
| // have meaning elsewhere in the project. |
| if (!SystemTools::FileIsFullPath(pathIn)) { |
| // This looks unnecessary, but it allows for the return value optimization |
| // since all return paths return the same local variable. |
| casePath = pathIn; |
| return casePath; |
| } |
| |
| std::vector<std::string> path_components; |
| SystemTools::SplitPath(pathIn, path_components); |
| |
| // Start with root component. |
| std::vector<std::string>::size_type idx = 0; |
| casePath = path_components[idx++]; |
| // make sure drive letter is always upper case |
| if (casePath.size() > 1 && casePath[1] == ':') { |
| casePath[0] = toupper(casePath[0]); |
| } |
| const char* sep = ""; |
| |
| // If network path, fill casePath with server/share so FindFirstFile |
| // will work after that. Maybe someday call other APIs to get |
| // actual case of servers and shares. |
| if (path_components.size() > 2 && path_components[0] == "//") { |
| casePath += path_components[idx++]; |
| casePath += "/"; |
| casePath += path_components[idx++]; |
| sep = "/"; |
| } |
| |
| // Convert case of all components that exist. |
| bool converting = true; |
| for (; idx < path_components.size(); idx++) { |
| casePath += sep; |
| sep = "/"; |
| |
| if (converting) { |
| // If path component contains wildcards, we skip matching |
| // because these filenames are not allowed on windows, |
| // and we do not want to match a different file. |
| if (path_components[idx].find('*') != std::string::npos || |
| path_components[idx].find('?') != std::string::npos) { |
| converting = false; |
| } else { |
| std::string test_str = casePath; |
| test_str += path_components[idx]; |
| WIN32_FIND_DATAW findData; |
| HANDLE hFind = |
| ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData); |
| if (INVALID_HANDLE_VALUE != hFind) { |
| path_components[idx] = Encoding::ToNarrow(findData.cFileName); |
| ::FindClose(hFind); |
| } else { |
| converting = false; |
| } |
| } |
| } |
| |
| casePath += path_components[idx]; |
| } |
| return casePath; |
| } |
| |
| std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p) |
| { |
| // Check to see if actual case has already been called |
| // for this path, and the result is stored in the PathCaseMap |
| auto& pcm = SystemTools::Statics->PathCaseMap; |
| { |
| auto itr = pcm.find(p); |
| if (itr != pcm.end()) { |
| return itr->second; |
| } |
| } |
| std::string casePath = SystemToolsStatic::GetCasePathName(p); |
| if (casePath.size() <= MAX_PATH) { |
| pcm[p] = casePath; |
| } |
| return casePath; |
| } |
| #endif |
| |
| // adds the elements of the env variable path to the arg passed in |
| void SystemTools::GetPath(std::vector<std::string>& path, const char* env) |
| { |
| size_t const old_size = path.size(); |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| const char pathSep = ';'; |
| #else |
| const char pathSep = ':'; |
| #endif |
| if (!env) { |
| env = "PATH"; |
| } |
| std::string pathEnv; |
| if (!SystemTools::GetEnv(env, pathEnv)) { |
| return; |
| } |
| |
| // A hack to make the below algorithm work. |
| if (!pathEnv.empty() && pathEnv.back() != pathSep) { |
| pathEnv += pathSep; |
| } |
| std::string::size_type start = 0; |
| bool done = false; |
| while (!done) { |
| std::string::size_type endpos = pathEnv.find(pathSep, start); |
| if (endpos != std::string::npos) { |
| path.push_back(pathEnv.substr(start, endpos - start)); |
| start = endpos + 1; |
| } else { |
| done = true; |
| } |
| } |
| for (std::vector<std::string>::iterator i = path.begin() + old_size; |
| i != path.end(); ++i) { |
| SystemTools::ConvertToUnixSlashes(*i); |
| } |
| } |
| |
| #if defined(_WIN32) |
| const char* SystemToolsStatic::GetEnvBuffered(const char* key) |
| { |
| std::string env; |
| if (SystemTools::GetEnv(key, env)) { |
| std::string& menv = SystemTools::Statics->EnvMap[key]; |
| if (menv != env) { |
| menv = std::move(env); |
| } |
| return menv.c_str(); |
| } |
| return nullptr; |
| } |
| #endif |
| |
| const char* SystemTools::GetEnv(const char* key) |
| { |
| #if defined(_WIN32) |
| return SystemToolsStatic::GetEnvBuffered(key); |
| #else |
| return getenv(key); |
| #endif |
| } |
| |
| const char* SystemTools::GetEnv(const std::string& key) |
| { |
| #if defined(_WIN32) |
| return SystemToolsStatic::GetEnvBuffered(key.c_str()); |
| #else |
| return getenv(key.c_str()); |
| #endif |
| } |
| |
| bool SystemTools::GetEnv(const char* key, std::string& result) |
| { |
| #if defined(_WIN32) |
| const std::wstring wkey = Encoding::ToWide(key); |
| const wchar_t* wv = _wgetenv(wkey.c_str()); |
| if (wv) { |
| result = Encoding::ToNarrow(wv); |
| return true; |
| } |
| #else |
| const char* v = getenv(key); |
| if (v) { |
| result = v; |
| return true; |
| } |
| #endif |
| return false; |
| } |
| |
| bool SystemTools::GetEnv(const std::string& key, std::string& result) |
| { |
| return SystemTools::GetEnv(key.c_str(), result); |
| } |
| |
| bool SystemTools::HasEnv(const char* key) |
| { |
| #if defined(_WIN32) |
| const std::wstring wkey = Encoding::ToWide(key); |
| const wchar_t* v = _wgetenv(wkey.c_str()); |
| #else |
| const char* v = getenv(key); |
| #endif |
| return v != nullptr; |
| } |
| |
| bool SystemTools::HasEnv(const std::string& key) |
| { |
| return SystemTools::HasEnv(key.c_str()); |
| } |
| |
| #if KWSYS_CXX_HAS_UNSETENV |
| /* unsetenv("A") removes A from the environment. |
| On older platforms it returns void instead of int. */ |
| static int kwsysUnPutEnv(const std::string& env) |
| { |
| size_t pos = env.find('='); |
| if (pos != std::string::npos) { |
| std::string name = env.substr(0, pos); |
| unsetenv(name.c_str()); |
| } else { |
| unsetenv(env.c_str()); |
| } |
| return 0; |
| } |
| |
| #elif defined(__CYGWIN__) || defined(__GLIBC__) |
| /* putenv("A") removes A from the environment. It must not put the |
| memory in the environment because it does not have any "=" syntax. */ |
| static int kwsysUnPutEnv(const std::string& env) |
| { |
| int err = 0; |
| size_t pos = env.find('='); |
| size_t const len = pos == std::string::npos ? env.size() : pos; |
| size_t const sz = len + 1; |
| char local_buf[256]; |
| char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; |
| if (!buf) { |
| return -1; |
| } |
| strncpy(buf, env.c_str(), len); |
| buf[len] = 0; |
| if (putenv(buf) < 0 && errno != EINVAL) { |
| err = errno; |
| } |
| if (buf != local_buf) { |
| free(buf); |
| } |
| if (err) { |
| errno = err; |
| return -1; |
| } |
| return 0; |
| } |
| |
| #elif defined(_WIN32) |
| /* putenv("A=") places "A=" in the environment, which is as close to |
| removal as we can get with the putenv API. We have to leak the |
| most recent value placed in the environment for each variable name |
| on program exit in case exit routines access it. */ |
| |
| static kwsysEnvSet kwsysUnPutEnvSet; |
| |
| static int kwsysUnPutEnv(std::string const& env) |
| { |
| std::wstring wEnv = Encoding::ToWide(env); |
| size_t const pos = wEnv.find('='); |
| size_t const len = pos == std::string::npos ? wEnv.size() : pos; |
| wEnv.resize(len + 1, L'='); |
| wchar_t* newEnv = _wcsdup(wEnv.c_str()); |
| if (!newEnv) { |
| return -1; |
| } |
| kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv)); |
| kwsysUnPutEnvSet.insert(newEnv); |
| return _wputenv(newEnv); |
| } |
| |
| #else |
| /* Manipulate the "environ" global directly. */ |
| static int kwsysUnPutEnv(const std::string& env) |
| { |
| size_t pos = env.find('='); |
| size_t const len = pos == std::string::npos ? env.size() : pos; |
| int in = 0; |
| int out = 0; |
| while (environ[in]) { |
| if (strlen(environ[in]) > len && environ[in][len] == '=' && |
| strncmp(env.c_str(), environ[in], len) == 0) { |
| ++in; |
| } else { |
| environ[out++] = environ[in++]; |
| } |
| } |
| while (out < in) { |
| environ[out++] = 0; |
| } |
| return 0; |
| } |
| #endif |
| |
| #if KWSYS_CXX_HAS_SETENV |
| |
| /* setenv("A", "B", 1) will set A=B in the environment and makes its |
| own copies of the strings. */ |
| bool SystemTools::PutEnv(const std::string& env) |
| { |
| size_t pos = env.find('='); |
| if (pos != std::string::npos) { |
| std::string name = env.substr(0, pos); |
| return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0; |
| } else { |
| return kwsysUnPutEnv(env) == 0; |
| } |
| } |
| |
| bool SystemTools::UnPutEnv(const std::string& env) |
| { |
| return kwsysUnPutEnv(env) == 0; |
| } |
| |
| #else |
| |
| /* putenv("A=B") will set A=B in the environment. Most putenv implementations |
| put their argument directly in the environment. They never free the memory |
| on program exit. Keep an active set of pointers to memory we allocate and |
| pass to putenv, one per environment key. At program exit remove any |
| environment values that may still reference memory we allocated. Then free |
| the memory. This will not affect any environment values we never set. */ |
| |
| # ifdef __INTEL_COMPILER |
| # pragma warning disable 444 /* base has non-virtual destructor */ |
| # endif |
| |
| class kwsysEnv : public kwsysEnvSet |
| { |
| public: |
| ~kwsysEnv() |
| { |
| for (iterator i = this->begin(); i != this->end(); ++i) { |
| # if defined(_WIN32) |
| const std::string s = Encoding::ToNarrow(*i); |
| kwsysUnPutEnv(s); |
| # else |
| kwsysUnPutEnv(*i); |
| # endif |
| free(const_cast<envchar*>(*i)); |
| } |
| } |
| bool Put(const char* env) |
| { |
| # if defined(_WIN32) |
| const std::wstring wEnv = Encoding::ToWide(env); |
| wchar_t* newEnv = _wcsdup(wEnv.c_str()); |
| # else |
| char* newEnv = strdup(env); |
| # endif |
| Free oldEnv(this->Release(newEnv)); |
| this->insert(newEnv); |
| # if defined(_WIN32) |
| return _wputenv(newEnv) == 0; |
| # else |
| return putenv(newEnv) == 0; |
| # endif |
| } |
| bool UnPut(const char* env) |
| { |
| # if defined(_WIN32) |
| const std::wstring wEnv = Encoding::ToWide(env); |
| Free oldEnv(this->Release(wEnv.c_str())); |
| # else |
| Free oldEnv(this->Release(env)); |
| # endif |
| return kwsysUnPutEnv(env) == 0; |
| } |
| }; |
| |
| static kwsysEnv kwsysEnvInstance; |
| |
| bool SystemTools::PutEnv(const std::string& env) |
| { |
| return kwsysEnvInstance.Put(env.c_str()); |
| } |
| |
| bool SystemTools::UnPutEnv(const std::string& env) |
| { |
| return kwsysEnvInstance.UnPut(env.c_str()); |
| } |
| |
| #endif |
| |
| const char* SystemTools::GetExecutableExtension() |
| { |
| #if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS) |
| return ".exe"; |
| #else |
| return ""; |
| #endif |
| } |
| |
| FILE* SystemTools::Fopen(const std::string& file, const char* mode) |
| { |
| #ifdef _WIN32 |
| return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(), |
| Encoding::ToWide(mode).c_str()); |
| #else |
| return fopen(file.c_str(), mode); |
| #endif |
| } |
| |
| bool SystemTools::MakeDirectory(const char* path, const mode_t* mode) |
| { |
| if (!path) { |
| return false; |
| } |
| return SystemTools::MakeDirectory(std::string(path), mode); |
| } |
| |
| bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) |
| { |
| if (SystemTools::PathExists(path)) { |
| return SystemTools::FileIsDirectory(path); |
| } |
| if (path.empty()) { |
| return false; |
| } |
| std::string dir = path; |
| SystemTools::ConvertToUnixSlashes(dir); |
| |
| std::string::size_type pos = 0; |
| std::string topdir; |
| while ((pos = dir.find('/', pos)) != std::string::npos) { |
| topdir = dir.substr(0, pos); |
| |
| if (Mkdir(topdir) == 0 && mode != nullptr) { |
| SystemTools::SetPermissions(topdir, *mode); |
| } |
| |
| ++pos; |
| } |
| topdir = dir; |
| if (Mkdir(topdir) != 0) { |
| // There is a bug in the Borland Run time library which makes MKDIR |
| // return EACCES when it should return EEXISTS |
| // if it is some other error besides directory exists |
| // then return false |
| if ((errno != EEXIST) |
| #ifdef __BORLANDC__ |
| && (errno != EACCES) |
| #endif |
| ) { |
| return false; |
| } |
| } else if (mode != nullptr) { |
| SystemTools::SetPermissions(topdir, *mode); |
| } |
| |
| return true; |
| } |
| |
| // replace replace with with as many times as it shows up in source. |
| // write the result into source. |
| void SystemTools::ReplaceString(std::string& source, |
| const std::string& replace, |
| const std::string& with) |
| { |
| // do while hangs if replaceSize is 0 |
| if (replace.empty()) { |
| return; |
| } |
| |
| SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(), |
| with); |
| } |
| |
| void SystemTools::ReplaceString(std::string& source, const char* replace, |
| const char* with) |
| { |
| // do while hangs if replaceSize is 0 |
| if (!*replace) { |
| return; |
| } |
| |
| SystemToolsStatic::ReplaceString(source, replace, strlen(replace), |
| with ? with : ""); |
| } |
| |
| void SystemToolsStatic::ReplaceString(std::string& source, const char* replace, |
| size_t replaceSize, |
| const std::string& with) |
| { |
| const char* src = source.c_str(); |
| char* searchPos = const_cast<char*>(strstr(src, replace)); |
| |
| // get out quick if string is not found |
| if (!searchPos) { |
| return; |
| } |
| |
| // perform replacements until done |
| char* orig = strdup(src); |
| char* currentPos = orig; |
| searchPos = searchPos - src + orig; |
| |
| // initialize the result |
| source.erase(source.begin(), source.end()); |
| do { |
| *searchPos = '\0'; |
| source += currentPos; |
| currentPos = searchPos + replaceSize; |
| // replace |
| source += with; |
| searchPos = strstr(currentPos, replace); |
| } while (searchPos); |
| |
| // copy any trailing text |
| source += currentPos; |
| free(orig); |
| } |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| |
| # if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY) |
| # define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY |
| # define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY |
| # else |
| # define KWSYS_ST_KEY_WOW64_32KEY 0x0200 |
| # define KWSYS_ST_KEY_WOW64_64KEY 0x0100 |
| # endif |
| |
| static bool SystemToolsParseRegistryKey(const std::string& key, |
| HKEY& primaryKey, std::string& second, |
| std::string& valuename) |
| { |
| std::string primary = key; |
| |
| size_t start = primary.find('\\'); |
| if (start == std::string::npos) { |
| return false; |
| } |
| |
| size_t valuenamepos = primary.find(';'); |
| if (valuenamepos != std::string::npos) { |
| valuename = primary.substr(valuenamepos + 1); |
| } |
| |
| second = primary.substr(start + 1, valuenamepos - start - 1); |
| primary = primary.substr(0, start); |
| |
| if (primary == "HKEY_CURRENT_USER") { |
| primaryKey = HKEY_CURRENT_USER; |
| } |
| if (primary == "HKEY_CURRENT_CONFIG") { |
| primaryKey = HKEY_CURRENT_CONFIG; |
| } |
| if (primary == "HKEY_CLASSES_ROOT") { |
| primaryKey = HKEY_CLASSES_ROOT; |
| } |
| if (primary == "HKEY_LOCAL_MACHINE") { |
| primaryKey = HKEY_LOCAL_MACHINE; |
| } |
| if (primary == "HKEY_USERS") { |
| primaryKey = HKEY_USERS; |
| } |
| |
| return true; |
| } |
| |
| static DWORD SystemToolsMakeRegistryMode(DWORD mode, |
| SystemTools::KeyWOW64 view) |
| { |
| // only add the modes when on a system that supports Wow64. |
| static FARPROC wow64p = |
| GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"); |
| if (wow64p == nullptr) { |
| return mode; |
| } |
| |
| if (view == SystemTools::KeyWOW64_32) { |
| return mode | KWSYS_ST_KEY_WOW64_32KEY; |
| } else if (view == SystemTools::KeyWOW64_64) { |
| return mode | KWSYS_ST_KEY_WOW64_64KEY; |
| } |
| return mode; |
| } |
| #endif |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::GetRegistrySubKeys(const std::string& key, |
| std::vector<std::string>& subkeys, |
| KeyWOW64 view) |
| { |
| HKEY primaryKey = HKEY_CURRENT_USER; |
| std::string second; |
| std::string valuename; |
| if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { |
| return false; |
| } |
| |
| HKEY hKey; |
| if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, |
| SystemToolsMakeRegistryMode(KEY_READ, view), |
| &hKey) != ERROR_SUCCESS) { |
| return false; |
| } else { |
| wchar_t name[1024]; |
| DWORD dwNameSize = sizeof(name) / sizeof(name[0]); |
| |
| DWORD i = 0; |
| while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) { |
| subkeys.push_back(Encoding::ToNarrow(name)); |
| ++i; |
| } |
| |
| RegCloseKey(hKey); |
| } |
| |
| return true; |
| } |
| #else |
| bool SystemTools::GetRegistrySubKeys(const std::string&, |
| std::vector<std::string>&, KeyWOW64) |
| { |
| return false; |
| } |
| #endif |
| |
| // Read a registry value. |
| // Example : |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath |
| // => will return the data of the "default" value of the key |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root |
| // => will return the data of the "Root" value of the key |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value, |
| KeyWOW64 view) |
| { |
| bool valueset = false; |
| HKEY primaryKey = HKEY_CURRENT_USER; |
| std::string second; |
| std::string valuename; |
| if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { |
| return false; |
| } |
| |
| HKEY hKey; |
| if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, |
| SystemToolsMakeRegistryMode(KEY_READ, view), |
| &hKey) != ERROR_SUCCESS) { |
| return false; |
| } else { |
| DWORD dwType, dwSize; |
| dwSize = 1023; |
| wchar_t data[1024]; |
| if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), nullptr, |
| &dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) { |
| if (dwType == REG_SZ) { |
| value = Encoding::ToNarrow(data); |
| valueset = true; |
| } else if (dwType == REG_EXPAND_SZ) { |
| wchar_t expanded[1024]; |
| DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]); |
| if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) { |
| value = Encoding::ToNarrow(expanded); |
| valueset = true; |
| } |
| } |
| } |
| |
| RegCloseKey(hKey); |
| } |
| |
| return valueset; |
| } |
| #else |
| bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64) |
| { |
| return false; |
| } |
| #endif |
| |
| // Write a registry value. |
| // Example : |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath |
| // => will set the data of the "default" value of the key |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root |
| // => will set the data of the "Root" value of the key |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::WriteRegistryValue(const std::string& key, |
| const std::string& value, KeyWOW64 view) |
| { |
| HKEY primaryKey = HKEY_CURRENT_USER; |
| std::string second; |
| std::string valuename; |
| if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { |
| return false; |
| } |
| |
| HKEY hKey; |
| DWORD dwDummy; |
| wchar_t lpClass[] = L""; |
| if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass, |
| REG_OPTION_NON_VOLATILE, |
| SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr, |
| &hKey, &dwDummy) != ERROR_SUCCESS) { |
| return false; |
| } |
| |
| std::wstring wvalue = Encoding::ToWide(value); |
| if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ, |
| (CONST BYTE*)wvalue.c_str(), |
| (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) == |
| ERROR_SUCCESS) { |
| return true; |
| } |
| return false; |
| } |
| #else |
| bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, |
| KeyWOW64) |
| { |
| return false; |
| } |
| #endif |
| |
| // Delete a registry value. |
| // Example : |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath |
| // => will delete the data of the "default" value of the key |
| // HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root |
| // => will delete the data of the "Root" value of the key |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) |
| { |
| HKEY primaryKey = HKEY_CURRENT_USER; |
| std::string second; |
| std::string valuename; |
| if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { |
| return false; |
| } |
| |
| HKEY hKey; |
| if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, |
| SystemToolsMakeRegistryMode(KEY_WRITE, view), |
| &hKey) != ERROR_SUCCESS) { |
| return false; |
| } else { |
| if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) { |
| RegCloseKey(hKey); |
| return true; |
| } |
| } |
| return false; |
| } |
| #else |
| bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64) |
| { |
| return false; |
| } |
| #endif |
| |
| bool SystemTools::SameFile(const std::string& file1, const std::string& file2) |
| { |
| #ifdef _WIN32 |
| HANDLE hFile1, hFile2; |
| |
| hFile1 = |
| CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ, |
| nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); |
| hFile2 = |
| CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ, |
| nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); |
| if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) { |
| if (hFile1 != INVALID_HANDLE_VALUE) { |
| CloseHandle(hFile1); |
| } |
| if (hFile2 != INVALID_HANDLE_VALUE) { |
| CloseHandle(hFile2); |
| } |
| return false; |
| } |
| |
| BY_HANDLE_FILE_INFORMATION fiBuf1; |
| BY_HANDLE_FILE_INFORMATION fiBuf2; |
| GetFileInformationByHandle(hFile1, &fiBuf1); |
| GetFileInformationByHandle(hFile2, &fiBuf2); |
| CloseHandle(hFile1); |
| CloseHandle(hFile2); |
| return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber && |
| fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh && |
| fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow); |
| #else |
| struct stat fileStat1, fileStat2; |
| if (stat(file1.c_str(), &fileStat1) == 0 && |
| stat(file2.c_str(), &fileStat2) == 0) { |
| // see if the files are the same file |
| // check the device inode and size |
| if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev, |
| sizeof(fileStat1.st_dev)) == 0 && |
| memcmp(&fileStat2.st_ino, &fileStat1.st_ino, |
| sizeof(fileStat1.st_ino)) == 0 && |
| fileStat2.st_size == fileStat1.st_size) { |
| return true; |
| } |
| } |
| return false; |
| #endif |
| } |
| |
| bool SystemTools::PathExists(const std::string& path) |
| { |
| if (path.empty()) { |
| return false; |
| } |
| #if defined(__CYGWIN__) |
| // Convert path to native windows path if possible. |
| char winpath[MAX_PATH]; |
| if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) { |
| return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); |
| } |
| struct stat st; |
| return lstat(path.c_str(), &st) == 0; |
| #elif defined(_WIN32) |
| return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) != |
| INVALID_FILE_ATTRIBUTES); |
| #else |
| struct stat st; |
| return lstat(path.c_str(), &st) == 0; |
| #endif |
| } |
| |
| bool SystemTools::FileExists(const char* filename) |
| { |
| if (!filename) { |
| return false; |
| } |
| return SystemTools::FileExists(std::string(filename)); |
| } |
| |
| bool SystemTools::FileExists(const std::string& filename) |
| { |
| if (filename.empty()) { |
| return false; |
| } |
| #if defined(__CYGWIN__) |
| // Convert filename to native windows path if possible. |
| char winpath[MAX_PATH]; |
| if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) { |
| return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); |
| } |
| return access(filename.c_str(), R_OK) == 0; |
| #elif defined(_WIN32) |
| DWORD attr = |
| GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()); |
| if (attr == INVALID_FILE_ATTRIBUTES) { |
| return false; |
| } |
| |
| if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { |
| // Using 0 instead of GENERIC_READ as it allows reading of file attributes |
| // even if we do not have permission to read the file itself |
| HANDLE handle = |
| CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0, |
| nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); |
| |
| if (handle == INVALID_HANDLE_VALUE) { |
| return false; |
| } |
| |
| CloseHandle(handle); |
| } |
| |
| return true; |
| #else |
| // SCO OpenServer 5.0.7/3.2's command has 711 permission. |
| # if defined(_SCO_DS) |
| return access(filename.c_str(), F_OK) == 0; |
| # else |
| return access(filename.c_str(), R_OK) == 0; |
| # endif |
| #endif |
| } |
| |
| bool SystemTools::FileExists(const char* filename, bool isFile) |
| { |
| if (!filename) { |
| return false; |
| } |
| return SystemTools::FileExists(std::string(filename), isFile); |
| } |
| |
| bool SystemTools::FileExists(const std::string& filename, bool isFile) |
| { |
| if (SystemTools::FileExists(filename)) { |
| // If isFile is set return not FileIsDirectory, |
| // so this will only be true if it is a file |
| return !isFile || !SystemTools::FileIsDirectory(filename); |
| } |
| return false; |
| } |
| |
| bool SystemTools::TestFileAccess(const char* filename, |
| TestFilePermissions permissions) |
| { |
| if (!filename) { |
| return false; |
| } |
| return SystemTools::TestFileAccess(std::string(filename), permissions); |
| } |
| |
| bool SystemTools::TestFileAccess(const std::string& filename, |
| TestFilePermissions permissions) |
| { |
| if (filename.empty()) { |
| return false; |
| } |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| // If execute set, change to read permission (all files on Windows |
| // are executable if they are readable). The CRT will always fail |
| // if you pass an execute bit. |
| if (permissions & TEST_FILE_EXECUTE) { |
| permissions &= ~TEST_FILE_EXECUTE; |
| permissions |= TEST_FILE_READ; |
| } |
| return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(), |
| permissions) == 0; |
| #else |
| return access(filename.c_str(), permissions) == 0; |
| #endif |
| } |
| |
| int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf) |
| { |
| if (!path) { |
| errno = EFAULT; |
| return -1; |
| } |
| return SystemTools::Stat(std::string(path), buf); |
| } |
| |
| int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) |
| { |
| if (path.empty()) { |
| errno = ENOENT; |
| return -1; |
| } |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| // Ideally we should use Encoding::ToWindowsExtendedPath to support |
| // long paths, but _wstat64 rejects paths with '?' in them, thinking |
| // they are wildcards. |
| std::wstring const& wpath = Encoding::ToWide(path); |
| # if defined(__BORLANDC__) |
| return _wstati64(wpath.c_str(), buf); |
| # else |
| return _wstat64(wpath.c_str(), buf); |
| # endif |
| #else |
| return stat(path.c_str(), buf); |
| #endif |
| } |
| |
| #ifdef __CYGWIN__ |
| bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) |
| { |
| auto itr = SystemTools::Statics->Cyg2Win32Map.find(path); |
| if (itr != SystemTools::Statics->Cyg2Win32Map.end()) { |
| strncpy(win32_path, itr->second.c_str(), MAX_PATH); |
| } else { |
| if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) != |
| 0) { |
| win32_path[0] = 0; |
| } |
| SystemTools::Statics->Cyg2Win32Map.insert( |
| SystemToolsStatic::StringMap::value_type(path, win32_path)); |
| } |
| return win32_path[0] != 0; |
| } |
| #endif |
| |
| bool SystemTools::Touch(const std::string& filename, bool create) |
| { |
| if (!SystemTools::PathExists(filename)) { |
| if (create) { |
| FILE* file = Fopen(filename, "a+b"); |
| if (file) { |
| fclose(file); |
| return true; |
| } |
| return false; |
| } else { |
| return true; |
| } |
| } |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), |
| FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, |
| OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); |
| if (!h) { |
| return false; |
| } |
| FILETIME mtime; |
| GetSystemTimeAsFileTime(&mtime); |
| if (!SetFileTime(h, 0, 0, &mtime)) { |
| CloseHandle(h); |
| return false; |
| } |
| CloseHandle(h); |
| #elif KWSYS_CXX_HAS_UTIMENSAT |
| // utimensat is only available on newer Unixes and macOS 10.13+ |
| if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) { |
| return false; |
| } |
| #else |
| // fall back to utimes |
| if (utimes(filename.c_str(), nullptr) < 0) { |
| return false; |
| } |
| #endif |
| return true; |
| } |
| |
| bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, |
| int* result) |
| { |
| // Default to same time. |
| *result = 0; |
| #if !defined(_WIN32) || defined(__CYGWIN__) |
| // POSIX version. Use stat function to get file modification time. |
| struct stat s1; |
| if (stat(f1.c_str(), &s1) != 0) { |
| return false; |
| } |
| struct stat s2; |
| if (stat(f2.c_str(), &s2) != 0) { |
| return false; |
| } |
| # if KWSYS_CXX_STAT_HAS_ST_MTIM |
| // Compare using nanosecond resolution. |
| if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) { |
| *result = -1; |
| } else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) { |
| *result = 1; |
| } else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) { |
| *result = -1; |
| } else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) { |
| *result = 1; |
| } |
| # elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC |
| // Compare using nanosecond resolution. |
| if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) { |
| *result = -1; |
| } else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) { |
| *result = 1; |
| } else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) { |
| *result = -1; |
| } else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) { |
| *result = 1; |
| } |
| # else |
| // Compare using 1 second resolution. |
| if (s1.st_mtime < s2.st_mtime) { |
| *result = -1; |
| } else if (s1.st_mtime > s2.st_mtime) { |
| *result = 1; |
| } |
| # endif |
| #else |
| // Windows version. Get the modification time from extended file attributes. |
| WIN32_FILE_ATTRIBUTE_DATA f1d; |
| WIN32_FILE_ATTRIBUTE_DATA f2d; |
| if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(), |
| GetFileExInfoStandard, &f1d)) { |
| return false; |
| } |
| if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(), |
| GetFileExInfoStandard, &f2d)) { |
| return false; |
| } |
| |
| // Compare the file times using resolution provided by system call. |
| *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime); |
| #endif |
| return true; |
| } |
| |
| // Return a capitalized string (i.e the first letter is uppercased, all other |
| // are lowercased) |
| std::string SystemTools::Capitalized(const std::string& s) |
| { |
| std::string n; |
| if (s.empty()) { |
| return n; |
| } |
| n.resize(s.size()); |
| n[0] = static_cast<std::string::value_type>(toupper(s[0])); |
| for (size_t i = 1; i < s.size(); i++) { |
| n[i] = static_cast<std::string::value_type>(tolower(s[i])); |
| } |
| return n; |
| } |
| |
| // Return capitalized words |
| std::string SystemTools::CapitalizedWords(const std::string& s) |
| { |
| std::string n(s); |
| for (size_t i = 0; i < s.size(); i++) { |
| #if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) |
| // MS has an assert that will fail if s[i] < 0; setting |
| // LC_CTYPE using setlocale() does *not* help. Painful. |
| if ((int)s[i] >= 0 && isalpha(s[i]) && |
| (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) |
| #else |
| if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) |
| #endif |
| { |
| n[i] = static_cast<std::string::value_type>(toupper(s[i])); |
| } |
| } |
| return n; |
| } |
| |
| // Return uncapitalized words |
| std::string SystemTools::UnCapitalizedWords(const std::string& s) |
| { |
| std::string n(s); |
| for (size_t i = 0; i < s.size(); i++) { |
| #if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) |
| // MS has an assert that will fail if s[i] < 0; setting |
| // LC_CTYPE using setlocale() does *not* help. Painful. |
| if ((int)s[i] >= 0 && isalpha(s[i]) && |
| (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) |
| #else |
| if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) |
| #endif |
| { |
| n[i] = static_cast<std::string::value_type>(tolower(s[i])); |
| } |
| } |
| return n; |
| } |
| |
| // only works for words with at least two letters |
| std::string SystemTools::AddSpaceBetweenCapitalizedWords(const std::string& s) |
| { |
| std::string n; |
| if (!s.empty()) { |
| n.reserve(s.size()); |
| n += s[0]; |
| for (size_t i = 1; i < s.size(); i++) { |
| if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) { |
| n += ' '; |
| } |
| n += s[i]; |
| } |
| } |
| return n; |
| } |
| |
| char* SystemTools::AppendStrings(const char* str1, const char* str2) |
| { |
| if (!str1) { |
| return SystemTools::DuplicateString(str2); |
| } |
| if (!str2) { |
| return SystemTools::DuplicateString(str1); |
| } |
| size_t len1 = strlen(str1); |
| char* newstr = new char[len1 + strlen(str2) + 1]; |
| if (!newstr) { |
| return nullptr; |
| } |
| strcpy(newstr, str1); |
| strcat(newstr + len1, str2); |
| return newstr; |
| } |
| |
| char* SystemTools::AppendStrings(const char* str1, const char* str2, |
| const char* str3) |
| { |
| if (!str1) { |
| return SystemTools::AppendStrings(str2, str3); |
| } |
| if (!str2) { |
| return SystemTools::AppendStrings(str1, str3); |
| } |
| if (!str3) { |
| return SystemTools::AppendStrings(str1, str2); |
| } |
| |
| size_t len1 = strlen(str1), len2 = strlen(str2); |
| char* newstr = new char[len1 + len2 + strlen(str3) + 1]; |
| if (!newstr) { |
| return nullptr; |
| } |
| strcpy(newstr, str1); |
| strcat(newstr + len1, str2); |
| strcat(newstr + len1 + len2, str3); |
| return newstr; |
| } |
| |
| // Return a lower case string |
| std::string SystemTools::LowerCase(const std::string& s) |
| { |
| std::string n; |
| n.resize(s.size()); |
| for (size_t i = 0; i < s.size(); i++) { |
| n[i] = static_cast<std::string::value_type>(tolower(s[i])); |
| } |
| return n; |
| } |
| |
| // Return a lower case string |
| std::string SystemTools::UpperCase(const std::string& s) |
| { |
| std::string n; |
| n.resize(s.size()); |
| for (size_t i = 0; i < s.size(); i++) { |
| n[i] = static_cast<std::string::value_type>(toupper(s[i])); |
| } |
| return n; |
| } |
| |
| // Count char in string |
| size_t SystemTools::CountChar(const char* str, char c) |
| { |
| size_t count = 0; |
| |
| if (str) { |
| while (*str) { |
| if (*str == c) { |
| ++count; |
| } |
| ++str; |
| } |
| } |
| return count; |
| } |
| |
| // Remove chars in string |
| char* SystemTools::RemoveChars(const char* str, const char* toremove) |
| { |
| if (!str) { |
| return nullptr; |
| } |
| char* clean_str = new char[strlen(str) + 1]; |
| char* ptr = clean_str; |
| while (*str) { |
| const char* str2 = toremove; |
| while (*str2 && *str != *str2) { |
| ++str2; |
| } |
| if (!*str2) { |
| *ptr++ = *str; |
| } |
| ++str; |
| } |
| *ptr = '\0'; |
| return clean_str; |
| } |
| |
| // Remove chars in string |
| char* SystemTools::RemoveCharsButUpperHex(const char* str) |
| { |
| if (!str) { |
| return nullptr; |
| } |
| char* clean_str = new char[strlen(str) + 1]; |
| char* ptr = clean_str; |
| while (*str) { |
| if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F')) { |
| *ptr++ = *str; |
| } |
| ++str; |
| } |
| *ptr = '\0'; |
| return clean_str; |
| } |
| |
| // Replace chars in string |
| char* SystemTools::ReplaceChars(char* str, const char* toreplace, |
| char replacement) |
| { |
| if (str) { |
| char* ptr = str; |
| while (*ptr) { |
| const char* ptr2 = toreplace; |
| while (*ptr2) { |
| if (*ptr == *ptr2) { |
| *ptr = replacement; |
| } |
| ++ptr2; |
| } |
| ++ptr; |
| } |
| } |
| return str; |
| } |
| |
| // Returns if string starts with another string |
| bool SystemTools::StringStartsWith(const char* str1, const char* str2) |
| { |
| if (!str1 || !str2) { |
| return false; |
| } |
| size_t len1 = strlen(str1), len2 = strlen(str2); |
| return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false; |
| } |
| |
| // Returns if string starts with another string |
| bool SystemTools::StringStartsWith(const std::string& str1, const char* str2) |
| { |
| if (!str2) { |
| return false; |
| } |
| size_t len1 = str1.size(), len2 = strlen(str2); |
| return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false; |
| } |
| |
| // Returns if string ends with another string |
| bool SystemTools::StringEndsWith(const char* str1, const char* str2) |
| { |
| if (!str1 || !str2) { |
| return false; |
| } |
| size_t len1 = strlen(str1), len2 = strlen(str2); |
| return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true |
| : false; |
| } |
| |
| // Returns if string ends with another string |
| bool SystemTools::StringEndsWith(const std::string& str1, const char* str2) |
| { |
| if (!str2) { |
| return false; |
| } |
| size_t len1 = str1.size(), len2 = strlen(str2); |
| return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2) |
| ? true |
| : false; |
| } |
| |
| // Returns a pointer to the last occurrence of str2 in str1 |
| const char* SystemTools::FindLastString(const char* str1, const char* str2) |
| { |
| if (!str1 || !str2) { |
| return nullptr; |
| } |
| |
| size_t len1 = strlen(str1), len2 = strlen(str2); |
| if (len1 >= len2) { |
| const char* ptr = str1 + len1 - len2; |
| do { |
| if (!strncmp(ptr, str2, len2)) { |
| return ptr; |
| } |
| } while (ptr-- != str1); |
| } |
| |
| return nullptr; |
| } |
| |
| // Duplicate string |
| char* SystemTools::DuplicateString(const char* str) |
| { |
| if (str) { |
| char* newstr = new char[strlen(str) + 1]; |
| return strcpy(newstr, str); |
| } |
| return nullptr; |
| } |
| |
| // Return a cropped string |
| std::string SystemTools::CropString(const std::string& s, size_t max_len) |
| { |
| if (!s.size() || max_len == 0 || max_len >= s.size()) { |
| return s; |
| } |
| |
| std::string n; |
| n.reserve(max_len); |
| |
| size_t middle = max_len / 2; |
| |
| n += s.substr(0, middle); |
| n += s.substr(s.size() - (max_len - middle)); |
| |
| if (max_len > 2) { |
| n[middle] = '.'; |
| if (max_len > 3) { |
| n[middle - 1] = '.'; |
| if (max_len > 4) { |
| n[middle + 1] = '.'; |
| } |
| } |
| } |
| |
| return n; |
| } |
| |
| std::vector<std::string> SystemTools::SplitString(const std::string& p, |
| char sep, bool isPath) |
| { |
| std::string path = p; |
| std::vector<std::string> paths; |
| if (path.empty()) { |
| return paths; |
| } |
| if (isPath && path[0] == '/') { |
| path.erase(path.begin()); |
| paths.push_back("/"); |
| } |
| std::string::size_type pos1 = 0; |
| std::string::size_type pos2 = path.find(sep, pos1 + 1); |
| while (pos2 != std::string::npos) { |
| paths.push_back(path.substr(pos1, pos2 - pos1)); |
| pos1 = pos2 + 1; |
| pos2 = path.find(sep, pos1 + 1); |
| } |
| paths.push_back(path.substr(pos1, pos2 - pos1)); |
| |
| return paths; |
| } |
| |
| int SystemTools::EstimateFormatLength(const char* format, va_list ap) |
| { |
| if (!format) { |
| return 0; |
| } |
| |
| // Quick-hack attempt at estimating the length of the string. |
| // Should never under-estimate. |
| |
| // Start with the length of the format string itself. |
| |
| size_t length = strlen(format); |
| |
| // Increase the length for every argument in the format. |
| |
| const char* cur = format; |
| while (*cur) { |
| if (*cur++ == '%') { |
| // Skip "%%" since it doesn't correspond to a va_arg. |
| if (*cur != '%') { |
| while (!int(isalpha(*cur))) { |
| ++cur; |
| } |
| switch (*cur) { |
| case 's': { |
| // Check the length of the string. |
| char* s = va_arg(ap, char*); |
| if (s) { |
| length += strlen(s); |
| } |
| } break; |
| case 'e': |
| case 'f': |
| case 'g': { |
| // Assume the argument contributes no more than 64 characters. |
| length += 64; |
| |
| // Eat the argument. |
| static_cast<void>(va_arg(ap, double)); |
| } break; |
| default: { |
| // Assume the argument contributes no more than 64 characters. |
| length += 64; |
| |
| // Eat the argument. |
| static_cast<void>(va_arg(ap, int)); |
| } break; |
| } |
| } |
| |
| // Move past the characters just tested. |
| ++cur; |
| } |
| } |
| |
| return static_cast<int>(length); |
| } |
| |
| std::string SystemTools::EscapeChars(const char* str, |
| const char* chars_to_escape, |
| char escape_char) |
| { |
| std::string n; |
| if (str) { |
| if (!chars_to_escape || !*chars_to_escape) { |
| n.append(str); |
| } else { |
| n.reserve(strlen(str)); |
| while (*str) { |
| const char* ptr = chars_to_escape; |
| while (*ptr) { |
| if (*str == *ptr) { |
| n += escape_char; |
| break; |
| } |
| ++ptr; |
| } |
| n += *str; |
| ++str; |
| } |
| } |
| } |
| return n; |
| } |
| |
| #ifdef __VMS |
| static void ConvertVMSToUnix(std::string& path) |
| { |
| std::string::size_type rootEnd = path.find(":["); |
| std::string::size_type pathEnd = path.find("]"); |
| if (rootEnd != std::string::npos) { |
| std::string root = path.substr(0, rootEnd); |
| std::string pathPart = path.substr(rootEnd + 2, pathEnd - rootEnd - 2); |
| const char* pathCString = pathPart.c_str(); |
| const char* pos0 = pathCString; |
| for (std::string::size_type pos = 0; *pos0; ++pos) { |
| if (*pos0 == '.') { |
| pathPart[pos] = '/'; |
| } |
| pos0++; |
| } |
| path = "/" + root + "/" + pathPart; |
| } |
| } |
| #endif |
| |
| // convert windows slashes to unix slashes |
| void SystemTools::ConvertToUnixSlashes(std::string& path) |
| { |
| if (path.empty()) { |
| return; |
| } |
| |
| const char* pathCString = path.c_str(); |
| bool hasDoubleSlash = false; |
| #ifdef __VMS |
| ConvertVMSToUnix(path); |
| #else |
| const char* pos0 = pathCString; |
| for (std::string::size_type pos = 0; *pos0; ++pos) { |
| if (*pos0 == '\\') { |
| path[pos] = '/'; |
| } |
| |
| // Also, reuse the loop to check for slash followed by another slash |
| if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') { |
| # ifdef _WIN32 |
| // However, on windows if the first characters are both slashes, |
| // then keep them that way, so that network paths can be handled. |
| if (pos > 0) { |
| hasDoubleSlash = true; |
| } |
| # else |
| hasDoubleSlash = true; |
| # endif |
| } |
| |
| pos0++; |
| } |
| |
| if (hasDoubleSlash) { |
| SystemTools::ReplaceString(path, "//", "/"); |
| } |
| #endif |
| |
| // remove any trailing slash |
| // if there is a tilda ~ then replace it with HOME |
| pathCString = path.c_str(); |
| if (pathCString[0] == '~' && |
| (pathCString[1] == '/' || pathCString[1] == '\0')) { |
| std::string homeEnv; |
| if (SystemTools::GetEnv("HOME", homeEnv)) { |
| path.replace(0, 1, homeEnv); |
| } |
| } |
| #ifdef HAVE_GETPWNAM |
| else if (pathCString[0] == '~') { |
| std::string::size_type idx = path.find_first_of("/\0"); |
| std::string user = path.substr(1, idx - 1); |
| passwd* pw = getpwnam(user.c_str()); |
| if (pw) { |
| path.replace(0, idx, pw->pw_dir); |
| } |
| } |
| #endif |
| // remove trailing slash if the path is more than |
| // a single / |
| pathCString = path.c_str(); |
| size_t size = path.size(); |
| if (size > 1 && path.back() == '/') { |
| // if it is c:/ then do not remove the trailing slash |
| if (!((size == 3 && pathCString[1] == ':'))) { |
| path.resize(size - 1); |
| } |
| } |
| } |
| |
| #ifdef _WIN32 |
| std::wstring SystemTools::ConvertToWindowsExtendedPath( |
| const std::string& source) |
| { |
| return Encoding::ToWindowsExtendedPath(source); |
| } |
| #endif |
| |
| // change // to /, and escape any spaces in the path |
| std::string SystemTools::ConvertToUnixOutputPath(const std::string& path) |
| { |
| std::string ret = path; |
| |
| // remove // except at the beginning might be a cygwin drive |
| std::string::size_type pos = 1; |
| while ((pos = ret.find("//", pos)) != std::string::npos) { |
| ret.erase(pos, 1); |
| } |
| // escape spaces and () in the path |
| if (ret.find_first_of(" ") != std::string::npos) { |
| std::string result; |
| char lastch = 1; |
| for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) { |
| // if it is already escaped then don't try to escape it again |
| if ((*ch == ' ') && lastch != '\\') { |
| result += '\\'; |
| } |
| result += *ch; |
| lastch = *ch; |
| } |
| ret = result; |
| } |
| return ret; |
| } |
| |
| std::string SystemTools::ConvertToOutputPath(const std::string& path) |
| { |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| return SystemTools::ConvertToWindowsOutputPath(path); |
| #else |
| return SystemTools::ConvertToUnixOutputPath(path); |
| #endif |
| } |
| |
| // remove double slashes not at the start |
| std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path) |
| { |
| std::string ret; |
| // make it big enough for all of path and double quotes |
| ret.reserve(path.size() + 3); |
| // put path into the string |
| ret = path; |
| std::string::size_type pos = 0; |
| // first convert all of the slashes |
| while ((pos = ret.find('/', pos)) != std::string::npos) { |
| ret[pos] = '\\'; |
| pos++; |
| } |
| // check for really small paths |
| if (ret.size() < 2) { |
| return ret; |
| } |
| // now clean up a bit and remove double slashes |
| // Only if it is not the first position in the path which is a network |
| // path on windows |
| pos = 1; // start at position 1 |
| if (ret[0] == '\"') { |
| pos = 2; // if the string is already quoted then start at 2 |
| if (ret.size() < 3) { |
| return ret; |
| } |
| } |
| while ((pos = ret.find("\\\\", pos)) != std::string::npos) { |
| ret.erase(pos, 1); |
| } |
| // now double quote the path if it has spaces in it |
| // and is not already double quoted |
| if (ret.find(' ') != std::string::npos && ret[0] != '\"') { |
| ret.insert(static_cast<std::string::size_type>(0), |
| static_cast<std::string::size_type>(1), '\"'); |
| ret.append(1, '\"'); |
| } |
| return ret; |
| } |
| |
| /** |
| * Append the filename from the path source to the directory name dir. |
| */ |
| static std::string FileInDir(const std::string& source, const std::string& dir) |
| { |
| std::string new_destination = dir; |
| SystemTools::ConvertToUnixSlashes(new_destination); |
| return new_destination + '/' + SystemTools::GetFilenameName(source); |
| } |
| |
| bool SystemTools::CopyFileIfDifferent(const std::string& source, |
| const std::string& destination) |
| { |
| // special check for a destination that is a directory |
| // FilesDiffer does not handle file to directory compare |
| if (SystemTools::FileIsDirectory(destination)) { |
| const std::string new_destination = FileInDir(source, destination); |
| return SystemTools::CopyFileIfDifferent(source, new_destination); |
| } |
| // source and destination are files so do a copy if they |
| // are different |
| if (SystemTools::FilesDiffer(source, destination)) { |
| return SystemTools::CopyFileAlways(source, destination); |
| } |
| // at this point the files must be the same so return true |
| return true; |
| } |
| |
| #define KWSYS_ST_BUFFER 4096 |
| |
| bool SystemTools::FilesDiffer(const std::string& source, |
| const std::string& destination) |
| { |
| |
| #if defined(_WIN32) |
| WIN32_FILE_ATTRIBUTE_DATA statSource; |
| if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(), |
| GetFileExInfoStandard, &statSource) == 0) { |
| return true; |
| } |
| |
| WIN32_FILE_ATTRIBUTE_DATA statDestination; |
| if (GetFileAttributesExW( |
| Encoding::ToWindowsExtendedPath(destination).c_str(), |
| GetFileExInfoStandard, &statDestination) == 0) { |
| return true; |
| } |
| |
| if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh || |
| statSource.nFileSizeLow != statDestination.nFileSizeLow) { |
| return true; |
| } |
| |
| if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { |
| return false; |
| } |
| off_t nleft = |
| ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; |
| |
| #else |
| |
| struct stat statSource; |
| if (stat(source.c_str(), &statSource) != 0) { |
| return true; |
| } |
| |
| struct stat statDestination; |
| if (stat(destination.c_str(), &statDestination) != 0) { |
| return true; |
| } |
| |
| if (statSource.st_size != statDestination.st_size) { |
| return true; |
| } |
| |
| if (statSource.st_size == 0) { |
| return false; |
| } |
| off_t nleft = statSource.st_size; |
| #endif |
| |
| #if defined(_WIN32) |
| kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in)); |
| kwsys::ifstream finDestination(destination.c_str(), |
| (std::ios::binary | std::ios::in)); |
| #else |
| kwsys::ifstream finSource(source.c_str()); |
| kwsys::ifstream finDestination(destination.c_str()); |
| #endif |
| if (!finSource || !finDestination) { |
| return true; |
| } |
| |
| // Compare the files a block at a time. |
| char source_buf[KWSYS_ST_BUFFER]; |
| char dest_buf[KWSYS_ST_BUFFER]; |
| while (nleft > 0) { |
| // Read a block from each file. |
| std::streamsize nnext = (nleft > KWSYS_ST_BUFFER) |
| ? KWSYS_ST_BUFFER |
| : static_cast<std::streamsize>(nleft); |
| finSource.read(source_buf, nnext); |
| finDestination.read(dest_buf, nnext); |
| |
| // If either failed to read assume they are different. |
| if (static_cast<std::streamsize>(finSource.gcount()) != nnext || |
| static_cast<std::streamsize>(finDestination.gcount()) != nnext) { |
| return true; |
| } |
| |
| // If this block differs the file differs. |
| if (memcmp(static_cast<const void*>(source_buf), |
| static_cast<const void*>(dest_buf), |
| static_cast<size_t>(nnext)) != 0) { |
| return true; |
| } |
| |
| // Update the byte count remaining. |
| nleft -= nnext; |
| } |
| |
| // No differences found. |
| return false; |
| } |
| |
| bool SystemTools::TextFilesDiffer(const std::string& path1, |
| const std::string& path2) |
| { |
| kwsys::ifstream if1(path1.c_str()); |
| kwsys::ifstream if2(path2.c_str()); |
| if (!if1 || !if2) { |
| return true; |
| } |
| |
| for (;;) { |
| std::string line1, line2; |
| bool hasData1 = GetLineFromStream(if1, line1); |
| bool hasData2 = GetLineFromStream(if2, line2); |
| if (hasData1 != hasData2) { |
| return true; |
| } |
| if (!hasData1) { |
| break; |
| } |
| if (line1 != line2) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Blockwise copy source to destination file |
| */ |
| static bool CopyFileContentBlockwise(const std::string& source, |
| const std::string& destination) |
| { |
| // Open files |
| #if defined(_WIN32) |
| kwsys::ifstream fin( |
| Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(), |
| std::ios::in | std::ios::binary); |
| #else |
| kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); |
| #endif |
| if (!fin) { |
| return false; |
| } |
| |
| // try and remove the destination file so that read only destination files |
| // can be written to. |
| // If the remove fails continue so that files in read only directories |
| // that do not allow file removal can be modified. |
| SystemTools::RemoveFile(destination); |
| |
| #if defined(_WIN32) |
| kwsys::ofstream fout( |
| Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(), |
| std::ios::out | std::ios::trunc | std::ios::binary); |
| #else |
| kwsys::ofstream fout(destination.c_str(), |
| std::ios::out | std::ios::trunc | std::ios::binary); |
| #endif |
| if (!fout) { |
| return false; |
| } |
| |
| // This copy loop is very sensitive on certain platforms with |
| // slightly broken stream libraries (like HPUX). Normally, it is |
| // incorrect to not check the error condition on the fin.read() |
| // before using the data, but the fin.gcount() will be zero if an |
| // error occurred. Therefore, the loop should be safe everywhere. |
| while (fin) { |
| const int bufferSize = 4096; |
| char buffer[bufferSize]; |
| |
| fin.read(buffer, bufferSize); |
| if (fin.gcount()) { |
| fout.write(buffer, fin.gcount()); |
| } else { |
| break; |
| } |
| } |
| |
| // Make sure the operating system has finished writing the file |
| // before closing it. This will ensure the file is finished before |
| // the check below. |
| fout.flush(); |
| |
| fin.close(); |
| fout.close(); |
| |
| if (!fout) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Clone the source file to the destination file |
| * |
| * If available, the Linux FICLONE ioctl is used to create a check |
| * copy-on-write clone of the source file. |
| * |
| * The method returns false for the following cases: |
| * - The code has not been compiled on Linux or the ioctl was unknown |
| * - The source and destination is on different file systems |
| * - The underlying filesystem does not support file cloning |
| * - An unspecified error occurred |
| */ |
| static bool CloneFileContent(const std::string& source, |
| const std::string& destination) |
| { |
| #if defined(__linux) && defined(FICLONE) |
| int in = open(source.c_str(), O_RDONLY); |
| if (in < 0) { |
| return false; |
| } |
| |
| SystemTools::RemoveFile(destination); |
| |
| int out = |
| open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (out < 0) { |
| close(in); |
| return false; |
| } |
| |
| int result = ioctl(out, FICLONE, in); |
| close(in); |
| close(out); |
| |
| if (result < 0) { |
| return false; |
| } |
| |
| return true; |
| #else |
| (void)source; |
| (void)destination; |
| return false; |
| #endif |
| } |
| |
| /** |
| * Copy a file named by "source" to the file named by "destination". |
| */ |
| bool SystemTools::CopyFileAlways(const std::string& source, |
| const std::string& destination) |
| { |
| mode_t perm = 0; |
| bool perms = SystemTools::GetPermissions(source, perm); |
| std::string real_destination = destination; |
| |
| if (SystemTools::FileIsDirectory(source)) { |
| SystemTools::MakeDirectory(destination); |
| } else { |
| // If destination is a directory, try to create a file with the same |
| // name as the source in that directory. |
| |
| std::string destination_dir; |
| if (SystemTools::FileIsDirectory(destination)) { |
| destination_dir = real_destination; |
| SystemTools::ConvertToUnixSlashes(real_destination); |
| real_destination += '/'; |
| std::string source_name = source; |
| real_destination += SystemTools::GetFilenameName(source_name); |
| } else { |
| destination_dir = SystemTools::GetFilenamePath(destination); |
| } |
| // If files are the same do not copy |
| if (SystemTools::SameFile(source, real_destination)) { |
| return true; |
| } |
| |
| // Create destination directory |
| |
| SystemTools::MakeDirectory(destination_dir); |
| |
| if (!CloneFileContent(source, real_destination)) { |
| // if cloning did not succeed, fall back to blockwise copy |
| if (!CopyFileContentBlockwise(source, real_destination)) { |
| return false; |
| } |
| } |
| } |
| if (perms) { |
| if (!SystemTools::SetPermissions(real_destination, perm)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool SystemTools::CopyAFile(const std::string& source, |
| const std::string& destination, bool always) |
| { |
| if (always) { |
| return SystemTools::CopyFileAlways(source, destination); |
| } else { |
| return SystemTools::CopyFileIfDifferent(source, destination); |
| } |
| } |
| |
| /** |
| * Copy a directory content from "source" directory to the directory named by |
| * "destination". |
| */ |
| bool SystemTools::CopyADirectory(const std::string& source, |
| const std::string& destination, bool always) |
| { |
| Directory dir; |
| if (dir.Load(source) == 0) { |
| return false; |
| } |
| size_t fileNum; |
| if (!SystemTools::MakeDirectory(destination)) { |
| return false; |
| } |
| for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { |
| if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") && |
| strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) { |
| std::string fullPath = source; |
| fullPath += "/"; |
| fullPath += dir.GetFile(static_cast<unsigned long>(fileNum)); |
| if (SystemTools::FileIsDirectory(fullPath)) { |
| std::string fullDestPath = destination; |
| fullDestPath += "/"; |
| fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum)); |
| if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) { |
| return false; |
| } |
| } else { |
| if (!SystemTools::CopyAFile(fullPath, destination, always)) { |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| // return size of file; also returns zero if no file exists |
| unsigned long SystemTools::FileLength(const std::string& filename) |
| { |
| unsigned long length = 0; |
| #ifdef _WIN32 |
| WIN32_FILE_ATTRIBUTE_DATA fs; |
| if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), |
| GetFileExInfoStandard, &fs) != 0) { |
| /* To support the full 64-bit file size, use fs.nFileSizeHigh |
| * and fs.nFileSizeLow to construct the 64 bit size |
| |
| length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow; |
| */ |
| length = static_cast<unsigned long>(fs.nFileSizeLow); |
| } |
| #else |
| struct stat fs; |
| if (stat(filename.c_str(), &fs) == 0) { |
| length = static_cast<unsigned long>(fs.st_size); |
| } |
| #endif |
| return length; |
| } |
| |
| int SystemTools::Strucmp(const char* l, const char* r) |
| { |
| int lc; |
| int rc; |
| do { |
| lc = tolower(*l++); |
| rc = tolower(*r++); |
| } while (lc == rc && lc); |
| return lc - rc; |
| } |
| |
| // return file's modified time |
| long int SystemTools::ModifiedTime(const std::string& filename) |
| { |
| long int mt = 0; |
| #ifdef _WIN32 |
| WIN32_FILE_ATTRIBUTE_DATA fs; |
| if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), |
| GetFileExInfoStandard, &fs) != 0) { |
| mt = windows_filetime_to_posix_time(fs.ftLastWriteTime); |
| } |
| #else |
| struct stat fs; |
| if (stat(filename.c_str(), &fs) == 0) { |
| mt = static_cast<long int>(fs.st_mtime); |
| } |
| #endif |
| return mt; |
| } |
| |
| // return file's creation time |
| long int SystemTools::CreationTime(const std::string& filename) |
| { |
| long int ct = 0; |
| #ifdef _WIN32 |
| WIN32_FILE_ATTRIBUTE_DATA fs; |
| if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), |
| GetFileExInfoStandard, &fs) != 0) { |
| ct = windows_filetime_to_posix_time(fs.ftCreationTime); |
| } |
| #else |
| struct stat fs; |
| if (stat(filename.c_str(), &fs) == 0) { |
| ct = fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0; |
| } |
| #endif |
| return ct; |
| } |
| |
| std::string SystemTools::GetLastSystemError() |
| { |
| int e = errno; |
| return strerror(e); |
| } |
| |
| bool SystemTools::RemoveFile(const std::string& source) |
| { |
| #ifdef _WIN32 |
| std::wstring const& ws = Encoding::ToWindowsExtendedPath(source); |
| if (DeleteFileW(ws.c_str())) { |
| return true; |
| } |
| DWORD err = GetLastError(); |
| if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { |
| return true; |
| } |
| if (err != ERROR_ACCESS_DENIED) { |
| return false; |
| } |
| /* The file may be read-only. Try adding write permission. */ |
| mode_t mode; |
| if (!SystemTools::GetPermissions(source, mode) || |
| !SystemTools::SetPermissions(source, S_IWRITE)) { |
| SetLastError(err); |
| return false; |
| } |
| |
| const DWORD DIRECTORY_SOFT_LINK_ATTRS = |
| FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; |
| DWORD attrs = GetFileAttributesW(ws.c_str()); |
| if (attrs != INVALID_FILE_ATTRIBUTES && |
| (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS && |
| RemoveDirectoryW(ws.c_str())) { |
| return true; |
| } |
| if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND || |
| GetLastError() == ERROR_PATH_NOT_FOUND) { |
| return true; |
| } |
| /* Try to restore the original permissions. */ |
| SystemTools::SetPermissions(source, mode); |
| SetLastError(err); |
| return false; |
| #else |
| return unlink(source.c_str()) == 0 || errno == ENOENT; |
| #endif |
| } |
| |
| bool SystemTools::RemoveADirectory(const std::string& source) |
| { |
| // Add write permission to the directory so we can modify its |
| // content to remove files and directories from it. |
| mode_t mode; |
| if (SystemTools::GetPermissions(source, mode)) { |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| mode |= S_IWRITE; |
| #else |
| mode |= S_IWUSR; |
| #endif |
| SystemTools::SetPermissions(source, mode); |
| } |
| |
| Directory dir; |
| dir.Load(source); |
| size_t fileNum; |
| for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { |
| if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") && |
| strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) { |
| std::string fullPath = source; |
| fullPath += "/"; |
| fullPath += dir.GetFile(static_cast<unsigned long>(fileNum)); |
| if (SystemTools::FileIsDirectory(fullPath) && |
| !SystemTools::FileIsSymlink(fullPath)) { |
| if (!SystemTools::RemoveADirectory(fullPath)) { |
| return false; |
| } |
| } else { |
| if (!SystemTools::RemoveFile(fullPath)) { |
| return false; |
| } |
| } |
| } |
| } |
| |
| return (Rmdir(source) == 0); |
| } |
| |
| /** |
| */ |
| size_t SystemTools::GetMaximumFilePathLength() |
| { |
| return KWSYS_SYSTEMTOOLS_MAXPATH; |
| } |
| |
| /** |
| * Find the file the given name. Searches the given path and then |
| * the system search path. Returns the full path to the file if it is |
| * found. Otherwise, the empty string is returned. |
| */ |
| std::string SystemToolsStatic::FindName( |
| const std::string& name, const std::vector<std::string>& userPaths, |
| bool no_system_path) |
| { |
| // Add the system search path to our path first |
| std::vector<std::string> path; |
| if (!no_system_path) { |
| SystemTools::GetPath(path, "CMAKE_FILE_PATH"); |
| SystemTools::GetPath(path); |
| } |
| // now add the additional paths |
| path.reserve(path.size() + userPaths.size()); |
| path.insert(path.end(), userPaths.begin(), userPaths.end()); |
| // now look for the file |
| std::string tryPath; |
| for (std::string const& p : path) { |
| tryPath = p; |
| if (tryPath.empty() || tryPath.back() != '/') { |
| tryPath += '/'; |
| } |
| tryPath += name; |
| if (SystemTools::FileExists(tryPath)) { |
| return tryPath; |
| } |
| } |
| // Couldn't find the file. |
| return ""; |
| } |
| |
| /** |
| * Find the file the given name. Searches the given path and then |
| * the system search path. Returns the full path to the file if it is |
| * found. Otherwise, the empty string is returned. |
| */ |
| std::string SystemTools::FindFile(const std::string& name, |
| const std::vector<std::string>& userPaths, |
| bool no_system_path) |
| { |
| std::string tryPath = |
| SystemToolsStatic::FindName(name, userPaths, no_system_path); |
| if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| // Couldn't find the file. |
| return ""; |
| } |
| |
| /** |
| * Find the directory the given name. Searches the given path and then |
| * the system search path. Returns the full path to the directory if it is |
| * found. Otherwise, the empty string is returned. |
| */ |
| std::string SystemTools::FindDirectory( |
| const std::string& name, const std::vector<std::string>& userPaths, |
| bool no_system_path) |
| { |
| std::string tryPath = |
| SystemToolsStatic::FindName(name, userPaths, no_system_path); |
| if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| // Couldn't find the file. |
| return ""; |
| } |
| |
| /** |
| * Find the executable with the given name. Searches the given path and then |
| * the system search path. Returns the full path to the executable if it is |
| * found. Otherwise, the empty string is returned. |
| */ |
| std::string SystemTools::FindProgram(const char* nameIn, |
| const std::vector<std::string>& userPaths, |
| bool no_system_path) |
| { |
| if (!nameIn || !*nameIn) { |
| return ""; |
| } |
| return SystemTools::FindProgram(std::string(nameIn), userPaths, |
| no_system_path); |
| } |
| |
| std::string SystemTools::FindProgram(const std::string& name, |
| const std::vector<std::string>& userPaths, |
| bool no_system_path) |
| { |
| std::string tryPath; |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) |
| std::vector<std::string> extensions; |
| // check to see if the name already has a .xxx at |
| // the end of it |
| // on windows try .com then .exe |
| if (name.size() <= 3 || name[name.size() - 4] != '.') { |
| extensions.emplace_back(".com"); |
| extensions.emplace_back(".exe"); |
| |
| // first try with extensions if the os supports them |
| for (std::string const& ext : extensions) { |
| tryPath = name; |
| tryPath += ext; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| } |
| } |
| #endif |
| |
| // now try just the name |
| if (SystemTools::FileExists(name, true)) { |
| return SystemTools::CollapseFullPath(name); |
| } |
| // now construct the path |
| std::vector<std::string> path; |
| // Add the system search path to our path. |
| if (!no_system_path) { |
| SystemTools::GetPath(path); |
| } |
| // now add the additional paths |
| path.reserve(path.size() + userPaths.size()); |
| path.insert(path.end(), userPaths.begin(), userPaths.end()); |
| // Add a trailing slash to all paths to aid the search process. |
| for (std::string& p : path) { |
| if (p.empty() || p.back() != '/') { |
| p += '/'; |
| } |
| } |
| // Try each path |
| for (std::string& p : path) { |
| #ifdef _WIN32 |
| // Remove double quotes from the path on windows |
| SystemTools::ReplaceString(p, "\"", ""); |
| #endif |
| #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) |
| // first try with extensions |
| for (std::string const& ext : extensions) { |
| tryPath = p; |
| tryPath += name; |
| tryPath += ext; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| } |
| #endif |
| // now try it without them |
| tryPath = p; |
| tryPath += name; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| } |
| // Couldn't find the program. |
| return ""; |
| } |
| |
| std::string SystemTools::FindProgram(const std::vector<std::string>& names, |
| const std::vector<std::string>& path, |
| bool noSystemPath) |
| { |
| for (std::string const& name : names) { |
| // Try to find the program. |
| std::string result = SystemTools::FindProgram(name, path, noSystemPath); |
| if (!result.empty()) { |
| return result; |
| } |
| } |
| return ""; |
| } |
| |
| /** |
| * Find the library with the given name. Searches the given path and then |
| * the system search path. Returns the full path to the library if it is |
| * found. Otherwise, the empty string is returned. |
| */ |
| std::string SystemTools::FindLibrary(const std::string& name, |
| const std::vector<std::string>& userPaths) |
| { |
| // See if the executable exists as written. |
| if (SystemTools::FileExists(name, true)) { |
| return SystemTools::CollapseFullPath(name); |
| } |
| |
| // Add the system search path to our path. |
| std::vector<std::string> path; |
| SystemTools::GetPath(path); |
| // now add the additional paths |
| path.reserve(path.size() + userPaths.size()); |
| path.insert(path.end(), userPaths.begin(), userPaths.end()); |
| // Add a trailing slash to all paths to aid the search process. |
| for (std::string& p : path) { |
| if (p.empty() || p.back() != '/') { |
| p += '/'; |
| } |
| } |
| std::string tryPath; |
| for (std::string const& p : path) { |
| #if defined(__APPLE__) |
| tryPath = p; |
| tryPath += name; |
| tryPath += ".framework"; |
| if (SystemTools::FileIsDirectory(tryPath)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| #endif |
| #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) |
| tryPath = p; |
| tryPath += name; |
| tryPath += ".lib"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| #else |
| tryPath = p; |
| tryPath += "lib"; |
| tryPath += name; |
| tryPath += ".so"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| tryPath = p; |
| tryPath += "lib"; |
| tryPath += name; |
| tryPath += ".a"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| tryPath = p; |
| tryPath += "lib"; |
| tryPath += name; |
| tryPath += ".sl"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| tryPath = p; |
| tryPath += "lib"; |
| tryPath += name; |
| tryPath += ".dylib"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| tryPath = p; |
| tryPath += "lib"; |
| tryPath += name; |
| tryPath += ".dll"; |
| if (SystemTools::FileExists(tryPath, true)) { |
| return SystemTools::CollapseFullPath(tryPath); |
| } |
| #endif |
| } |
| |
| // Couldn't find the library. |
| return ""; |
| } |
| |
| std::string SystemTools::GetRealPath(const std::string& path, |
| std::string* errorMessage) |
| { |
| std::string ret; |
| Realpath(path, ret, errorMessage); |
| return ret; |
| } |
| |
| 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::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_GUID_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 |
| } |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::CreateSymlink(const std::string&, const std::string&) |
| { |
| return false; |
| } |
| #else |
| bool SystemTools::CreateSymlink(const std::string& origName, |
| const std::string& newName) |
| { |
| return symlink(origName.c_str(), newName.c_str()) >= 0; |
| } |
| #endif |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| bool SystemTools::ReadSymlink(const std::string&, std::string&) |
| { |
| return false; |
| } |
| #else |
| bool SystemTools::ReadSymlink(const std::string& newName, |
| std::string& origName) |
| { |
| char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1]; |
| int count = static_cast<int>( |
| readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH)); |
| if (count >= 0) { |
| // Add null-terminator. |
| buf[count] = 0; |
| origName = buf; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| #endif |
| |
| int SystemTools::ChangeDirectory(const std::string& dir) |
| { |
| return Chdir(dir); |
| } |
| |
| std::string SystemTools::GetCurrentWorkingDirectory(bool collapse) |
| { |
| char buf[2048]; |
| const char* cwd = Getcwd(buf, 2048); |
| std::string path; |
| if (cwd) { |
| path = cwd; |
| } |
| if (collapse) { |
| return SystemTools::CollapseFullPath(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 = ""; |
| 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 = dir.substr(0, slashPos); |
| } else { |
| file = dir; |
| dir = ""; |
| } |
| } |
| 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::FileExists(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::FileExists(self)) { |
| failures.push_back(self); |
| self = installPrefix; |
| self += "/bin/"; |
| self += exeName; |
| } |
| } |
| if (!SystemTools::FileExists(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; |
| } |
| |
| std::string SystemTools::CollapseFullPath(const std::string& in_relative) |
| { |
| return SystemTools::CollapseFullPath(in_relative, nullptr); |
| } |
| |
| #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)) { |
| SystemTools::Statics->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 : SystemTools::Statics->TranslationMap) { |
| // We need to check of the path is a substring of the other path |
| if (path.find(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)); |
| } |
| } |
| } |
| |
| std::string SystemTools::CollapseFullPath(const std::string& in_path, |
| const char* in_base) |
| { |
| // Use the current working directory as a base path. |
| char buf[2048]; |
| const char* res_in_base = in_base; |
| if (!res_in_base) { |
| if (const char* cwd = Getcwd(buf, 2048)) { |
| res_in_base = cwd; |
| } else { |
| res_in_base = ""; |
| } |
| } |
| |
| return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); |
| } |
| |
| std::string SystemTools::CollapseFullPath(const std::string& in_path, |
| const std::string& 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; |
| // Use the given base path. |
| SystemTools::SplitPath(in_base, 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 = SystemTools::Statics->GetActualCaseForPathCached(newPath); |
| SystemTools::ConvertToUnixSlashes(newPath); |
| #endif |
| // Return the reconstructed path. |
| return newPath; |
| } |
| |
| // 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 = root.substr(0, 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.push_back(std::string(first, last)); |
| first = last + 1; |
| } |
| } |
| |
| // Save the last component unless there were no components. |
| if (last != c) { |
| components.push_back(std::string(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 (std::vector<std::string>::const_iterator 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 != std::string::npos) { |
| std::string ret = fn.substr(0, slash_pos); |
| if (ret.size() == 2 && ret[1] == ':') { |
| return ret + '/'; |
| } |
| if (ret.empty()) { |
| return "/"; |
| } |
| return ret; |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| * 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) { |
| return name.substr(dot_pos); |
| } 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) { |
| return name.substr(dot_pos); |
| } 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) { |
| return name.substr(0, dot_pos); |
| } else { |
| 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) { |
| return name.substr(0, dot_pos); |
| } else { |
| 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 |
| |
| unsigned char* 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; |
| } |
| |
| bool SystemTools::GetShortPath(const std::string& 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 = path.substr(1, path.length() - 2); |
| } |
| |
| 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 false; |
| } else { |
| shortPath = Encoding::ToNarrow(&buffer[0]); |
| return true; |
| } |
| #else |
| shortPath = path; |
| return true; |
| #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; |
| } |
| |
| bool SystemTools::GetPermissions(const char* file, mode_t& mode) |
| { |
| if (!file) { |
| return false; |
| } |
| return SystemTools::GetPermissions(std::string(file), mode); |
| } |
| |
| bool SystemTools::GetPermissions(const std::string& file, mode_t& mode) |
| { |
| #if defined(_WIN32) |
| DWORD attr = |
| GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str()); |
| if (attr == INVALID_FILE_ATTRIBUTES) { |
| return false; |
| } |
| 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 false; |
| } |
| mode = st.st_mode; |
| #endif |
| return true; |
| } |
| |
| bool SystemTools::SetPermissions(const char* file, mode_t mode, |
| bool honor_umask) |
| { |
| if (!file) { |
| return false; |
| } |
| return SystemTools::SetPermissions(std::string(file), mode, honor_umask); |
| } |
| |
| bool SystemTools::SetPermissions(const std::string& file, mode_t mode, |
| bool honor_umask) |
| { |
| if (!SystemTools::PathExists(file)) { |
| return false; |
| } |
| 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 false; |
| } |
| |
| return true; |
| } |
| |
| 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; |
| } |
| std::string s = subdir.substr(0, dir.size()); |
| return SystemTools::ComparePath(s, 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 0; |
| } |
| # 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 0; |
| } |
| |
| lRet = RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, |
| (LPBYTE)szProductType, &dwBufLen); |
| |
| if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) { |
| return 0; |
| } |
| |
| 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) |
| { |
| // 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); |
| |
| 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) |
| { |
| 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); |
| |
| return true; |
| } |
| |
| // These must NOT be initialized. Default initialization to zero is |
| // necessary. |
| static unsigned int SystemToolsManagerCount; |
| SystemToolsStatic* SystemTools::Statics; |
| |
| // 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 |
| SystemTools::Statics = 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 SystemTools::Statics; |
| } |
| |
| } // namespace KWSYS_NAMESPACE |
| |
| #if defined(_MSC_VER) && defined(_DEBUG) |
| # include <crtdbg.h> |
| # include <stdio.h> |
| # include <stdlib.h> |
| namespace KWSYS_NAMESPACE { |
| |
| static int SystemToolsDebugReport(int, char* message, int*) |
| { |
| fprintf(stderr, "%s", message); |
| fflush(stderr); |
| return 1; // no further reporting required |
| } |
| |
| void SystemTools::EnableMSVCDebugHook() |
| { |
| if (SystemTools::HasEnv("DART_TEST_FROM_DART") || |
| SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { |
| _CrtSetReportHook(SystemToolsDebugReport); |
| } |
| } |
| |
| } // namespace KWSYS_NAMESPACE |
| #else |
| namespace KWSYS_NAMESPACE { |
| void SystemTools::EnableMSVCDebugHook() |
| { |
| } |
| } // namespace KWSYS_NAMESPACE |
| #endif |