diff options
Diffstat (limited to 'Source/kwsys/SystemTools.cxx')
-rw-r--r-- | Source/kwsys/SystemTools.cxx | 5521 |
1 files changed, 5521 insertions, 0 deletions
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx new file mode 100644 index 0000000..c6e668d --- /dev/null +++ b/Source/kwsys/SystemTools.cxx @@ -0,0 +1,5521 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#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.hxx) + +#include <iostream> +#include <fstream> +#include <sstream> +#include <set> +#include <vector> + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "RegularExpression.hxx.in" +# include "SystemTools.hxx.in" +# include "Directory.hxx.in" +# include "FStream.hxx.in" +# include "Encoding.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 <sys/stat.h> +#include <time.h> + +#ifdef _MSC_VER +# define umask _umask // Note this is still umask on Borland +#endif + +// support for realpath call +#ifndef _WIN32 +#include <sys/time.h> +#include <utime.h> +#include <limits.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <pwd.h> +#ifndef __VMS +#include <sys/param.h> +#include <termios.h> +#endif +#include <signal.h> /* sigprocmask */ +#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__) +# 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 <io.h> +#include <direct.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, NULL, true); + const char *resolved = normalized.Path(); + if (resolved != NULL) // NULL == No such file. + { + if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) + { + return resolved_path; + } + } + return NULL; // 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::SystemTools::ConvertToWindowsExtendedPath(dir).c_str()); +} +inline int Rmdir(const std::string& dir) +{ + return _wrmdir( + KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(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)) + { + // make sure the drive letter is capital + if(wcslen(&w_buf[0]) > 1 && w_buf[1] == L':') + { + w_buf[0] = towupper(w_buf[0]); + } + std::string tmp = KWSYS_NAMESPACE::Encoding::ToNarrow(&w_buf[0]); + strcpy(buf, tmp.c_str()); + 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 = NULL; + DWORD size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorId, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message, 0, NULL); + *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 = 0) +{ + 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, 0); + return 1.0*double(t.tv_sec) + 0.000001*double(t.tv_usec); +#endif +} + +class SystemToolsTranslationMap : + public std::map<std::string,std::string> +{ +}; + +#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 + } +}; + +class SystemToolsPathCaseMap: + public std::map<std::string, std::string, + SystemToolsPathCaseCmp> {}; +#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"; + } + const char* cpathEnv = SystemTools::GetEnv(env); + if ( !cpathEnv ) + { + return; + } + + std::string pathEnv = cpathEnv; + + // A hack to make the below algorithm work. + if(!pathEnv.empty() && *pathEnv.rbegin() != 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); + } +} + +const char* SystemTools::GetEnv(const char* key) +{ + return getenv(key); +} + +const char* SystemTools::GetEnv(const std::string& key) +{ + return SystemTools::GetEnv(key.c_str()); +} + +bool SystemTools::GetEnv(const char* key, std::string& result) +{ + const char* v = getenv(key); + if(v) + { + result = v; + return true; + } + else + { + return false; + } +} + +bool SystemTools::GetEnv(const std::string& key, std::string& result) +{ + return SystemTools::GetEnv(key.c_str(), result); +} + +//---------------------------------------------------------------------------- + +#if defined(__CYGWIN__) || defined(__GLIBC__) +# define KWSYS_PUTENV_NAME /* putenv("A") removes A. */ +#elif defined(_WIN32) +# define KWSYS_PUTENV_EMPTY /* putenv("A=") removes A. */ +#endif + +#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 != env.npos) + { + std::string name = env.substr(0, pos); + unsetenv(name.c_str()); + } + else + { + unsetenv(env.c_str()); + } + return 0; +} + +#elif defined(KWSYS_PUTENV_EMPTY) || defined(KWSYS_PUTENV_NAME) +/* putenv("A=") or putenv("A") removes A from the environment. */ +static int kwsysUnPutEnv(const std::string& env) +{ + int err = 0; + size_t pos = env.find('='); + size_t const len = pos == env.npos ? env.size() : pos; +# ifdef KWSYS_PUTENV_EMPTY + size_t const sz = len + 2; +# else + size_t const sz = len + 1; +# endif + 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); +# ifdef KWSYS_PUTENV_EMPTY + buf[len] = '='; + buf[len+1] = 0; + if(putenv(buf) < 0) + { + err = errno; + } +# else + buf[len] = 0; + if(putenv(buf) < 0 && errno != EINVAL) + { + err = errno; + } +# endif + if(buf != local_buf) + { + free(buf); + } + if(err) + { + errno = err; + return -1; + } + return 0; +} + +#else +/* Manipulate the "environ" global directly. */ +static int kwsysUnPutEnv(const std::string& env) +{ + size_t pos = env.find('='); + size_t const len = pos == env.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 != env.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 + +/* Order by environment key only (VAR from VAR=VALUE). */ +struct kwsysEnvCompare +{ + bool operator() (const char* l, const char* r) const + { + const char* leq = strchr(l, '='); + const char* req = strchr(r, '='); + size_t llen = leq? (leq-l) : strlen(l); + size_t rlen = req? (req-r) : strlen(r); + if(llen == rlen) + { + return strncmp(l,r,llen) < 0; + } + else + { + return strcmp(l,r) < 0; + } + } +}; + +class kwsysEnv: public std::set<const char*, kwsysEnvCompare> +{ + class Free + { + const char* Env; + public: + Free(const char* env): Env(env) {} + ~Free() { free(const_cast<char*>(this->Env)); } + }; +public: + typedef std::set<const char*, kwsysEnvCompare> derived; + ~kwsysEnv() + { + for(derived::iterator i = this->begin(); i != this->end(); ++i) + { + kwsysUnPutEnv(*i); + free(const_cast<char*>(*i)); + } + } + const char* Release(const char* env) + { + const char* old = 0; + derived::iterator i = this->find(env); + if(i != this->end()) + { + old = *i; + this->erase(i); + } + return old; + } + bool Put(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast<void>(oldEnv); + char* newEnv = strdup(env); + this->insert(newEnv); + return putenv(newEnv) == 0; + } + bool UnPut(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast<void>(oldEnv); + 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(SystemTools::ConvertToWindowsExtendedPath(file).c_str(), + Encoding::ToWide(mode).c_str()); +#else + return fopen(file.c_str(), mode); +#endif +} + +bool SystemTools::MakeDirectory(const char* path) +{ + if(!path) + { + return false; + } + return SystemTools::MakeDirectory(std::string(path)); +} + +bool SystemTools::MakeDirectory(const std::string& path) +{ + if(SystemTools::FileExists(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); + Mkdir(topdir); + 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; + } + } + 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; + } + + SystemTools::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; + } + + SystemTools::ReplaceString(source, replace, strlen(replace), with ? with : ""); +} + +void SystemTools::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(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 + +#if defined(_WIN32) && !defined(__CYGWIN__) +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 == NULL) + { + 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(), + NULL, + &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), + NULL, + &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 , + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + hFile2 = CreateFileW( Encoding::ToWide(file2).c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + 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::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) + return (GetFileAttributesW( + SystemTools::ConvertToWindowsExtendedPath(filename).c_str()) + != INVALID_FILE_ATTRIBUTES); +#else + return access(filename.c_str(), R_OK) == 0; +#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( + SystemTools::ConvertToWindowsExtendedPath(filename).c_str(), + permissions) == 0; +#else + return access(filename.c_str(), permissions) == 0; +#endif +} + +//---------------------------------------------------------------------------- +#ifdef __CYGWIN__ +bool SystemTools::PathCygwinToWin32(const char *path, char *win32_path) +{ + SystemToolsTranslationMap::iterator i = + SystemTools::Cyg2Win32Map->find(path); + + if (i != SystemTools::Cyg2Win32Map->end()) + { + strncpy(win32_path, i->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; + } + SystemToolsTranslationMap::value_type entry(path, win32_path); + SystemTools::Cyg2Win32Map->insert(entry); + } + return win32_path[0] != 0; +} +#endif + +bool SystemTools::Touch(const std::string& filename, bool create) +{ + if (!SystemTools::FileExists(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( + SystemTools::ConvertToWindowsExtendedPath(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 + struct timespec times[2] = {{0,UTIME_OMIT},{0,UTIME_NOW}}; + if(utimensat(AT_FDCWD, filename.c_str(), times, 0) < 0) + { + return false; + } +#else + struct stat st; + if(stat(filename.c_str(), &st) < 0) + { + return false; + } + struct timeval mtime; + gettimeofday(&mtime, 0); +# if KWSYS_CXX_HAS_UTIMES + struct timeval atime; +# if KWSYS_CXX_STAT_HAS_ST_MTIM + atime.tv_sec = st.st_atim.tv_sec; + atime.tv_usec = st.st_atim.tv_nsec/1000; +# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC + atime.tv_sec = st.st_atimespec.tv_sec; + atime.tv_usec = st.st_atimespec.tv_nsec/1000; +# else + atime.tv_sec = st.st_atime; + atime.tv_usec = 0; +# endif + struct timeval times[2] = { atime, mtime }; + if(utimes(filename.c_str(), times) < 0) + { + return false; + } +# else + struct utimbuf times = {st.st_atime, mtime.tv_sec}; + if(utime(filename.c_str(), ×) < 0) + { + return false; + } +# endif +#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( + SystemTools::ConvertToWindowsExtendedPath(f1).c_str(), + GetFileExInfoStandard, &f1d)) + { + return false; + } + if(!GetFileAttributesExW( + SystemTools::ConvertToWindowsExtendedPath(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 0; + } + 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 0; + } + 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 NULL; + } + 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 0; + } + 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 occurence of str2 in str1 +const char* SystemTools::FindLastString(const char* str1, const char* str2) +{ + if (!str1 || !str2) + { + return NULL; + } + + 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 NULL; +} + +// Duplicate string +char* SystemTools::DuplicateString(const char* str) +{ + if (str) + { + char *newstr = new char [strlen(str) + 1]; + return strcpy(newstr, str); + } + return NULL; +} + +// 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), std::string::npos); + + if (max_len > 2) + { + n[middle] = '.'; + if (max_len > 3) + { + n[middle - 1] = '.'; + if (max_len > 4) + { + n[middle + 1] = '.'; + } + } + } + + return n; +} + +//---------------------------------------------------------------------------- +std::vector<kwsys::String> SystemTools::SplitString(const std::string& p, char sep, bool isPath) +{ + std::string path = p; + std::vector<kwsys::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 != path.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) +{ + const char* pathCString = path.c_str(); + bool hasDoubleSlash = false; +#ifdef __VMS + ConvertVMSToUnix(path); +#else + const char* pos0 = pathCString; + const char* pos1 = pathCString+1; + for (std::string::size_type pos = 0; *pos0; ++ pos ) + { + // make sure we don't convert an escaped space to a unix slash + if ( *pos0 == '\\' && *pos1 != ' ' ) + { + path[pos] = '/'; + } + + // Also, reuse the loop to check for slash followed by another slash + if (*pos1 == '/' && *(pos1+1) == '/' && !hasDoubleSlash) + { +#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 ++; + pos1 ++; + } + + if ( hasDoubleSlash ) + { + SystemTools::ReplaceString(path, "//", "/"); + } +#endif + // remove any trailing slash + if(!path.empty()) + { + // if there is a tilda ~ then replace it with HOME + pathCString = path.c_str(); + if(pathCString[0] == '~' && (pathCString[1] == '/' || pathCString[1] == '\0')) + { + const char* homeEnv = SystemTools::GetEnv("HOME"); + if (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.rbegin() == '/') + { + // if it is c:/ then do not remove the trailing slash + if(!((size == 3 && pathCString[1] == ':'))) + { + path.resize(size - 1); + } + } + } +} + +#ifdef _WIN32 +// Convert local paths to UNC style paths +std::wstring +SystemTools::ConvertToWindowsExtendedPath(const std::string &source) +{ + std::wstring wsource = Encoding::ToWide(source); + + // Resolve any relative paths + DWORD wfull_len; + + /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that + * won't return a large enough buffer size if the input is too small */ + wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3; + std::vector<wchar_t> wfull(wfull_len); + GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL); + + /* This should get the correct size without any extra padding from the + * previous size workaround. */ + wfull_len = static_cast<DWORD>(wcslen(&wfull[0])); + + if(wfull_len >= 2 && isalpha(wfull[0]) && wfull[1] == L':') + { /* C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[0]); + } + else if(wfull_len >= 2 && wfull[0] == L'\\' && wfull[1] == L'\\') + { /* Starts with \\ */ + if(wfull_len >= 4 && wfull[2] == L'?' && wfull[3] == L'\\') + { /* Starts with \\?\ */ + if(wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' && + wfull[6] == L'C' && wfull[7] == L'\\') + { /* \\?\UNC\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } + else if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':') + { /* \\?\C:\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } + else if(wfull_len >= 5) + { /* \\?\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]); + } + } + else if(wfull_len >= 4 && wfull[2] == L'.' && wfull[3] == L'\\') + { /* Starts with \\.\ a device name */ + if(wfull_len >= 6 && isalpha(wfull[4]) && wfull[5] == L':') + { /* \\.\C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[4]); + } + else if(wfull_len >= 5) + { /* \\.\Foo\bar\ Device name is left unchanged */ + return std::wstring(&wfull[0]); + } + } + else if(wfull_len >= 3) + { /* \\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]); + } + } + + // If this case has been reached, then the path is invalid. Leave it + // unchanged + return Encoding::ToWide(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; +} + +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)) + { + std::string new_destination = destination; + SystemTools::ConvertToUnixSlashes(new_destination); + new_destination += '/'; + std::string source_name = source; + new_destination += SystemTools::GetFilenameName(source_name); + if(SystemTools::FilesDiffer(source, new_destination)) + { + return SystemTools::CopyFileAlways(source, destination); + } + else + { + // the files are the same so the copy is done return + // true + return true; + } + } + // 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( + SystemTools::ConvertToWindowsExtendedPath(source).c_str(), + GetFileExInfoStandard, + &statSource) == 0) + { + return true; + } + + WIN32_FILE_ATTRIBUTE_DATA statDestination; + if (GetFileAttributesExW( + SystemTools::ConvertToWindowsExtendedPath(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; +} + + +//---------------------------------------------------------------------------- +/** + * Copy a file named by "source" to the file named by "destination". + */ +bool SystemTools::CopyFileAlways(const std::string& source, const std::string& destination) +{ + // If files are the same do not copy + if ( SystemTools::SameFile(source, destination) ) + { + return true; + } + mode_t perm = 0; + bool perms = SystemTools::GetPermissions(source, perm); + std::string real_destination = destination; + + if(SystemTools::FileIsDirectory(source)) + { + SystemTools::MakeDirectory(destination); + } + else + { + const int bufferSize = 4096; + char buffer[bufferSize]; + + // 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); + } + + // Create destination directory + + SystemTools::MakeDirectory(destination_dir); + + // Open files +#if defined(_WIN32) + kwsys::ifstream fin(Encoding::ToNarrow( + SystemTools::ConvertToWindowsExtendedPath(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(real_destination); + +#if defined(_WIN32) + kwsys::ofstream fout(Encoding::ToNarrow( + SystemTools::ConvertToWindowsExtendedPath(real_destination)).c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); +#else + kwsys::ofstream fout(real_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) + { + 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; + } + } + 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; +#ifdef _WIN32 + dir.Load(Encoding::ToNarrow( + SystemTools::ConvertToWindowsExtendedPath(source))); +#else + dir.Load(source); +#endif + 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( + SystemTools::ConvertToWindowsExtendedPath(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 *s1, const char *s2) +{ + // lifted from Graphvis http://www.graphviz.org + while ((*s1 != '\0') + && (tolower(*s1) == tolower(*s2))) + { + s1++; + s2++; + } + + return tolower(*s1) - tolower(*s2); +} + +// 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( + SystemTools::ConvertToWindowsExtendedPath(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( + SystemTools::ConvertToWindowsExtendedPath(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; +} + +bool SystemTools::ConvertDateMacroString(const char *str, time_t *tmt) +{ + if (!str || !tmt || strlen(str) > 11) + { + return false; + } + + struct tm tmt2; + + // __DATE__ + // The compilation date of the current source file. The date is a string + // literal of the form Mmm dd yyyy. The month name Mmm is the same as for + // dates generated by the library function asctime declared in TIME.H. + + // index: 012345678901 + // format: Mmm dd yyyy + // example: Dec 19 2003 + + static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + char buffer[12]; + strcpy(buffer, str); + + buffer[3] = 0; + char *ptr = strstr(month_names, buffer); + if (!ptr) + { + return false; + } + + int month = static_cast<int>((ptr - month_names) / 3); + int day = atoi(buffer + 4); + int year = atoi(buffer + 7); + + tmt2.tm_isdst = -1; + tmt2.tm_hour = 0; + tmt2.tm_min = 0; + tmt2.tm_sec = 0; + tmt2.tm_wday = 0; + tmt2.tm_yday = 0; + tmt2.tm_mday = day; + tmt2.tm_mon = month; + tmt2.tm_year = year - 1900; + + *tmt = mktime(&tmt2); + return true; +} + +bool SystemTools::ConvertTimeStampMacroString(const char *str, time_t *tmt) +{ + if (!str || !tmt || strlen(str) > 26) + { + return false; + } + + struct tm tmt2; + + // __TIMESTAMP__ + // The date and time of the last modification of the current source file, + // expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy, + /// where Ddd is the abbreviated day of the week and Date is an integer + // from 1 to 31. + + // index: 0123456789 + // 0123456789 + // 0123456789 + // format: Ddd Mmm Date hh:mm:ss yyyy + // example: Fri Dec 19 14:34:58 2003 + + static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + char buffer[27]; + strcpy(buffer, str); + + buffer[7] = 0; + char *ptr = strstr(month_names, buffer + 4); + if (!ptr) + { + return false; + } + + int month = static_cast<int>((ptr - month_names) / 3); + int day = atoi(buffer + 8); + int hour = atoi(buffer + 11); + int min = atoi(buffer + 14); + int sec = atoi(buffer + 17); + int year = atoi(buffer + 20); + + tmt2.tm_isdst = -1; + tmt2.tm_hour = hour; + tmt2.tm_min = min; + tmt2.tm_sec = sec; + tmt2.tm_wday = 0; + tmt2.tm_yday = 0; + tmt2.tm_mday = day; + tmt2.tm_mon = month; + tmt2.tm_year = year - 1900; + + *tmt = mktime(&tmt2); + return true; +} + +std::string SystemTools::GetLastSystemError() +{ + int e = errno; + return strerror(e); +} + +#ifdef _WIN32 + +static bool IsJunction(const std::wstring& source) +{ +#ifdef FSCTL_GET_REPARSE_POINT + const DWORD JUNCTION_ATTRS = FILE_ATTRIBUTE_DIRECTORY | + FILE_ATTRIBUTE_REPARSE_POINT; + DWORD attrs = GetFileAttributesW(source.c_str()); + if (attrs == INVALID_FILE_ATTRIBUTES) + { + return false; + } + if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS) + { + return false; + } + + // Adjust privileges so that we can succefully open junction points. + HANDLE token; + TOKEN_PRIVILEGES privs; + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); + LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid); + privs.PrivilegeCount = 1; + privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + CloseHandle(token); + + HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ, + 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (dir == INVALID_HANDLE_VALUE) + { + return false; + } + + // Query whether this is a reparse point or not. + BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_GUID_DATA_BUFFER *reparse_buffer = + (REPARSE_GUID_DATA_BUFFER*) buffer; + DWORD sentinel; + + BOOL success = DeviceIoControl( + dir, FSCTL_GET_REPARSE_POINT, + NULL, 0, + reparse_buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &sentinel, NULL); + + CloseHandle(dir); + + return (success && (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)); +#else + return false; +#endif +} + +static bool DeleteJunction(const std::wstring& source) +{ +#ifdef FSCTL_DELETE_REPARSE_POINT + // Adjust privileges so that we can succefully open junction points as + // read/write. + HANDLE token; + TOKEN_PRIVILEGES privs; + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); + LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid); + privs.PrivilegeCount = 1; + privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + CloseHandle(token); + + HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (dir == INVALID_HANDLE_VALUE) + { + return false; + } + + // Set up the structure so that we can delete the junction. + std::vector<BYTE> buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0); + REPARSE_GUID_DATA_BUFFER *reparse_buffer = + (REPARSE_GUID_DATA_BUFFER*) &buffer[0]; + DWORD sentinel; + + reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + + BOOL success = DeviceIoControl( + dir, FSCTL_DELETE_REPARSE_POINT, + reparse_buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, + NULL, 0, + &sentinel, NULL); + + CloseHandle(dir); + + return !!success; +#else + return false; +#endif +} + +#endif + +bool SystemTools::RemoveFile(const std::string& source) +{ +#ifdef _WIN32 + std::wstring const& ws = + SystemTools::ConvertToWindowsExtendedPath(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; + } + if (IsJunction(ws) && DeleteJunction(ws)) + { + 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; +#ifdef _WIN32 + dir.Load(Encoding::ToNarrow( + SystemTools::ConvertToWindowsExtendedPath(source))); +#else + dir.Load(source); +#endif + 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 SystemTools +::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 + { + for(std::vector<std::string>::const_iterator i = userPaths.begin(); + i != userPaths.end(); ++i) + { + path.push_back(*i); + } + } + // Add a trailing slash to all paths to aid the search process. + { + for(std::vector<std::string>::iterator i = path.begin(); + i != path.end(); ++i) + { + std::string& p = *i; + if(p.empty() || *p.rbegin() != '/') + { + p += "/"; + } + } + } + // now look for the file + std::string tryPath; + for(std::vector<std::string>::const_iterator p = path.begin(); + p != path.end(); ++p) + { + tryPath = *p; + 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 = SystemTools::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 = SystemTools::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.push_back(".com"); + extensions.push_back(".exe"); + + // first try with extensions if the os supports them + for(std::vector<std::string>::iterator i = + extensions.begin(); i != extensions.end(); ++i) + { + tryPath = name; + tryPath += *i; + 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 + { + for(std::vector<std::string>::const_iterator i = + userPaths.begin(); i != userPaths.end(); ++i) + { + path.push_back(*i); + } + } + // Add a trailing slash to all paths to aid the search process. + { + for(std::vector<std::string>::iterator i = path.begin(); + i != path.end(); ++i) + { + std::string& p = *i; + if(p.empty() || *p.rbegin() != '/') + { + p += "/"; + } + } + } + // Try each path + for(std::vector<std::string>::iterator p = path.begin(); + p != path.end(); ++p) + { +#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::vector<std::string>::iterator ext + = extensions.begin(); ext != extensions.end(); ++ext) + { + 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::vector<std::string>::const_iterator it = names.begin(); + it != names.end() ; ++it) + { + // Try to find the program. + std::string result = SystemTools::FindProgram(*it, + 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 + { + for(std::vector<std::string>::const_iterator i = userPaths.begin(); + i != userPaths.end(); ++i) + { + path.push_back(*i); + } + } + // Add a trailing slash to all paths to aid the search process. + { + for(std::vector<std::string>::iterator i = path.begin(); + i != path.end(); ++i) + { + std::string& p = *i; + if(p.empty() || *p.rbegin() != '/') + { + p += "/"; + } + } + } + std::string tryPath; + for(std::vector<std::string>::const_iterator p = path.begin(); + p != path.end(); ++p) + { +#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( + SystemTools::ConvertToWindowsExtendedPath(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 ) + DWORD attr = GetFileAttributesW( + SystemTools::ConvertToWindowsExtendedPath(name).c_str()); + if (attr != INVALID_FILE_ATTRIBUTES) + { + return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + else + { + return false; + } +#else + struct stat fs; + if(lstat(name.c_str(), &fs) == 0) + { + return S_ISLNK(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"; + std::vector<std::string>::iterator i; + for(i=failures.begin(); i != failures.end(); ++i) + { + msg << " \"" << *i << "\"\n"; + } + errorMsg = msg.str(); + return false; + } + pathOut = self; + return true; +} + + +std::string SystemTools::CollapseFullPath(const std::string& in_relative) +{ + return SystemTools::CollapseFullPath(in_relative, 0); +} + +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.rbegin() != '/') + { + path_a += '/'; + } + if(!path_b.empty() && *path_b.rbegin() != '/') + { + path_b += '/'; + } + if( !(path_a == path_b) ) + { + SystemTools::TranslationMap->insert( + SystemToolsTranslationMap::value_type(path_a, path_b)); + } + } + } +} + +void SystemTools::AddKeepPath(const std::string& dir) +{ + std::string cdir; + Realpath(SystemTools::CollapseFullPath(dir).c_str(), 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: + std::map<std::string,std::string>::const_iterator it; + for(it = SystemTools::TranslationMap->begin(); + it != SystemTools::TranslationMap->end(); + ++it ) + { + // We need to check of the path is a substring of the other path + if(path.find( it->first ) == 0) + { + path = path.replace( 0, it->first.size(), it->second); + } + } + + // Remove the trailing slash we added before. + path.erase(path.end()-1, path.end()); +} + +static void +SystemToolsAppendComponents( + std::vector<std::string>& out_components, + std::vector<std::string>::const_iterator first, + std::vector<std::string>::const_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) + { + if(out_components.size() > 1) + { + out_components.resize(out_components.size()-1); + } + } + else if(!i->empty() && *i != cur) + { + out_components.push_back(*i); + } + } +} + +std::string SystemTools::CollapseFullPath(const std::string& in_path, + const char* 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); + + // If the input path is relative, start with a base path. + if(path_components[0].length() == 0) + { + std::vector<std::string> base_components; + if(in_base) + { + // Use the given base path. + SystemTools::SplitPath(in_base, base_components); + } + else + { + // Use the current working directory as a base path. + char buf[2048]; + if(const char* cwd = Getcwd(buf, 2048)) + { + SystemTools::SplitPath(cwd, base_components); + } + else + { + base_components.push_back(""); + } + } + + // 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); + + // 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); +#ifdef _WIN32 + newPath = SystemTools::GetActualCaseForPath(newPath); + SystemTools::ConvertToUnixSlashes(newPath); +#endif + // Return the reconstructed path. + return newPath; +} + +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); + + // If the input path is relative, start with a base path. + if(path_components[0].length() == 0) + { + 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); + + // 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); +#ifdef _WIN32 + newPath = SystemTools::GetActualCaseForPath(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<kwsys::String> localSplit = SystemTools::SplitString(l, '/', true); + std::vector<kwsys::String> remoteSplit = SystemTools::SplitString(r, '/', true); + std::vector<kwsys::String> commonPath; // store shared parts of path in this array + std::vector<kwsys::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(unsigned int i = 0; i < localSplit.size(); ++i) + { + if(!localSplit[i].empty()) + { + finalPath.push_back("../"); + } + } + // for each entry that is not common in the remote path add it + // to the final path. + for(std::vector<String>::iterator vit = remoteSplit.begin(); + vit != remoteSplit.end(); ++vit) + { + if(!vit->empty()) + { + finalPath.push_back(*vit); + } + } + 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::vector<String>::iterator vit1 = finalPath.begin(); + vit1 != finalPath.end(); ++vit1) + { + if(!relativePath.empty() && *relativePath.rbegin() != '/') + { + relativePath += "/"; + } + relativePath += *vit1; + } + return relativePath; +} + +#ifdef _WIN32 +static int GetCasePathName(const std::string & pathIn, + std::string & casePath) +{ + std::vector<std::string> path_components; + SystemTools::SplitPath(pathIn, path_components); + if(path_components[0].empty()) // First component always exists. + { + // Relative paths cannot be converted. + casePath = ""; + return 0; + } + + // 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 = "/"; + } + + for(; idx < path_components.size(); idx++) + { + casePath += sep; + sep = "/"; + std::string test_str = casePath; + test_str += path_components[idx]; + + // 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) + { + casePath = ""; + return 0; + } + + WIN32_FIND_DATAW findData; + HANDLE hFind = ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), + &findData); + if (INVALID_HANDLE_VALUE != hFind) + { + casePath += Encoding::ToNarrow(findData.cFileName); + ::FindClose(hFind); + } + else + { + casePath = ""; + return 0; + } + } + return (int)casePath.size(); +} +#endif + + +//---------------------------------------------------------------------------- +std::string SystemTools::GetActualCaseForPath(const std::string& p) +{ +#ifndef _WIN32 + return p; +#else + // Check to see if actual case has already been called + // for this path, and the result is stored in the PathCaseMap + SystemToolsPathCaseMap::iterator i = + SystemTools::PathCaseMap->find(p); + if(i != SystemTools::PathCaseMap->end()) + { + return i->second; + } + std::string casePath; + int len = GetCasePathName(p, casePath); + if(len == 0 || len > MAX_PATH+1) + { + return p; + } + (*SystemTools::PathCaseMap)[p] = casePath; + return casePath; +#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(const char* userp = getenv("USERPROFILE")) + { + homedir = userp; + } + else +#endif + if(const char* h = getenv("HOME")) + { + homedir = h; + } + } +#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.rbegin() == '/' || + *homedir.rbegin() == '\\')) + { + 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; + std::vector<std::string>::const_iterator i; + for(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.append("/"); + 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) + { + // Line ends at end of string without a newline. + lines.push_back(data.substr(lpos)); + return false; + } + else + { + // Line ends in a "\n", 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) + std::string::size_type slash_pos = filename.find_last_of("/\\"); +#else + std::string::size_type slash_pos = filename.rfind('/'); +#endif + 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.rbegin() == ':') +#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 SystemTools::FileIsFullPath(in_name.c_str(), in_name.size()); +} + +bool SystemTools::FileIsFullPath(const char* in_name) +{ + return SystemTools::FileIsFullPath(in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0); +} + +bool SystemTools::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.rbegin() == '"') + { + tempPath = path.substr(1, path.length()-2); + } + + std::wstring wtempPath = Encoding::ToWide(tempPath); + DWORD ret = GetShortPathNameW(wtempPath.c_str(), NULL, 0); + std::vector<wchar_t> buffer(ret); + 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 +} + +void SystemTools::SplitProgramFromArgs(const std::string& path, + std::string& program, std::string& args) +{ + // see if this is a full path to a program + // if so then set program to path and args to nothing + if(SystemTools::FileExists(path)) + { + program = path; + args = ""; + return; + } + // Try to find the program in the path, note the program + // may have spaces in its name so we have to look for it + std::vector<std::string> e; + std::string findProg = SystemTools::FindProgram(path, e); + if(!findProg.empty()) + { + program = findProg; + args = ""; + return; + } + + // Now try and peel off space separated chunks from the end of the string + // so the largest path possible is found allowing for spaces in the path + std::string dir = path; + std::string::size_type spacePos = dir.rfind(' '); + while(spacePos != std::string::npos) + { + std::string tryProg = dir.substr(0, spacePos); + // See if the file exists + if(SystemTools::FileExists(tryProg)) + { + program = tryProg; + // remove trailing spaces from program + std::string::size_type pos = program.size()-1; + while(program[pos] == ' ') + { + program.erase(pos); + pos--; + } + args = dir.substr(spacePos, dir.size()-spacePos); + return; + } + // Now try and find the program in the path + findProg = SystemTools::FindProgram(tryProg, e); + if(!findProg.empty()) + { + program = findProg; + // remove trailing spaces from program + std::string::size_type pos = program.size()-1; + while(program[pos] == ' ') + { + program.erase(pos); + pos--; + } + args = dir.substr(spacePos, dir.size()-spacePos); + return; + } + // move past the space for the next search + spacePos--; + spacePos = dir.rfind(' ', spacePos); + } + + program = ""; + args = ""; +} + +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; +} + +// Due to a buggy stream library on the HP and another on Mac OS X, we +// need this very carefully written version of getline. 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 */) +{ + const int bufferSize = 1024; + char buffer[bufferSize]; + bool haveData = false; + bool haveNewline = false; + + // Start with an empty line. + line = ""; + + long leftToRead = sizeLimit; + + // 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; + } + + // If no characters are read from the stream, the end of file has + // been reached. Clear the fail bit just before reading. + while(!haveNewline && + leftToRead != 0 && + (static_cast<void>(is.clear(is.rdstate() & ~std::ios::failbit)), + static_cast<void>(is.getline(buffer, bufferSize)), + is.gcount() > 0)) + { + // We have read at least one byte. + haveData = true; + + // If newline character was read the gcount includes the character + // but the buffer does not: the end of line has been reached. + size_t length = strlen(buffer); + if(length < static_cast<size_t>(is.gcount())) + { + haveNewline = true; + } + + // Avoid storing a carriage return character. + if(length > 0 && buffer[length-1] == '\r') + { + buffer[length-1] = 0; + } + + // if we read too much then truncate the buffer + if (leftToRead > 0) + { + if (static_cast<long>(length) > leftToRead) + { + buffer[leftToRead-1] = 0; + leftToRead = 0; + } + else + { + leftToRead -= static_cast<long>(length); + } + } + + // Append the data read to the line. + line.append(buffer); + } + + // Return the results. + if(has_newline) + { + *has_newline = haveNewline; + } + return haveData; +} + +int SystemTools::GetTerminalWidth() +{ + int width = -1; +#ifdef HAVE_TTY_INFO + struct winsize ws; + char *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; + } + columns = getenv("COLUMNS"); + if(columns && *columns) + { + long t; + char *endptr; + t = strtol(columns, &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( + SystemTools::ConvertToWindowsExtendedPath(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 == file.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) +{ + // TEMPORARY / TODO: After FileExists calls lstat() instead of + // access(), change this call to FileExists instead of + // TestFileAccess so that we don't follow symlinks. + if ( !SystemTools::TestFileAccess(file, TEST_FILE_OK) ) + { + return false; + } + if (honor_umask) + { + mode_t currentMask = umask(0); + umask(currentMask); + mode &= ~currentMask; + } +#ifdef _WIN32 + if ( _wchmod(SystemTools::ConvertToWindowsExtendedPath(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() && subdir[dir.size()] == '/') + { + std::string s = subdir.substr(0, dir.size()); + return SystemTools::ComparePath(s, dir); + } + return false; +} + +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) +# else +# pragma warning (disable:4996) +# endif +#endif + bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA *)&osvi); + if (!bOsVersionInfoEx) + { + return 0; + } +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning (pop) +#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", NULL, NULL, + (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; +SystemToolsTranslationMap *SystemTools::TranslationMap; +#ifdef _WIN32 +SystemToolsPathCaseMap *SystemTools::PathCaseMap; +#endif +#ifdef __CYGWIN__ +SystemToolsTranslationMap *SystemTools::Cyg2Win32Map; +#endif + +// 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 + // Allocate the translation map first. + SystemTools::TranslationMap = new SystemToolsTranslationMap; +#ifdef _WIN32 + SystemTools::PathCaseMap = new SystemToolsPathCaseMap; +#endif +#ifdef __CYGWIN__ + SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap; +#endif + + // 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. + if(const char* pwd = getenv("PWD")) + { + 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 pwd_str = pwd; + std::string cwd_str = cwd; + std::string pwd_path; + Realpath(pwd, 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.c_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 +} + +void SystemTools::ClassFinalize() +{ + delete SystemTools::TranslationMap; +#ifdef _WIN32 + delete SystemTools::PathCaseMap; +#endif +#ifdef __CYGWIN__ + delete SystemTools::Cyg2Win32Map; +#endif +} + + +} // 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 (getenv("DART_TEST_FROM_DART") || + getenv("DASHBOARD_TEST_FROM_CTEST")) + { + _CrtSetReportHook(SystemToolsDebugReport); + } +} + +} // namespace KWSYS_NAMESPACE +#else +namespace KWSYS_NAMESPACE +{ +void SystemTools::EnableMSVCDebugHook() {} +} // namespace KWSYS_NAMESPACE +#endif |