diff options
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r-- | Source/cmSystemTools.cxx | 2948 |
1 files changed, 2948 insertions, 0 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx new file mode 100644 index 000000000..89f03f62c --- /dev/null +++ b/Source/cmSystemTools.cxx @@ -0,0 +1,2948 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + 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. +============================================================================*/ +#if defined(_MSC_VER) && _MSC_VER < 1300 +# define _WIN32_WINNT 0x0400 /* for wincrypt.h */ +#endif +#include "cmSystemTools.h" +#include <ctype.h> +#include <errno.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#ifdef __QNX__ +# include <malloc.h> /* for malloc/free on QNX */ +#endif +#include <cmsys/Glob.hxx> +#include <cmsys/RegularExpression.hxx> +#include <cmsys/Directory.hxx> +#include <cmsys/System.h> +#if defined(CMAKE_BUILD_WITH_CMAKE) +# include "cmArchiveWrite.h" +# include <cm_libarchive.h> +# include <cmsys/Terminal.h> +#endif +#include <cmsys/stl/algorithm> + +#if defined(_WIN32) +# include <windows.h> +# include <wincrypt.h> +#else +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +# include <utime.h> +# include <sys/wait.h> +#endif + +#include <sys/stat.h> + +#if defined(_WIN32) && \ + (defined(_MSC_VER) || defined(__WATCOMC__) || \ + defined(__BORLANDC__) || defined(__MINGW32__)) +# include <io.h> +#endif + +#if defined(CMAKE_BUILD_WITH_CMAKE) +# include <memory> // auto_ptr +# include <fcntl.h> +# include "cmCryptoHash.h" +#endif + +#if defined(CMAKE_USE_ELF_PARSER) +# include "cmELF.h" +#endif + +class cmSystemToolsFileTime +{ +public: +#if defined(_WIN32) && !defined(__CYGWIN__) + FILETIME timeCreation; + FILETIME timeLastAccess; + FILETIME timeLastWrite; +#else + struct utimbuf timeBuf; +#endif +}; + +#if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 1375 /* base class destructor not virtual */ +#endif + +#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE) +// For GetEnvironmentVariables +# if defined(_WIN32) +extern __declspec( dllimport ) char** environ; +# else +extern char** environ; +# endif +#endif + +#ifdef _WIN32 +class cmSystemToolsWindowsHandle +{ +public: + cmSystemToolsWindowsHandle(HANDLE h): handle_(h) {} + ~cmSystemToolsWindowsHandle() + { + if(this->handle_ != INVALID_HANDLE_VALUE) + { + CloseHandle(this->handle_); + } + } + operator bool() const { return this->handle_ != INVALID_HANDLE_VALUE; } + bool operator !() const { return this->handle_ == INVALID_HANDLE_VALUE; } + operator HANDLE() const { return this->handle_; } +private: + HANDLE handle_; +}; +#elif defined(__APPLE__) +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) +#endif + +bool cmSystemTools::s_RunCommandHideConsole = false; +bool cmSystemTools::s_DisableRunCommandOutput = false; +bool cmSystemTools::s_ErrorOccured = false; +bool cmSystemTools::s_FatalErrorOccured = false; +bool cmSystemTools::s_DisableMessages = false; +bool cmSystemTools::s_ForceUnixPaths = false; + +std::string cmSystemTools::s_Windows9xComspecSubstitute = "command.com"; +void cmSystemTools::SetWindows9xComspecSubstitute(const char* str) +{ + if ( str ) + { + cmSystemTools::s_Windows9xComspecSubstitute = str; + } +} +const char* cmSystemTools::GetWindows9xComspecSubstitute() +{ + return cmSystemTools::s_Windows9xComspecSubstitute.c_str(); +} + +void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, + bool&, void*); +void (*cmSystemTools::s_StdoutCallback)(const char*, int len, void*); +void* cmSystemTools::s_ErrorCallbackClientData = 0; +void* cmSystemTools::s_StdoutCallbackClientData = 0; +bool (*cmSystemTools::s_InterruptCallback)(void*); +void* cmSystemTools::s_InterruptCallbackClientData = 0; + +// replace replace with with as many times as it shows up in source. +// write the result into source. +#if defined(_WIN32) && !defined(__CYGWIN__) +void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view) +{ + // Regular expression to match anything inside [...] that begins in HKEY. + // Note that there is a special rule for regular expressions to match a + // close square-bracket inside a list delimited by square brackets. + // The "[^]]" part of this expression will match any character except + // a close square-bracket. The ']' character must be the first in the + // list of characters inside the [^...] block of the expression. + cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]"); + + // check for black line or comment + while (regEntry.find(source)) + { + // the arguments are the second match + std::string key = regEntry.match(1); + std::string val; + if (ReadRegistryValue(key.c_str(), val, view)) + { + std::string reg = "["; + reg += key + "]"; + cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str()); + } + else + { + std::string reg = "["; + reg += key + "]"; + cmSystemTools::ReplaceString(source, reg.c_str(), "/registry"); + } + } +} +#else +void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64) +{ + cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]"); + while (regEntry.find(source)) + { + // the arguments are the second match + std::string key = regEntry.match(1); + std::string val; + std::string reg = "["; + reg += key + "]"; + cmSystemTools::ReplaceString(source, reg.c_str(), "/registry"); + } + +} +#endif + +std::string cmSystemTools::EscapeQuotes(const char* str) +{ + std::string result = ""; + for(const char* ch = str; *ch != '\0'; ++ch) + { + if(*ch == '"') + { + result += '\\'; + } + result += *ch; + } + return result; +} + +std::string cmSystemTools::TrimWhitespace(const std::string& s) +{ + std::string::const_iterator start = s.begin(); + while(start != s.end() && *start == ' ') + ++start; + if (start == s.end()) + return ""; + + std::string::const_iterator stop = s.end()-1; + while(*stop == ' ') + --stop; + return std::string(start, stop+1); +} + +void cmSystemTools::Error(const char* m1, const char* m2, + const char* m3, const char* m4) +{ + std::string message = "CMake Error: "; + if(m1) + { + message += m1; + } + if(m2) + { + message += m2; + } + if(m3) + { + message += m3; + } + if(m4) + { + message += m4; + } + cmSystemTools::s_ErrorOccured = true; + cmSystemTools::Message(message.c_str(),"Error"); +} + +void cmSystemTools::SetInterruptCallback(InterruptCallback f, void* clientData) +{ + s_InterruptCallback = f; + s_InterruptCallbackClientData = clientData; +} + +bool cmSystemTools::GetInterruptFlag() +{ + if(s_InterruptCallback) + { + return (*s_InterruptCallback)(s_InterruptCallbackClientData); + } + return false; +} + +void cmSystemTools::SetErrorCallback(ErrorCallback f, void* clientData) +{ + s_ErrorCallback = f; + s_ErrorCallbackClientData = clientData; +} + +void cmSystemTools::SetStdoutCallback(StdoutCallback f, void* clientData) +{ + s_StdoutCallback = f; + s_StdoutCallbackClientData = clientData; +} + +void cmSystemTools::Stdout(const char* s) +{ + if(s_StdoutCallback) + { + (*s_StdoutCallback)(s, static_cast<int>(strlen(s)), + s_StdoutCallbackClientData); + } + else + { + std::cout << s; + std::cout.flush(); + } +} + +void cmSystemTools::Stderr(const char* s, int length) +{ + std::cerr.write(s, length); + std::cerr.flush(); +} + +void cmSystemTools::Stdout(const char* s, int length) +{ + if(s_StdoutCallback) + { + (*s_StdoutCallback)(s, length, s_StdoutCallbackClientData); + } + else + { + std::cout.write(s, length); + std::cout.flush(); + } +} + +void cmSystemTools::Message(const char* m1, const char *title) +{ + if(s_DisableMessages) + { + return; + } + if(s_ErrorCallback) + { + (*s_ErrorCallback)(m1, title, s_DisableMessages, + s_ErrorCallbackClientData); + return; + } + else + { + std::cerr << m1 << std::endl << std::flush; + } + +} + + +void cmSystemTools::ReportLastSystemError(const char* msg) +{ + std::string m = msg; + m += ": System Error: "; + m += Superclass::GetLastSystemError(); + cmSystemTools::Error(m.c_str()); +} + +bool cmSystemTools::IsInternallyOn(const char* val) +{ + if (!val) + { + return false; + } + std::basic_string<char> v = val; + + for(std::basic_string<char>::iterator c = v.begin(); + c != v.end(); c++) + { + *c = static_cast<char>(toupper(*c)); + } + return (v == "I_ON" || v == "i_on"); +} + +bool cmSystemTools::IsOn(const char* val) +{ + if (!val) + { + return false; + } + std::basic_string<char> v = val; + + for(std::basic_string<char>::iterator c = v.begin(); + c != v.end(); c++) + { + *c = static_cast<char>(toupper(*c)); + } + return (v == "ON" || v == "1" || v == "YES" || v == "TRUE" || v == "Y"); +} + +bool cmSystemTools::IsNOTFOUND(const char* val) +{ + size_t len = strlen(val); + const char* notfound = "-NOTFOUND"; + const size_t lenNotFound = 9; + if(len < lenNotFound-1) + { + return false; + } + if(len == lenNotFound-1) + { + return ( strcmp(val, "NOTFOUND") == 0); + } + return ((strncmp((val + (len - lenNotFound)), notfound, lenNotFound) == 0)); +} + + +bool cmSystemTools::IsOff(const char* val) +{ + if (!val || strlen(val) == 0) + { + return true; + } + std::basic_string<char> v = val; + + for(std::basic_string<char>::iterator c = v.begin(); + c != v.end(); c++) + { + *c = static_cast<char>(toupper(*c)); + } + return (v == "OFF" || v == "0" || v == "NO" || v == "FALSE" || + v == "N" || cmSystemTools::IsNOTFOUND(v.c_str()) || v == "IGNORE"); +} + +//---------------------------------------------------------------------------- +void cmSystemTools::ParseWindowsCommandLine(const char* command, + std::vector<std::string>& args) +{ + // See the MSDN document "Parsing C Command-Line Arguments" at + // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules + // of parsing the windows command line. + + bool in_argument = false; + bool in_quotes = false; + int backslashes = 0; + std::string arg; + for(const char* c = command;*c; ++c) + { + if(*c == '\\') + { + ++backslashes; + in_argument = true; + } + else if(*c == '"') + { + int backslash_pairs = backslashes >> 1; + int backslash_escaped = backslashes & 1; + arg.append(backslash_pairs, '\\'); + backslashes = 0; + if(backslash_escaped) + { + /* An odd number of backslashes precede this quote. + It is escaped. */ + arg.append(1, '"'); + } + else + { + /* An even number of backslashes precede this quote. + It is not escaped. */ + in_quotes = !in_quotes; + } + in_argument = true; + } + else + { + arg.append(backslashes, '\\'); + backslashes = 0; + if(isspace(*c)) + { + if(in_quotes) + { + arg.append(1, *c); + } + else if(in_argument) + { + args.push_back(arg); + arg = ""; + in_argument = false; + } + } + else + { + in_argument = true; + arg.append(1, *c); + } + } + } + arg.append(backslashes, '\\'); + if(in_argument) + { + args.push_back(arg); + } +} + +//---------------------------------------------------------------------------- +class cmSystemToolsArgV +{ + char** ArgV; +public: + cmSystemToolsArgV(char** argv): ArgV(argv) {} + ~cmSystemToolsArgV() + { + for(char** arg = this->ArgV; arg && *arg; ++arg) + { + free(*arg); + } + free(this->ArgV); + } + void Store(std::vector<std::string>& args) const + { + for(char** arg = this->ArgV; arg && *arg; ++arg) + { + args.push_back(*arg); + } + } + void Store(std::vector<cmStdString>& args) const + { + for(char** arg = this->ArgV; arg && *arg; ++arg) + { + args.push_back(*arg); + } + } +}; + +//---------------------------------------------------------------------------- +void cmSystemTools::ParseUnixCommandLine(const char* command, + std::vector<std::string>& args) +{ + // Invoke the underlying parser. + cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0); + argv.Store(args); +} + +//---------------------------------------------------------------------------- +void cmSystemTools::ParseUnixCommandLine(const char* command, + std::vector<cmStdString>& args) +{ + // Invoke the underlying parser. + cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0); + argv.Store(args); +} + +std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg, + int shell_flags) +{ + char local_buffer[1024]; + char* buffer = local_buffer; + int size = cmsysSystem_Shell_GetArgumentSizeForWindows(arg, shell_flags); + if(size > 1024) + { + buffer = new char[size]; + } + cmsysSystem_Shell_GetArgumentForWindows(arg, buffer, shell_flags); + std::string result(buffer); + if(buffer != local_buffer) + { + delete [] buffer; + } + return result; +} + +std::vector<cmStdString> cmSystemTools::ParseArguments(const char* command) +{ + std::vector<cmStdString> args; + std::string arg; + + bool win_path = false; + + if ((command[0] != '/' && command[1] == ':' && command[2] == '\\') || + (command[0] == '\"' && command[1] != '/' && command[2] == ':' + && command[3] == '\\') || + (command[0] == '\'' && command[1] != '/' && command[2] == ':' + && command[3] == '\\') || + (command[0] == '\\' && command[1] == '\\')) + { + win_path = true; + } + // Split the command into an argv array. + for(const char* c = command; *c;) + { + // Skip over whitespace. + while(*c == ' ' || *c == '\t') + { + ++c; + } + arg = ""; + if(*c == '"') + { + // Parse a quoted argument. + ++c; + while(*c && *c != '"') + { + arg.append(1, *c); + ++c; + } + if(*c) + { + ++c; + } + args.push_back(arg); + } + else if(*c == '\'') + { + // Parse a quoted argument. + ++c; + while(*c && *c != '\'') + { + arg.append(1, *c); + ++c; + } + if(*c) + { + ++c; + } + args.push_back(arg); + } + else if(*c) + { + // Parse an unquoted argument. + while(*c && *c != ' ' && *c != '\t') + { + if(*c == '\\' && !win_path) + { + ++c; + if(*c) + { + arg.append(1, *c); + ++c; + } + } + else + { + arg.append(1, *c); + ++c; + } + } + args.push_back(arg); + } + } + + return args; +} + + +bool cmSystemTools::RunSingleCommand(std::vector<cmStdString>const& command, + std::string* output , + int* retVal , const char* dir , + OutputOption outputflag , + double timeout ) +{ + std::vector<const char*> argv; + for(std::vector<cmStdString>::const_iterator a = command.begin(); + a != command.end(); ++a) + { + argv.push_back(a->c_str()); + } + argv.push_back(0); + if ( output ) + { + *output = ""; + } + + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, &*argv.begin()); + cmsysProcess_SetWorkingDirectory(cp, dir); + if(cmSystemTools::GetRunCommandHideConsole()) + { + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + } + + cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_Execute(cp); + + std::vector<char> tempOutput; + char* data; + int length; + int pipe; + if ( output || outputflag != OUTPUT_NONE ) + { + while((pipe = cmsysProcess_WaitForData(cp, &data, &length, 0)) > 0) + { + if(output || outputflag != OUTPUT_NONE) + { + // Translate NULL characters in the output into valid text. + // Visual Studio 7 puts these characters in the output of its + // build process. + for(int i=0; i < length; ++i) + { + if(data[i] == '\0') + { + data[i] = ' '; + } + } + } + if ( output ) + { + tempOutput.insert(tempOutput.end(), data, data+length); + } + if(outputflag != OUTPUT_NONE) + { + if(outputflag == OUTPUT_MERGE) + { + cmSystemTools::Stdout(data, length); + } + else + { + if(pipe == cmsysProcess_Pipe_STDERR) + { + cmSystemTools::Stderr(data, length); + } + else if(pipe == cmsysProcess_Pipe_STDOUT) + { + cmSystemTools::Stdout(data, length); + } + } + } + } + } + + cmsysProcess_WaitForExit(cp, 0); + if ( output && tempOutput.begin() != tempOutput.end()) + { + output->append(&*tempOutput.begin(), tempOutput.size()); + } + + bool result = true; + if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) + { + if ( retVal ) + { + *retVal = cmsysProcess_GetExitValue(cp); + } + else + { + if ( cmsysProcess_GetExitValue(cp) != 0 ) + { + result = false; + } + } + } + else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) + { + const char* exception_str = cmsysProcess_GetExceptionString(cp); + if ( outputflag != OUTPUT_NONE ) + { + std::cerr << exception_str << std::endl; + } + if ( output ) + { + output->append(exception_str, strlen(exception_str)); + } + result = false; + } + else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error) + { + const char* error_str = cmsysProcess_GetErrorString(cp); + if ( outputflag != OUTPUT_NONE ) + { + std::cerr << error_str << std::endl; + } + if ( output ) + { + output->append(error_str, strlen(error_str)); + } + result = false; + } + else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) + { + const char* error_str = "Process terminated due to timeout\n"; + if ( outputflag != OUTPUT_NONE ) + { + std::cerr << error_str << std::endl; + } + if ( output ) + { + output->append(error_str, strlen(error_str)); + } + result = false; + } + + cmsysProcess_Delete(cp); + return result; +} + +bool cmSystemTools::RunSingleCommand( + const char* command, + std::string* output, + int *retVal, + const char* dir, + OutputOption outputflag, + double timeout) +{ + if(s_DisableRunCommandOutput) + { + outputflag = OUTPUT_NONE; + } + + std::vector<cmStdString> args = cmSystemTools::ParseArguments(command); + + if(args.size() < 1) + { + return false; + } + return cmSystemTools::RunSingleCommand(args, output,retVal, + dir, outputflag, timeout); +} +bool cmSystemTools::RunCommand(const char* command, + std::string& output, + const char* dir, + bool verbose, + int timeout) +{ + int dummy; + return cmSystemTools::RunCommand(command, output, dummy, + dir, verbose, timeout); +} + +#if defined(WIN32) && !defined(__CYGWIN__) +#include "cmWin32ProcessExecution.h" +// use this for shell commands like echo and dir +bool RunCommandViaWin32(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose, + int timeout) +{ +#if defined(__BORLANDC__) + return + cmWin32ProcessExecution:: + BorlandRunCommand(command, dir, output, + retVal, + verbose, timeout, + cmSystemTools::GetRunCommandHideConsole()); +#else // Visual studio + ::SetLastError(ERROR_SUCCESS); + if ( ! command ) + { + cmSystemTools::Error("No command specified"); + return false; + } + cmWin32ProcessExecution resProc; + if(cmSystemTools::GetRunCommandHideConsole()) + { + resProc.SetHideWindows(true); + } + + if ( cmSystemTools::GetWindows9xComspecSubstitute() ) + { + resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() ); + } + if ( !resProc.StartProcess(command, dir, verbose) ) + { + output = resProc.GetOutput(); + if(verbose) + { + cmSystemTools::Stdout(output.c_str()); + } + return false; + } + resProc.Wait(timeout); + output = resProc.GetOutput(); + retVal = resProc.GetExitValue(); + return true; +#endif +} + +// use this for shell commands like echo and dir +bool RunCommandViaSystem(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose) +{ + std::cout << "@@ " << command << std::endl; + + std::string commandInDir; + if(dir) + { + commandInDir = "cd "; + commandInDir += cmSystemTools::ConvertToOutputPath(dir); + commandInDir += " && "; + commandInDir += command; + } + else + { + commandInDir = command; + } + command = commandInDir.c_str(); + std::string commandToFile = command; + commandToFile += " > "; + std::string tempFile; + tempFile += _tempnam(0, "cmake"); + + commandToFile += tempFile; + retVal = system(commandToFile.c_str()); + std::ifstream fin(tempFile.c_str()); + if(!fin) + { + if(verbose) + { + std::string errormsg = "RunCommand produced no output: command: \""; + errormsg += command; + errormsg += "\""; + errormsg += "\nOutput file: "; + errormsg += tempFile; + cmSystemTools::Error(errormsg.c_str()); + } + fin.close(); + cmSystemTools::RemoveFile(tempFile.c_str()); + return false; + } + bool multiLine = false; + std::string line; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + output += line; + if(multiLine) + { + output += "\n"; + } + multiLine = true; + } + fin.close(); + cmSystemTools::RemoveFile(tempFile.c_str()); + return true; +} + +#else // We have popen + +// BeOS seems to return from a successful pclose() before the process has +// legitimately exited, or at least before SIGCHLD is thrown...the signal may +// come quite some time after pclose returns! This causes havoc with later +// parts of CMake that expect to catch the signal from other child processes, +// so we explicitly wait to catch it here. This should be safe to do with +// popen() so long as we don't actually collect the zombie process ourselves. +#ifdef __BEOS__ +#include <signal.h> +#undef SIGBUS // this is the same as SIGSEGV on BeOS and causes issues below. +static volatile bool beos_seen_signal = false; +static void beos_popen_workaround(int sig) +{ + beos_seen_signal = true; +} +#endif + +bool RunCommandViaPopen(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose, + int /*timeout*/) +{ + // if only popen worked on windows..... + std::string commandInDir; + if(dir) + { + commandInDir = "cd \""; + commandInDir += dir; + commandInDir += "\" && "; + commandInDir += command; + } + else + { + commandInDir = command; + } +#ifndef __VMS + commandInDir += " 2>&1"; +#endif + command = commandInDir.c_str(); + const int BUFFER_SIZE = 4096; + char buffer[BUFFER_SIZE]; + if(verbose) + { + cmSystemTools::Stdout("running "); + cmSystemTools::Stdout(command); + cmSystemTools::Stdout("\n"); + } + fflush(stdout); + fflush(stderr); + +#ifdef __BEOS__ + beos_seen_signal = false; + signal(SIGCHLD, beos_popen_workaround); +#endif + + FILE* cpipe = popen(command, "r"); + if(!cpipe) + { +#ifdef __BEOS__ + signal(SIGCHLD, SIG_DFL); +#endif + return false; + } + if (!fgets(buffer, BUFFER_SIZE, cpipe)) + { + buffer[0] = 0; + } + while(!feof(cpipe)) + { + if(verbose) + { + cmSystemTools::Stdout(buffer); + } + output += buffer; + if(!fgets(buffer, BUFFER_SIZE, cpipe)) + { + buffer[0] = 0; + } + } + + retVal = pclose(cpipe); + +#ifdef __BEOS__ + for (int i = 0; (!beos_seen_signal) && (i < 3); i++) + { + ::sleep(1); // signals should interrupt this... + } + + if (!beos_seen_signal) + { + signal(SIGCHLD, SIG_DFL); // oh well, didn't happen. Go on anyhow. + } +#endif + + if (WIFEXITED(retVal)) + { + retVal = WEXITSTATUS(retVal); + return true; + } + if (WIFSIGNALED(retVal)) + { + retVal = WTERMSIG(retVal); + cmOStringStream error; + error << "\nProcess terminated due to "; + switch (retVal) + { +#ifdef SIGKILL + case SIGKILL: + error << "SIGKILL"; + break; +#endif +#ifdef SIGFPE + case SIGFPE: + error << "SIGFPE"; + break; +#endif +#ifndef __HAIKU__ +#ifdef SIGBUS + case SIGBUS: + error << "SIGBUS"; + break; +#endif +#endif +#ifdef SIGSEGV + case SIGSEGV: + error << "SIGSEGV"; + break; +#endif + default: + error << "signal " << retVal; + break; + } + output += error.str(); + } + return false; +} + +#endif // endif WIN32 not CYGWIN + + +// run a command unix uses popen (easy) +// windows uses system and ShortPath +bool cmSystemTools::RunCommand(const char* command, + std::string& output, + int &retVal, + const char* dir, + bool verbose, + int timeout) +{ + if(s_DisableRunCommandOutput) + { + verbose = false; + } + +#if defined(WIN32) && !defined(__CYGWIN__) + // if the command does not start with a quote, then + // try to find the program, and if the program can not be + // found use system to run the command as it must be a built in + // shell command like echo or dir + int count = 0; + if(command[0] == '\"') + { + // count the number of quotes + for(const char* s = command; *s != 0; ++s) + { + if(*s == '\"') + { + count++; + if(count > 2) + { + break; + } + } + } + // if there are more than two double quotes use + // GetShortPathName, the cmd.exe program in windows which + // is used by system fails to execute if there are more than + // one set of quotes in the arguments + if(count > 2) + { + cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)"); + if(quoted.find(command)) + { + std::string shortCmd; + std::string cmd = quoted.match(1); + std::string args = quoted.match(2); + if(! cmSystemTools::FileExists(cmd.c_str()) ) + { + shortCmd = cmd; + } + else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) + { + cmSystemTools::Error("GetShortPath failed for " , cmd.c_str()); + return false; + } + shortCmd += " "; + shortCmd += args; + + //return RunCommandViaSystem(shortCmd.c_str(), dir, + // output, retVal, verbose); + //return WindowsRunCommand(shortCmd.c_str(), dir, + //output, retVal, verbose); + return RunCommandViaWin32(shortCmd.c_str(), dir, + output, retVal, verbose, timeout); + } + else + { + cmSystemTools::Error("Could not parse command line with quotes ", + command); + } + } + } + // if there is only one set of quotes or no quotes then just run the command + //return RunCommandViaSystem(command, dir, output, retVal, verbose); + //return WindowsRunCommand(command, dir, output, retVal, verbose); + return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout); +#else + return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout); +#endif +} + +bool cmSystemTools::DoesFileExistWithExtensions( + const char* name, + const std::vector<std::string>& headerExts) +{ + std::string hname; + + for( std::vector<std::string>::const_iterator ext = headerExts.begin(); + ext != headerExts.end(); ++ext ) + { + hname = name; + hname += "."; + hname += *ext; + if(cmSystemTools::FileExists(hname.c_str())) + { + return true; + } + } + return false; +} + +std::string cmSystemTools::FileExistsInParentDirectories(const char* fname, + const char* directory, const char* toplevel) +{ + std::string file = fname; + cmSystemTools::ConvertToUnixSlashes(file); + std::string dir = directory; + cmSystemTools::ConvertToUnixSlashes(dir); + std::string prevDir; + while(dir != prevDir) + { + std::string path = dir + "/" + file; + if ( cmSystemTools::FileExists(path.c_str()) ) + { + return path; + } + if ( dir.size() < strlen(toplevel) ) + { + break; + } + prevDir = dir; + dir = cmSystemTools::GetParentDirectory(dir.c_str()); + } + return ""; +} + +bool cmSystemTools::cmCopyFile(const char* source, const char* destination) +{ + return Superclass::CopyFileAlways(source, destination); +} + +bool cmSystemTools::CopyFileIfDifferent(const char* source, + const char* destination) +{ + return Superclass::CopyFileIfDifferent(source, destination); +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::RenameFile(const char* oldname, const char* newname) +{ +#ifdef _WIN32 + /* On Windows the move functions will not replace existing files. + Check if the destination exists. */ + struct stat newFile; + if(stat(newname, &newFile) == 0) + { + /* The destination exists. We have to replace it carefully. The + MoveFileEx function does what we need but is not available on + Win9x. */ + OSVERSIONINFO osv; + DWORD attrs; + + /* Make sure the destination is not read only. */ + attrs = GetFileAttributes(newname); + if(attrs & FILE_ATTRIBUTE_READONLY) + { + SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY); + } + + /* Check the windows version number. */ + osv.dwOSVersionInfoSize = sizeof(osv); + GetVersionEx(&osv); + if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + /* This is Win9x. There is no MoveFileEx implementation. We + cannot quite rename the file atomically. Just delete the + destination and then move the file. */ + DeleteFile(newname); + return MoveFile(oldname, newname) != 0; + } + else + { + /* This is not Win9x. Use the MoveFileEx implementation. */ + return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING) != 0; + } + } + else + { + /* The destination does not exist. Just move the file. */ + return MoveFile(oldname, newname) != 0; + } +#else + /* On UNIX we have an OS-provided call to do this atomically. */ + return rename(oldname, newname) == 0; +#endif +} + +bool cmSystemTools::ComputeFileMD5(const char* source, char* md5out) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + cmCryptoHashMD5 md5; + std::string str = md5.HashFile(source); + strncpy(md5out, str.c_str(), 32); + return !str.empty(); +#else + (void)source; + (void)md5out; + cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error"); + return false; +#endif +} + +std::string cmSystemTools::ComputeStringMD5(const char* input) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + cmCryptoHashMD5 md5; + return md5.HashString(input); +#else + (void)input; + cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error"); + return ""; +#endif +} + +void cmSystemTools::Glob(const char *directory, const char *regexp, + std::vector<std::string>& files) +{ + cmsys::Directory d; + cmsys::RegularExpression reg(regexp); + + if (d.Load(directory)) + { + size_t numf; + unsigned int i; + numf = d.GetNumberOfFiles(); + for (i = 0; i < numf; i++) + { + std::string fname = d.GetFile(i); + if (reg.find(fname)) + { + files.push_back(fname); + } + } + } +} + + +void cmSystemTools::GlobDirs(const char *fullPath, + std::vector<std::string>& files) +{ + std::string path = fullPath; + std::string::size_type pos = path.find("/*"); + if(pos == std::string::npos) + { + files.push_back(fullPath); + return; + } + std::string startPath = path.substr(0, pos); + std::string finishPath = path.substr(pos+2); + + cmsys::Directory d; + if (d.Load(startPath.c_str())) + { + for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) + { + if((std::string(d.GetFile(i)) != ".") + && (std::string(d.GetFile(i)) != "..")) + { + std::string fname = startPath; + fname +="/"; + fname += d.GetFile(i); + if(cmSystemTools::FileIsDirectory(fname.c_str())) + { + fname += finishPath; + cmSystemTools::GlobDirs(fname.c_str(), files); + } + } + } + } +} + + +void cmSystemTools::ExpandList(std::vector<std::string> const& arguments, + std::vector<std::string>& newargs) +{ + std::vector<std::string>::const_iterator i; + for(i = arguments.begin();i != arguments.end(); ++i) + { + cmSystemTools::ExpandListArgument(*i, newargs); + } +} + +void cmSystemTools::ExpandListArgument(const std::string& arg, + std::vector<std::string>& newargs, + bool emptyArgs) +{ + // If argument is empty, it is an empty list. + if(arg.length() == 0 && !emptyArgs) + { + return; + } + // if there are no ; in the name then just copy the current string + if(arg.find(';') == std::string::npos) + { + newargs.push_back(arg); + return; + } + std::vector<char> newArgVec; + // Break the string at non-escaped semicolons not nested in []. + int squareNesting = 0; + for(const char* c = arg.c_str(); *c; ++c) + { + switch(*c) + { + case '\\': + { + // We only want to allow escaping of semicolons. Other + // escapes should not be processed here. + ++c; + if(*c == ';') + { + newArgVec.push_back(*c); + } + else + { + newArgVec.push_back('\\'); + if(*c) + { + newArgVec.push_back(*c); + } + else + { + // Terminate the loop properly. + --c; + } + } + } break; + case '[': + { + ++squareNesting; + newArgVec.push_back(*c); + } break; + case ']': + { + --squareNesting; + newArgVec.push_back(*c); + } break; + case ';': + { + // Break the string here if we are not nested inside square + // brackets. + if(squareNesting == 0) + { + if ( newArgVec.size() || emptyArgs ) + { + // Add the last argument if the string is not empty. + newArgVec.push_back(0); + newargs.push_back(&*newArgVec.begin()); + newArgVec.clear(); + } + } + else + { + newArgVec.push_back(*c); + } + } break; + default: + { + // Just append this character. + newArgVec.push_back(*c); + } break; + } + } + if ( newArgVec.size() || emptyArgs ) + { + // Add the last argument if the string is not empty. + newArgVec.push_back(0); + newargs.push_back(&*newArgVec.begin()); + } +} + +bool cmSystemTools::SimpleGlob(const cmStdString& glob, + std::vector<cmStdString>& files, + int type /* = 0 */) +{ + files.clear(); + if ( glob[glob.size()-1] != '*' ) + { + return false; + } + std::string path = cmSystemTools::GetFilenamePath(glob); + std::string ppath = cmSystemTools::GetFilenameName(glob); + ppath = ppath.substr(0, ppath.size()-1); + if ( path.size() == 0 ) + { + path = "/"; + } + + bool res = false; + cmsys::Directory d; + if (d.Load(path.c_str())) + { + for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) + { + if((std::string(d.GetFile(i)) != ".") + && (std::string(d.GetFile(i)) != "..")) + { + std::string fname = path; + if ( path[path.size()-1] != '/' ) + { + fname +="/"; + } + fname += d.GetFile(i); + std::string sfname = d.GetFile(i); + if ( type > 0 && cmSystemTools::FileIsDirectory(fname.c_str()) ) + { + continue; + } + if ( type < 0 && !cmSystemTools::FileIsDirectory(fname.c_str()) ) + { + continue; + } + if ( sfname.size() >= ppath.size() && + sfname.substr(0, ppath.size()) == + ppath ) + { + files.push_back(fname); + res = true; + } + } + } + } + return res; +} + +cmSystemTools::FileFormat cmSystemTools::GetFileFormat(const char* cext) +{ + if ( ! cext || *cext == 0 ) + { + return cmSystemTools::NO_FILE_FORMAT; + } + //std::string ext = cmSystemTools::LowerCase(cext); + std::string ext = cext; + if ( ext == "c" || ext == ".c" || + ext == "m" || ext == ".m" + ) { return cmSystemTools::C_FILE_FORMAT; } + if ( + ext == "C" || ext == ".C" || + ext == "M" || ext == ".M" || + ext == "c++" || ext == ".c++" || + ext == "cc" || ext == ".cc" || + ext == "cpp" || ext == ".cpp" || + ext == "cxx" || ext == ".cxx" || + ext == "mm" || ext == ".mm" + ) { return cmSystemTools::CXX_FILE_FORMAT; } + if ( + ext == "f" || ext == ".f" || + ext == "F" || ext == ".F" || + ext == "f77" || ext == ".f77" || + ext == "f90" || ext == ".f90" || + ext == "for" || ext == ".for" || + ext == "f95" || ext == ".f95" + ) { return cmSystemTools::FORTRAN_FILE_FORMAT; } + if ( ext == "java" || ext == ".java" ) + { return cmSystemTools::JAVA_FILE_FORMAT; } + if ( + ext == "H" || ext == ".H" || + ext == "h" || ext == ".h" || + ext == "h++" || ext == ".h++" || + ext == "hm" || ext == ".hm" || + ext == "hpp" || ext == ".hpp" || + ext == "hxx" || ext == ".hxx" || + ext == "in" || ext == ".in" || + ext == "txx" || ext == ".txx" + ) { return cmSystemTools::HEADER_FILE_FORMAT; } + if ( ext == "rc" || ext == ".rc" ) + { return cmSystemTools::RESOURCE_FILE_FORMAT; } + if ( ext == "def" || ext == ".def" ) + { return cmSystemTools::DEFINITION_FILE_FORMAT; } + if ( ext == "lib" || ext == ".lib" || + ext == "a" || ext == ".a") + { return cmSystemTools::STATIC_LIBRARY_FILE_FORMAT; } + if ( ext == "o" || ext == ".o" || + ext == "obj" || ext == ".obj") + { return cmSystemTools::OBJECT_FILE_FORMAT; } +#ifdef __APPLE__ + if ( ext == "dylib" || ext == ".dylib" ) + { return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT; } + if ( ext == "so" || ext == ".so" || + ext == "bundle" || ext == ".bundle" ) + { return cmSystemTools::MODULE_FILE_FORMAT; } +#else // __APPLE__ + if ( ext == "so" || ext == ".so" || + ext == "sl" || ext == ".sl" || + ext == "dll" || ext == ".dll" ) + { return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT; } +#endif // __APPLE__ + return cmSystemTools::UNKNOWN_FILE_FORMAT; +} + +bool cmSystemTools::Split(const char* s, std::vector<cmStdString>& l) +{ + std::vector<std::string> temp; + bool res = Superclass::Split(s, temp); + for(std::vector<std::string>::const_iterator i = temp.begin(); + i != temp.end(); ++i) + { + l.push_back(*i); + } + return res; +} + +std::string cmSystemTools::ConvertToOutputPath(const char* path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if(s_ForceUnixPaths) + { + return cmSystemTools::ConvertToUnixOutputPath(path); + } + return cmSystemTools::ConvertToWindowsOutputPath(path); +#else + return cmSystemTools::ConvertToUnixOutputPath(path); +#endif +} + +void cmSystemTools::ConvertToOutputSlashes(std::string& path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if(!s_ForceUnixPaths) + { + // Convert to windows slashes. + std::string::size_type pos = 0; + while((pos = path.find('/', pos)) != std::string::npos) + { + path[pos++] = '\\'; + } + } +#else + static_cast<void>(path); +#endif +} + +std::string cmSystemTools::ConvertToRunCommandPath(const char* path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return cmSystemTools::ConvertToWindowsOutputPath(path); +#else + return cmSystemTools::ConvertToUnixOutputPath(path); +#endif +} + +bool cmSystemTools::StringEndsWith(const char* str1, const char* str2) +{ + if ( !str1 || !str2 || strlen(str1) < strlen(str2) ) + { + return 0; + } + return !strncmp(str1 + (strlen(str1)-strlen(str2)), str2, strlen(str2)); +} + +// compute the relative path from here to there +std::string cmSystemTools::RelativePath(const char* local, const char* remote) +{ + if(!cmSystemTools::FileIsFullPath(local)) + { + cmSystemTools::Error("RelativePath must be passed a full path to local: ", + local); + } + if(!cmSystemTools::FileIsFullPath(remote)) + { + cmSystemTools::Error + ("RelativePath must be passed a full path to remote: ", remote); + } + return cmsys::SystemTools::RelativePath(local, remote); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +//---------------------------------------------------------------------- +bool cmSystemTools::UnsetEnv(const char* value) +{ +#if !defined(HAVE_UNSETENV) + std::string var = value; + var += "="; + return cmSystemTools::PutEnv(var.c_str()); +#else + unsetenv(value); + return true; +#endif +} + +//---------------------------------------------------------------------- +std::vector<std::string> cmSystemTools::GetEnvironmentVariables() +{ + std::vector<std::string> env; + int cc; + for ( cc = 0; environ[cc]; ++ cc ) + { + env.push_back(environ[cc]); + } + return env; +} + +//---------------------------------------------------------------------- +void cmSystemTools::AppendEnv(std::vector<std::string> const& env) +{ + for(std::vector<std::string>::const_iterator eit = env.begin(); + eit != env.end(); ++eit) + { + cmSystemTools::PutEnv(eit->c_str()); + } +} + +//---------------------------------------------------------------------- +cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment() +{ + this->Env = cmSystemTools::GetEnvironmentVariables(); +} + +//---------------------------------------------------------------------- +cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() +{ + // First clear everything in the current environment: + std::vector<std::string> currentEnv = GetEnvironmentVariables(); + for(std::vector<std::string>::const_iterator + eit = currentEnv.begin(); eit != currentEnv.end(); ++eit) + { + std::string var(*eit); + + std::string::size_type pos = var.find("="); + if (pos != std::string::npos) + { + var = var.substr(0, pos); + } + + cmSystemTools::UnsetEnv(var.c_str()); + } + + // Then put back each entry from the original environment: + cmSystemTools::AppendEnv(this->Env); +} +#endif + +void cmSystemTools::EnableVSConsoleOutput() +{ + // Visual Studio 8 2005 (devenv.exe or VCExpress.exe) will not + // display output to the console unless this environment variable is + // set. We need it to capture the output of these build tools. + // Note for future work that one could pass "/out \\.\pipe\NAME" to + // either of these executables where NAME is created with + // CreateNamedPipe. This would bypass the internal buffering of the + // output and allow it to be captured on the fly. +#ifdef _WIN32 + cmSystemTools::PutEnv("vsconsoleoutput=1"); +#endif +} + +bool cmSystemTools::IsPathToFramework(const char* path) +{ + if(cmSystemTools::FileIsFullPath(path)) + { + std::string libname = path; + if(libname.find(".framework") == libname.size()+1-sizeof(".framework")) + { + return true; + } + } + return false; +} + +bool cmSystemTools::CreateTar(const char* outFileName, + const std::vector<cmStdString>& files, + bool gzip, bool bzip2, bool verbose) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + std::ofstream fout(outFileName, std::ios::out | cmsys_ios_binary); + if(!fout) + { + std::string e = "Cannot open output file \""; + e += outFileName; + e += "\": "; + e += cmSystemTools::GetLastSystemError(); + cmSystemTools::Error(e.c_str()); + return false; + } + cmArchiveWrite a(fout, (gzip? cmArchiveWrite::CompressGZip : + (bzip2? cmArchiveWrite::CompressBZip2 : + cmArchiveWrite::CompressNone)), + cmArchiveWrite::TypeTAR); + a.SetVerbose(verbose); + for(std::vector<cmStdString>::const_iterator i = files.begin(); + i != files.end(); ++i) + { + std::string path = *i; + if(cmSystemTools::FileIsFullPath(path.c_str())) + { + // Get the relative path to the file. + path = cmSystemTools::RelativePath(cwd.c_str(), path.c_str()); + } + if(!a.Add(path)) + { + break; + } + } + if(!a) + { + cmSystemTools::Error(a.GetError().c_str()); + return false; + } + return true; +#else + (void)outFileName; + (void)files; + (void)gzip; + (void)verbose; + return false; +#endif +} + +#if defined(CMAKE_BUILD_WITH_CMAKE) +namespace{ +#define BSDTAR_FILESIZE_PRINTF "%lu" +#define BSDTAR_FILESIZE_TYPE unsigned long + void + list_item_verbose(FILE *out, struct archive_entry *entry) +{ + char tmp[100]; + size_t w; + const char *p; + const char *fmt; + time_t tim; + static time_t now; + size_t u_width = 6; + size_t gs_width = 13; + + /* + * We avoid collecting the entire list in memory at once by + * listing things as we see them. However, that also means we can't + * just pre-compute the field widths. Instead, we start with guesses + * and just widen them as necessary. These numbers are completely + * arbitrary. + */ + if (!now) + { + time(&now); + } + fprintf(out, "%s %d ", + archive_entry_strmode(entry), + archive_entry_nlink(entry)); + + /* Use uname if it's present, else uid. */ + p = archive_entry_uname(entry); + if ((p == NULL) || (*p == '\0')) + { + sprintf(tmp, "%lu ", + (unsigned long)archive_entry_uid(entry)); + p = tmp; + } + w = strlen(p); + if (w > u_width) + { + u_width = w; + } + fprintf(out, "%-*s ", (int)u_width, p); + /* Use gname if it's present, else gid. */ + p = archive_entry_gname(entry); + if (p != NULL && p[0] != '\0') + { + fprintf(out, "%s", p); + w = strlen(p); + } + else + { + sprintf(tmp, "%lu", + (unsigned long)archive_entry_gid(entry)); + w = strlen(tmp); + fprintf(out, "%s", tmp); + } + + /* + * Print device number or file size, right-aligned so as to make + * total width of group and devnum/filesize fields be gs_width. + * If gs_width is too small, grow it. + */ + if (archive_entry_filetype(entry) == AE_IFCHR + || archive_entry_filetype(entry) == AE_IFBLK) + { + sprintf(tmp, "%lu,%lu", + (unsigned long)archive_entry_rdevmajor(entry), + (unsigned long)archive_entry_rdevminor(entry)); + } + else + { + /* + * Note the use of platform-dependent macros to format + * the filesize here. We need the format string and the + * corresponding type for the cast. + */ + sprintf(tmp, BSDTAR_FILESIZE_PRINTF, + (BSDTAR_FILESIZE_TYPE)archive_entry_size(entry)); + } + if (w + strlen(tmp) >= gs_width) + { + gs_width = w+strlen(tmp)+1; + } + fprintf(out, "%*s", (int)(gs_width - w), tmp); + + /* Format the time using 'ls -l' conventions. */ + tim = archive_entry_mtime(entry); +#define HALF_YEAR (time_t)365 * 86400 / 2 +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Windows' strftime function does not support %e format. */ +#define DAY_FMT "%d" +#else +#define DAY_FMT "%e" /* Day number without leading zeros */ +#endif + if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) + { + fmt = DAY_FMT " %b %Y"; + } + else + { + fmt = DAY_FMT " %b %H:%M"; + } + strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); + fprintf(out, " %s ", tmp); + fprintf(out, "%s", archive_entry_pathname(entry)); + + /* Extra information for links. */ + if (archive_entry_hardlink(entry)) /* Hard link */ + { + fprintf(out, " link to %s", + archive_entry_hardlink(entry)); + } + else if (archive_entry_symlink(entry)) /* Symbolic link */ + { + fprintf(out, " -> %s", archive_entry_symlink(entry)); + } +} +#ifdef __BORLANDC__ +# pragma warn -8066 /* unreachable code */ +#endif + +long copy_data(struct archive *ar, struct archive *aw) +{ + long r; + const void *buff; + size_t size; +#if defined(ARCHIVE_VERSION_NUMBER) && ARCHIVE_VERSION_NUMBER >= 3000000 + __LA_INT64_T offset; +#else + off_t offset; +#endif + + for (;;) + { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + { + return (ARCHIVE_OK); + } + if (r != ARCHIVE_OK) + { + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) + { + cmSystemTools::Message("archive_write_data_block()", + archive_error_string(aw)); + return (r); + } + } + return r; +} + +bool extract_tar(const char* outFileName, bool verbose, + bool extract) +{ + struct archive* a = archive_read_new(); + struct archive *ext = archive_write_disk_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + struct archive_entry *entry; + int r = archive_read_open_file(a, outFileName, 10240); + if(r) + { + cmSystemTools::Error("Problem with archive_read_open_file(): ", + archive_error_string(a)); + return false; + } + for (;;) + { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + { + break; + } + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_read_next_header(): ", + archive_error_string(a)); + } + if (verbose && extract) + { + cmSystemTools::Stdout("x "); + cmSystemTools::Stdout(archive_entry_pathname(entry)); + } + if(verbose && !extract) + { + list_item_verbose(stdout, entry); + } + else if(!extract) + { + cmSystemTools::Stdout(archive_entry_pathname(entry)); + } + if(extract) + { + r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME); + if (r != ARCHIVE_OK) + { + cmSystemTools::Error( + "Problem with archive_write_disk_set_options(): ", + archive_error_string(ext)); + } + + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_write_header(): ", + archive_error_string(ext)); + cmSystemTools::Error("Current file:", + archive_entry_pathname(entry)); + } + else + { + copy_data(a, ext); + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + { + cmSystemTools::Error("Problem with archive_write_finish_entry(): ", + archive_error_string(ext)); + } + } + } + if (verbose || !extract) + { + cmSystemTools::Stdout("\n"); + } + } + archive_read_close(a); + archive_read_finish(a); + return true; + +} +} +#endif + +bool cmSystemTools::ExtractTar(const char* outFileName, + bool , bool verbose) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + return extract_tar(outFileName, verbose, true); +#else + (void)outFileName; + (void)verbose; + return false; +#endif +} + +bool cmSystemTools::ListTar(const char* outFileName, + bool , + bool verbose) +{ +#if defined(CMAKE_BUILD_WITH_CMAKE) + return extract_tar(outFileName, verbose, false); +#else + (void)outFileName; + (void)verbose; + return false; +#endif +} + +int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, + double timeout, + std::vector<char>& out, + std::vector<char>& err) +{ + line = ""; + std::vector<char>::iterator outiter = out.begin(); + std::vector<char>::iterator erriter = err.begin(); + while(1) + { + // Check for a newline in stdout. + for(;outiter != out.end(); ++outiter) + { + if((*outiter == '\r') && ((outiter+1) == out.end())) + { + break; + } + else if(*outiter == '\n' || *outiter == '\0') + { + std::vector<char>::size_type length = outiter-out.begin(); + if(length > 1 && *(outiter-1) == '\r') + { + --length; + } + if(length > 0) + { + line.append(&out[0], length); + } + out.erase(out.begin(), outiter+1); + return cmsysProcess_Pipe_STDOUT; + } + } + + // Check for a newline in stderr. + for(;erriter != err.end(); ++erriter) + { + if((*erriter == '\r') && ((erriter+1) == err.end())) + { + break; + } + else if(*erriter == '\n' || *erriter == '\0') + { + std::vector<char>::size_type length = erriter-err.begin(); + if(length > 1 && *(erriter-1) == '\r') + { + --length; + } + if(length > 0) + { + line.append(&err[0], length); + } + err.erase(err.begin(), erriter+1); + return cmsysProcess_Pipe_STDERR; + } + } + + // No newlines found. Wait for more data from the process. + int length; + char* data; + int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout); + if(pipe == cmsysProcess_Pipe_Timeout) + { + // Timeout has been exceeded. + return pipe; + } + else if(pipe == cmsysProcess_Pipe_STDOUT) + { + // Append to the stdout buffer. + std::vector<char>::size_type size = out.size(); + out.insert(out.end(), data, data+length); + outiter = out.begin()+size; + } + else if(pipe == cmsysProcess_Pipe_STDERR) + { + // Append to the stderr buffer. + std::vector<char>::size_type size = err.size(); + err.insert(err.end(), data, data+length); + erriter = err.begin()+size; + } + else if(pipe == cmsysProcess_Pipe_None) + { + // Both stdout and stderr pipes have broken. Return leftover data. + if(!out.empty()) + { + line.append(&out[0], outiter-out.begin()); + out.erase(out.begin(), out.end()); + return cmsysProcess_Pipe_STDOUT; + } + else if(!err.empty()) + { + line.append(&err[0], erriter-err.begin()); + err.erase(err.begin(), err.end()); + return cmsysProcess_Pipe_STDERR; + } + else + { + return cmsysProcess_Pipe_None; + } + } + } +} + +void cmSystemTools::DoNotInheritStdPipes() +{ +#ifdef _WIN32 + // Check to see if we are attached to a console + // if so, then do not stop the inherited pipes + // or stdout and stderr will not show up in dos + // shell windows + CONSOLE_SCREEN_BUFFER_INFO hOutInfo; + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + if(GetConsoleScreenBufferInfo(hOut, &hOutInfo)) + { + return; + } + { + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_OUTPUT_HANDLE, out); + } + { + HANDLE out = GetStdHandle(STD_ERROR_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_ERROR_HANDLE, out); + } +#endif +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + cmSystemToolsWindowsHandle hFrom = + CreateFile(fromFile, GENERIC_READ, FILE_SHARE_READ, 0, + OPEN_EXISTING, 0, 0); + cmSystemToolsWindowsHandle hTo = + CreateFile(toFile, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if(!hFrom || !hTo) + { + return false; + } + FILETIME timeCreation; + FILETIME timeLastAccess; + FILETIME timeLastWrite; + if(!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite)) + { + return false; + } + if(!SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite)) + { + return false; + } +#else + struct stat fromStat; + if(stat(fromFile, &fromStat) < 0) + { + return false; + } + + struct utimbuf buf; + buf.actime = fromStat.st_atime; + buf.modtime = fromStat.st_mtime; + if(utime(toFile, &buf) < 0) + { + return false; + } +#endif + return true; +} + +//---------------------------------------------------------------------------- +cmSystemToolsFileTime* cmSystemTools::FileTimeNew() +{ + return new cmSystemToolsFileTime; +} + +//---------------------------------------------------------------------------- +void cmSystemTools::FileTimeDelete(cmSystemToolsFileTime* t) +{ + delete t; +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + cmSystemToolsWindowsHandle h = + CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if(!h) + { + return false; + } + if(!GetFileTime(h, &t->timeCreation, &t->timeLastAccess, &t->timeLastWrite)) + { + return false; + } +#else + struct stat st; + if(stat(fname, &st) < 0) + { + return false; + } + t->timeBuf.actime = st.st_atime; + t->timeBuf.modtime = st.st_mtime; +#endif + return true; +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + cmSystemToolsWindowsHandle h = + CreateFile(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if(!h) + { + return false; + } + if(!SetFileTime(h, &t->timeCreation, &t->timeLastAccess, &t->timeLastWrite)) + { + return false; + } +#else + if(utime(fname, &t->timeBuf) < 0) + { + return false; + } +#endif + return true; +} + +//---------------------------------------------------------------------------- +#ifdef _WIN32 +# ifndef CRYPT_SILENT +# define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */ +# endif +static int WinCryptRandom(void* data, size_t size) +{ + int result = 0; + HCRYPTPROV hProvider = 0; + if(CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + result = CryptGenRandom(hProvider, (DWORD)size, (BYTE*)data)? 1:0; + CryptReleaseContext(hProvider, 0); + } + return result; +} +#endif + +//---------------------------------------------------------------------------- +unsigned int cmSystemTools::RandomSeed() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + unsigned int seed = 0; + + // Try using a real random source. + if(WinCryptRandom(&seed, sizeof(seed))) + { + return seed; + } + + // Fall back to the time and pid. + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + unsigned int t1 = static_cast<unsigned int>(ft.dwHighDateTime); + unsigned int t2 = static_cast<unsigned int>(ft.dwLowDateTime); + unsigned int pid = static_cast<unsigned int>(GetCurrentProcessId()); + return t1 ^ t2 ^ pid; +#else + union + { + unsigned int integer; + char bytes[sizeof(unsigned int)]; + } seed; + + // Try using a real random source. + std::ifstream fin("/dev/urandom"); + if(fin && fin.read(seed.bytes, sizeof(seed)) && + fin.gcount() == sizeof(seed)) + { + return seed.integer; + } + + // Fall back to the time and pid. + struct timeval t; + gettimeofday(&t, 0); + unsigned int pid = static_cast<unsigned int>(getpid()); + unsigned int tv_sec = static_cast<unsigned int>(t.tv_sec); + unsigned int tv_usec = static_cast<unsigned int>(t.tv_usec); + // Since tv_usec never fills more than 11 bits we shift it to fill + // in the slow-changing high-order bits of tv_sec. + return tv_sec ^ (tv_usec << 21) ^ pid; +#endif +} + +//---------------------------------------------------------------------------- +static std::string cmSystemToolsExecutableDirectory; +void cmSystemTools::FindExecutableDirectory(const char* argv0) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)argv0; // ignore this on windows + char modulepath[_MAX_PATH]; + ::GetModuleFileName(NULL, modulepath, sizeof(modulepath)); + cmSystemToolsExecutableDirectory = + cmSystemTools::GetFilenamePath(modulepath); + return; +#else + std::string errorMsg; + std::string exe; + if(cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) + { + // remove symlinks + exe = cmSystemTools::GetRealPath(exe.c_str()); + cmSystemToolsExecutableDirectory = + cmSystemTools::GetFilenamePath(exe.c_str()); + } + else + { + // ??? + } +#endif +} + +//---------------------------------------------------------------------------- +const char* cmSystemTools::GetExecutableDirectory() +{ + return cmSystemToolsExecutableDirectory.c_str(); +} + +//---------------------------------------------------------------------------- +#if defined(CMAKE_BUILD_WITH_CMAKE) +void cmSystemTools::MakefileColorEcho(int color, const char* message, + bool newline, bool enabled) +{ + // On some platforms (an MSYS prompt) cmsysTerminal may not be able + // to determine whether the stream is displayed on a tty. In this + // case it assumes no unless we tell it otherwise. Since we want + // color messages to be displayed for users we will assume yes. + // However, we can test for some situations when the answer is most + // likely no. + int assumeTTY = cmsysTerminal_Color_AssumeTTY; + if(cmSystemTools::GetEnv("DART_TEST_FROM_DART") || + cmSystemTools::GetEnv("DASHBOARD_TEST_FROM_CTEST") || + cmSystemTools::GetEnv("CTEST_INTERACTIVE_DEBUG_MODE")) + { + // Avoid printing color escapes during dashboard builds. + assumeTTY = 0; + } + + if(enabled) + { + cmsysTerminal_cfprintf(color | assumeTTY, stdout, "%s%s", + message, newline? "\n" : ""); + } + else + { + // Color is disabled. Print without color. + fprintf(stdout, "%s%s", message, newline? "\n" : ""); + } +} +#endif + +//---------------------------------------------------------------------------- +bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, + std::string& soname) +{ + // For ELF shared libraries use a real parser to get the correct + // soname. +#if defined(CMAKE_USE_ELF_PARSER) + cmELF elf(fullPath.c_str()); + if(elf) + { + return elf.GetSOName(soname); + } +#endif + + // If the file is not a symlink we have no guess for its soname. + if(!cmSystemTools::FileIsSymlink(fullPath.c_str())) + { + return false; + } + if(!cmSystemTools::ReadSymlink(fullPath.c_str(), soname)) + { + return false; + } + + // If the symlink has a path component we have no guess for the soname. + if(!cmSystemTools::GetFilenamePath(soname).empty()) + { + return false; + } + + // If the symlink points at an extended version of the same name + // assume it is the soname. + std::string name = cmSystemTools::GetFilenameName(fullPath); + if(soname.length() > name.length() && + soname.substr(0, name.length()) == name) + { + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +#if defined(CMAKE_USE_ELF_PARSER) +std::string::size_type cmSystemToolsFindRPath(std::string const& have, + std::string const& want) +{ + // Search for the desired rpath. + std::string::size_type pos = have.find(want); + + // If the path is not present we are done. + if(pos == std::string::npos) + { + return pos; + } + + // Build a regex to match a properly separated path instance. + std::string regex_str = "(^|:)("; + for(std::string::const_iterator i = want.begin(); i != want.end(); ++i) + { + int ch = *i; + if(!(('a' <= ch && ch <= 'z') || + ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9'))) + { + // Escape the non-alphanumeric character. + regex_str += "\\"; + } + // Store the character. + regex_str.append(1, static_cast<char>(ch)); + } + regex_str += ")(:|$)"; + + // Look for the separated path. + cmsys::RegularExpression regex(regex_str.c_str()); + if(regex.find(have)) + { + // Return the position of the path portion. + return regex.start(2); + } + else + { + // The desired rpath was not found. + return std::string::npos; + } +} +#endif + +#if defined(CMAKE_USE_ELF_PARSER) +struct cmSystemToolsRPathInfo +{ + unsigned long Position; + unsigned long Size; + std::string Name; + std::string Value; +}; +#endif + +//---------------------------------------------------------------------------- +bool cmSystemTools::ChangeRPath(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + std::string* emsg, + bool* changed) +{ +#if defined(CMAKE_USE_ELF_PARSER) + if(changed) + { + *changed = false; + } + int rp_count = 0; + cmSystemToolsRPathInfo rp[2]; + { + // Parse the ELF binary. + cmELF elf(file.c_str()); + + // Get the RPATH and RUNPATH entries from it. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + const char* se_name[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) + { + se[se_count] = se_rpath; + se_name[se_count] = "RPATH"; + ++se_count; + } + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) + { + se[se_count] = se_runpath; + se_name[se_count] = "RUNPATH"; + ++se_count; + } + if(se_count == 0) + { + if(newRPath.empty()) + { + // The new rpath is empty and there is no rpath anyway so it is + // okay. + return true; + } + else + { + if(emsg) + { + *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; "; + *emsg += elf.GetErrorMessage(); + } + return false; + } + } + + for(int i=0; i < se_count; ++i) + { + // If both RPATH and RUNPATH refer to the same string literal it + // needs to be changed only once. + if(rp_count && rp[0].Position == se[i]->Position) + { + continue; + } + + // Make sure the current rpath contains the old rpath. + std::string::size_type pos = + cmSystemToolsFindRPath(se[i]->Value, oldRPath); + if(pos == std::string::npos) + { + // If it contains the new rpath instead then it is okay. + if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos) + { + continue; + } + if(emsg) + { + cmOStringStream e; + e << "The current " << se_name[i] << " is:\n" + << " " << se[i]->Value << "\n" + << "which does not contain:\n" + << " " << oldRPath << "\n" + << "as was expected."; + *emsg = e.str(); + } + return false; + } + + // Store information about the entry in the file. + rp[rp_count].Position = se[i]->Position; + rp[rp_count].Size = se[i]->Size; + rp[rp_count].Name = se_name[i]; + + // Construct the new value which preserves the part of the path + // not being changed. + rp[rp_count].Value = se[i]->Value.substr(0, pos); + rp[rp_count].Value += newRPath; + rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(), + oldRPath.npos); + + // Make sure there is enough room to store the new rpath and at + // least one null terminator. + if(rp[rp_count].Size < rp[rp_count].Value.length()+1) + { + if(emsg) + { + *emsg = "The replacement path is too long for the "; + *emsg += se_name[i]; + *emsg += " entry."; + } + return false; + } + + // This entry is ready for update. + ++rp_count; + } + } + + // If no runtime path needs to be changed, we are done. + if(rp_count == 0) + { + return true; + } + + { + // Open the file for update. + std::ofstream f(file.c_str(), + std::ios::in | std::ios::out | std::ios::binary); + if(!f) + { + if(emsg) + { + *emsg = "Error opening file for update."; + } + return false; + } + + // Store the new RPATH and RUNPATH strings. + for(int i=0; i < rp_count; ++i) + { + // Seek to the RPATH position. + if(!f.seekp(rp[i].Position)) + { + if(emsg) + { + *emsg = "Error seeking to "; + *emsg += rp[i].Name; + *emsg += " position."; + } + return false; + } + + // Write the new rpath. Follow it with enough null terminators to + // fill the string table entry. + f << rp[i].Value; + for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j) + { + f << '\0'; + } + + // Make sure it wrote correctly. + if(!f) + { + if(emsg) + { + *emsg = "Error writing the new "; + *emsg += rp[i].Name; + *emsg += " string to the file."; + } + return false; + } + } + } + + // Everything was updated successfully. + if(changed) + { + *changed = true; + } + return true; +#else + (void)file; + (void)oldRPath; + (void)newRPath; + (void)emsg; + (void)changed; + return false; +#endif +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, + const char* lhss, const char* rhss) +{ + unsigned int lhs[4] = {0,0,0,0}; + unsigned int rhs[4] = {0,0,0,0}; + sscanf(lhss, "%u.%u.%u.%u", &lhs[0], &lhs[1], &lhs[2], &lhs[3]); + sscanf(rhss, "%u.%u.%u.%u", &rhs[0], &rhs[1], &rhs[2], &rhs[3]); + + // Do component-wise comparison. + for(unsigned int i=0; i < 4; ++i) + { + if(lhs[i] < rhs[i]) + { + // lhs < rhs, so true if operation is LESS + return op == cmSystemTools::OP_LESS; + } + else if(lhs[i] > rhs[i]) + { + // lhs > rhs, so true if operation is GREATER + return op == cmSystemTools::OP_GREATER; + } + } + // lhs == rhs, so true if operation is EQUAL + return op == cmSystemTools::OP_EQUAL; +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, + bool* removed) +{ +#if defined(CMAKE_USE_ELF_PARSER) + if(removed) + { + *removed = false; + } + int zeroCount = 0; + unsigned long zeroPosition[2] = {0,0}; + unsigned long zeroSize[2] = {0,0}; + unsigned long bytesBegin = 0; + std::vector<char> bytes; + { + // Parse the ELF binary. + cmELF elf(file.c_str()); + + // Get the RPATH and RUNPATH entries from it and sort them by index + // in the dynamic section header. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) + { + se[se_count++] = se_rpath; + } + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) + { + se[se_count++] = se_runpath; + } + if(se_count == 0) + { + // There is no RPATH or RUNPATH anyway. + return true; + } + if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) + { + cmsys_stl::swap(se[0], se[1]); + } + + // Get the size of the dynamic section header. + unsigned int count = elf.GetDynamicEntryCount(); + if(count == 0) + { + // This should happen only for invalid ELF files where a DT_NULL + // appears before the end of the table. + if(emsg) + { + *emsg = "DYNAMIC section contains a DT_NULL before the end."; + } + return false; + } + + // Save information about the string entries to be zeroed. + zeroCount = se_count; + for(int i=0; i < se_count; ++i) + { + zeroPosition[i] = se[i]->Position; + zeroSize[i] = se[i]->Size; + } + + // Get the range of file positions corresponding to each entry and + // the rest of the table after them. + unsigned long entryBegin[3] = {0,0,0}; + unsigned long entryEnd[2] = {0,0}; + for(int i=0; i < se_count; ++i) + { + entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection); + entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1); + } + entryBegin[se_count] = elf.GetDynamicEntryPosition(count); + + // The data are to be written over the old table entries starting at + // the first one being removed. + bytesBegin = entryBegin[0]; + unsigned long bytesEnd = entryBegin[se_count]; + + // Allocate a buffer to hold the part of the file to be written. + // Initialize it with zeros. + bytes.resize(bytesEnd - bytesBegin, 0); + + // Read the part of the DYNAMIC section header that will move. + // The remainder of the buffer will be left with zeros which + // represent a DT_NULL entry. + char* data = &bytes[0]; + for(int i=0; i < se_count; ++i) + { + // Read data between the entries being removed. + unsigned long sz = entryBegin[i+1] - entryEnd[i]; + if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) + { + if(emsg) + { + *emsg = "Failed to read DYNAMIC section header."; + } + return false; + } + data += sz; + } + } + + // Open the file for update. + std::ofstream f(file.c_str(), + std::ios::in | std::ios::out | std::ios::binary); + if(!f) + { + if(emsg) + { + *emsg = "Error opening file for update."; + } + return false; + } + + // Write the new DYNAMIC table header. + if(!f.seekp(bytesBegin)) + { + if(emsg) + { + *emsg = "Error seeking to DYNAMIC table header for RPATH."; + } + return false; + } + if(!f.write(&bytes[0], bytes.size())) + { + if(emsg) + { + *emsg = "Error replacing DYNAMIC table header."; + } + return false; + } + + // Fill the RPATH and RUNPATH strings with zero bytes. + for(int i=0; i < zeroCount; ++i) + { + if(!f.seekp(zeroPosition[i])) + { + if(emsg) + { + *emsg = "Error seeking to RPATH position."; + } + return false; + } + for(unsigned long j=0; j < zeroSize[i]; ++j) + { + f << '\0'; + } + if(!f) + { + if(emsg) + { + *emsg = "Error writing the empty rpath string to the file."; + } + return false; + } + } + + // Everything was updated successfully. + if(removed) + { + *removed = true; + } + return true; +#else + (void)file; + (void)emsg; + (void)removed; + return false; +#endif +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::CheckRPath(std::string const& file, + std::string const& newRPath) +{ +#if defined(CMAKE_USE_ELF_PARSER) + // Parse the ELF binary. + cmELF elf(file.c_str()); + + // Get the RPATH or RUNPATH entry from it. + cmELF::StringEntry const* se = elf.GetRPath(); + if(!se) + { + se = elf.GetRunPath(); + } + + // Make sure the current rpath contains the new rpath. + if(newRPath.empty()) + { + if(!se) + { + return true; + } + } + else + { + if(se && + cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) + { + return true; + } + } + return false; +#else + (void)file; + (void)newRPath; + return false; +#endif +} + +//---------------------------------------------------------------------------- +bool cmSystemTools::RepeatedRemoveDirectory(const char* dir) +{ + // Windows sometimes locks files temporarily so try a few times. + for(int i = 0; i < 10; ++i) + { + if(cmSystemTools::RemoveADirectory(dir)) + { + return true; + } + cmSystemTools::Delay(100); + } + return false; +} + +//---------------------------------------------------------------------------- +std::vector<std::string> cmSystemTools::tokenize(const std::string& str, + const std::string& sep) +{ + std::vector<std::string> tokens; + std::string::size_type tokend = 0; + + do + { + std::string::size_type tokstart=str.find_first_not_of(sep, tokend); + if (tokstart==std::string::npos) + { + break; // no more tokens + } + tokend=str.find_first_of(sep,tokstart); + if (tokend==std::string::npos) + { + tokens.push_back(str.substr(tokstart)); + } + else + { + tokens.push_back(str.substr(tokstart,tokend-tokstart)); + } + } while (tokend!=std::string::npos); + + if (tokens.empty()) + { + tokens.push_back(""); + } + return tokens; +} |