Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmSystemTools.cxx
blob761b83ebbd334dad5bde32b52ed230bfa395edae
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmSystemTools.cxx,v $
5 Language: C++
6 Date: $Date: 2009-07-13 21:08:38 $
7 Version: $Revision: 1.400 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmSystemTools.h"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #ifdef __QNX__
24 # include <malloc.h> /* for malloc/free on QNX */
25 #endif
27 #include <cmsys/RegularExpression.hxx>
28 #include <cmsys/Directory.hxx>
29 #include <cmsys/System.h>
30 #if defined(CMAKE_BUILD_WITH_CMAKE)
31 # include <cmsys/Terminal.h>
32 #endif
33 #include <cmsys/stl/algorithm>
35 #if defined(_WIN32)
36 # include <windows.h>
37 #else
38 # include <sys/types.h>
39 # include <unistd.h>
40 # include <utime.h>
41 # include <sys/wait.h>
42 #endif
44 #include <sys/stat.h>
46 #if defined(_WIN32) && \
47 (defined(_MSC_VER) || defined(__WATCOMC__) || \
48 defined(__BORLANDC__) || defined(__MINGW32__))
49 # include <io.h>
50 #endif
52 #if defined(CMAKE_BUILD_WITH_CMAKE)
53 # include <libtar/libtar.h>
54 # include <memory> // auto_ptr
55 # include <fcntl.h>
56 # include <cm_zlib.h>
57 # include <cmsys/MD5.h>
58 #endif
60 #if defined(CMAKE_USE_ELF_PARSER)
61 # include "cmELF.h"
62 #endif
64 class cmSystemToolsFileTime
66 public:
67 #if defined(_WIN32) && !defined(__CYGWIN__)
68 FILETIME timeCreation;
69 FILETIME timeLastAccess;
70 FILETIME timeLastWrite;
71 #else
72 struct utimbuf timeBuf;
73 #endif
76 #if defined(__sgi) && !defined(__GNUC__)
77 # pragma set woff 1375 /* base class destructor not virtual */
78 #endif
80 #if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
81 // For GetEnvironmentVariables
82 # if defined(_WIN32)
83 extern __declspec( dllimport ) char** environ;
84 # else
85 extern char** environ;
86 # endif
87 #endif
89 #ifdef _WIN32
90 class cmSystemToolsWindowsHandle
92 public:
93 cmSystemToolsWindowsHandle(HANDLE h): handle_(h) {}
94 ~cmSystemToolsWindowsHandle()
96 if(this->handle_ != INVALID_HANDLE_VALUE)
98 CloseHandle(this->handle_);
101 operator bool() const { return this->handle_ != INVALID_HANDLE_VALUE; }
102 bool operator !() const { return this->handle_ == INVALID_HANDLE_VALUE; }
103 operator HANDLE() const { return this->handle_; }
104 private:
105 HANDLE handle_;
107 #endif
109 bool cmSystemTools::s_RunCommandHideConsole = false;
110 bool cmSystemTools::s_DisableRunCommandOutput = false;
111 bool cmSystemTools::s_ErrorOccured = false;
112 bool cmSystemTools::s_FatalErrorOccured = false;
113 bool cmSystemTools::s_DisableMessages = false;
114 bool cmSystemTools::s_ForceUnixPaths = false;
116 std::string cmSystemTools::s_Windows9xComspecSubstitute = "command.com";
117 void cmSystemTools::SetWindows9xComspecSubstitute(const char* str)
119 if ( str )
121 cmSystemTools::s_Windows9xComspecSubstitute = str;
124 const char* cmSystemTools::GetWindows9xComspecSubstitute()
126 return cmSystemTools::s_Windows9xComspecSubstitute.c_str();
129 void (*cmSystemTools::s_ErrorCallback)(const char*, const char*,
130 bool&, void*);
131 void (*cmSystemTools::s_StdoutCallback)(const char*, int len, void*);
132 void* cmSystemTools::s_ErrorCallbackClientData = 0;
133 void* cmSystemTools::s_StdoutCallbackClientData = 0;
135 // replace replace with with as many times as it shows up in source.
136 // write the result into source.
137 #if defined(_WIN32) && !defined(__CYGWIN__)
138 void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view)
140 // Regular expression to match anything inside [...] that begins in HKEY.
141 // Note that there is a special rule for regular expressions to match a
142 // close square-bracket inside a list delimited by square brackets.
143 // The "[^]]" part of this expression will match any character except
144 // a close square-bracket. The ']' character must be the first in the
145 // list of characters inside the [^...] block of the expression.
146 cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
148 // check for black line or comment
149 while (regEntry.find(source))
151 // the arguments are the second match
152 std::string key = regEntry.match(1);
153 std::string val;
154 if (ReadRegistryValue(key.c_str(), val, view))
156 std::string reg = "[";
157 reg += key + "]";
158 cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
160 else
162 std::string reg = "[";
163 reg += key + "]";
164 cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
168 #else
169 void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64)
171 cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
172 while (regEntry.find(source))
174 // the arguments are the second match
175 std::string key = regEntry.match(1);
176 std::string val;
177 std::string reg = "[";
178 reg += key + "]";
179 cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
183 #endif
185 std::string cmSystemTools::EscapeQuotes(const char* str)
187 std::string result = "";
188 for(const char* ch = str; *ch != '\0'; ++ch)
190 if(*ch == '"')
192 result += '\\';
194 result += *ch;
196 return result;
199 std::string cmSystemTools::EscapeSpaces(const char* str)
201 #if defined(_WIN32) && !defined(__CYGWIN__)
202 bool useDoubleQ = true;
203 #else
204 bool useDoubleQ = false;
205 #endif
206 if(cmSystemTools::s_ForceUnixPaths)
208 useDoubleQ = false;
211 if(useDoubleQ)
213 std::string result;
215 // if there are spaces
216 std::string temp = str;
217 if (temp.find(" ") != std::string::npos &&
218 temp.find("\"")==std::string::npos)
220 result = "\"";
221 result += str;
222 result += "\"";
223 return result;
225 return str;
227 else
229 std::string result = "";
230 for(const char* ch = str; *ch != '\0'; ++ch)
232 if(*ch == ' ')
234 result += '\\';
236 result += *ch;
238 return result;
242 void cmSystemTools::Error(const char* m1, const char* m2,
243 const char* m3, const char* m4)
245 std::string message = "CMake Error: ";
246 if(m1)
248 message += m1;
250 if(m2)
252 message += m2;
254 if(m3)
256 message += m3;
258 if(m4)
260 message += m4;
262 cmSystemTools::s_ErrorOccured = true;
263 cmSystemTools::Message(message.c_str(),"Error");
267 void cmSystemTools::SetErrorCallback(ErrorCallback f, void* clientData)
269 s_ErrorCallback = f;
270 s_ErrorCallbackClientData = clientData;
273 void cmSystemTools::SetStdoutCallback(StdoutCallback f, void* clientData)
275 s_StdoutCallback = f;
276 s_StdoutCallbackClientData = clientData;
279 void cmSystemTools::Stdout(const char* s)
281 if(s_StdoutCallback)
283 (*s_StdoutCallback)(s, static_cast<int>(strlen(s)),
284 s_StdoutCallbackClientData);
286 else
288 std::cout << s;
289 std::cout.flush();
293 void cmSystemTools::Stdout(const char* s, int length)
295 if(s_StdoutCallback)
297 (*s_StdoutCallback)(s, length, s_StdoutCallbackClientData);
299 else
301 std::cout.write(s, length);
302 std::cout.flush();
306 void cmSystemTools::Message(const char* m1, const char *title)
308 if(s_DisableMessages)
310 return;
312 if(s_ErrorCallback)
314 (*s_ErrorCallback)(m1, title, s_DisableMessages,
315 s_ErrorCallbackClientData);
316 return;
318 else
320 std::cerr << m1 << std::endl << std::flush;
326 void cmSystemTools::ReportLastSystemError(const char* msg)
328 std::string m = msg;
329 m += ": System Error: ";
330 m += Superclass::GetLastSystemError();
331 cmSystemTools::Error(m.c_str());
335 bool cmSystemTools::IsOn(const char* val)
337 if (!val)
339 return false;
341 std::basic_string<char> v = val;
343 for(std::basic_string<char>::iterator c = v.begin();
344 c != v.end(); c++)
346 *c = toupper(*c);
348 return (v == "ON" || v == "1" || v == "YES" || v == "TRUE" || v == "Y");
351 bool cmSystemTools::IsNOTFOUND(const char* val)
353 size_t len = strlen(val);
354 const char* notfound = "-NOTFOUND";
355 const size_t lenNotFound = 9;
356 if(len < lenNotFound-1)
358 return false;
360 if(len == lenNotFound-1)
362 return ( strcmp(val, "NOTFOUND") == 0);
364 return ((strncmp((val + (len - lenNotFound)), notfound, lenNotFound) == 0));
368 bool cmSystemTools::IsOff(const char* val)
370 if (!val || strlen(val) == 0)
372 return true;
374 std::basic_string<char> v = val;
376 for(std::basic_string<char>::iterator c = v.begin();
377 c != v.end(); c++)
379 *c = toupper(*c);
381 return (v == "OFF" || v == "0" || v == "NO" || v == "FALSE" ||
382 v == "N" || cmSystemTools::IsNOTFOUND(v.c_str()) || v == "IGNORE");
385 //----------------------------------------------------------------------------
386 void cmSystemTools::ParseWindowsCommandLine(const char* command,
387 std::vector<std::string>& args)
389 // See the MSDN document "Parsing C Command-Line Arguments" at
390 // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules
391 // of parsing the windows command line.
393 bool in_argument = false;
394 bool in_quotes = false;
395 int backslashes = 0;
396 std::string arg;
397 for(const char* c = command;*c; ++c)
399 if(*c == '\\')
401 ++backslashes;
402 in_argument = true;
404 else if(*c == '"')
406 int backslash_pairs = backslashes >> 1;
407 int backslash_escaped = backslashes & 1;
408 arg.append(backslash_pairs, '\\');
409 backslashes = 0;
410 if(backslash_escaped)
412 /* An odd number of backslashes precede this quote.
413 It is escaped. */
414 arg.append(1, '"');
416 else
418 /* An even number of backslashes precede this quote.
419 It is not escaped. */
420 in_quotes = !in_quotes;
422 in_argument = true;
424 else
426 arg.append(backslashes, '\\');
427 backslashes = 0;
428 if(isspace(*c))
430 if(in_quotes)
432 arg.append(1, *c);
434 else if(in_argument)
436 args.push_back(arg);
437 arg = "";
438 in_argument = false;
441 else
443 in_argument = true;
444 arg.append(1, *c);
448 arg.append(backslashes, '\\');
449 if(in_argument)
451 args.push_back(arg);
455 //----------------------------------------------------------------------------
456 class cmSystemToolsArgV
458 char** ArgV;
459 public:
460 cmSystemToolsArgV(char** argv): ArgV(argv) {}
461 ~cmSystemToolsArgV()
463 for(char** arg = this->ArgV; arg && *arg; ++arg)
465 free(*arg);
467 free(this->ArgV);
469 void Store(std::vector<std::string>& args) const
471 for(char** arg = this->ArgV; arg && *arg; ++arg)
473 args.push_back(*arg);
478 //----------------------------------------------------------------------------
479 void cmSystemTools::ParseUnixCommandLine(const char* command,
480 std::vector<std::string>& args)
482 // Invoke the underlying parser.
483 cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
484 argv.Store(args);
487 std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg,
488 int shell_flags)
490 char local_buffer[1024];
491 char* buffer = local_buffer;
492 int size = cmsysSystem_Shell_GetArgumentSizeForWindows(arg, shell_flags);
493 if(size > 1024)
495 buffer = new char[size];
497 cmsysSystem_Shell_GetArgumentForWindows(arg, buffer, shell_flags);
498 std::string result(buffer);
499 if(buffer != local_buffer)
501 delete [] buffer;
503 return result;
506 std::vector<cmStdString> cmSystemTools::ParseArguments(const char* command)
508 std::vector<cmStdString> args;
509 std::string arg;
511 bool win_path = false;
513 if ( command[0] != '/' && command[1] == ':' && command[2] == '\\' ||
514 command[0] == '\"' && command[1] != '/' && command[2] == ':'
515 && command[3] == '\\' ||
516 command[0] == '\'' && command[1] != '/' && command[2] == ':'
517 && command[3] == '\\' ||
518 command[0] == '\\' && command[1] == '\\')
520 win_path = true;
522 // Split the command into an argv array.
523 for(const char* c = command; *c;)
525 // Skip over whitespace.
526 while(*c == ' ' || *c == '\t')
528 ++c;
530 arg = "";
531 if(*c == '"')
533 // Parse a quoted argument.
534 ++c;
535 while(*c && *c != '"')
537 arg.append(1, *c);
538 ++c;
540 if(*c)
542 ++c;
544 args.push_back(arg);
546 else if(*c == '\'')
548 // Parse a quoted argument.
549 ++c;
550 while(*c && *c != '\'')
552 arg.append(1, *c);
553 ++c;
555 if(*c)
557 ++c;
559 args.push_back(arg);
561 else if(*c)
563 // Parse an unquoted argument.
564 while(*c && *c != ' ' && *c != '\t')
566 if(*c == '\\' && !win_path)
568 ++c;
569 if(*c)
571 arg.append(1, *c);
572 ++c;
575 else
577 arg.append(1, *c);
578 ++c;
581 args.push_back(arg);
585 return args;
589 bool cmSystemTools::RunSingleCommand(std::vector<cmStdString>const& command,
590 std::string* output ,
591 int* retVal , const char* dir ,
592 bool verbose ,
593 double timeout )
595 std::vector<const char*> argv;
596 for(std::vector<cmStdString>::const_iterator a = command.begin();
597 a != command.end(); ++a)
599 argv.push_back(a->c_str());
601 argv.push_back(0);
602 if ( output )
604 *output = "";
607 cmsysProcess* cp = cmsysProcess_New();
608 cmsysProcess_SetCommand(cp, &*argv.begin());
609 cmsysProcess_SetWorkingDirectory(cp, dir);
610 if(cmSystemTools::GetRunCommandHideConsole())
612 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
614 cmsysProcess_SetTimeout(cp, timeout);
615 cmsysProcess_Execute(cp);
617 std::vector<char> tempOutput;
618 char* data;
619 int length;
620 if ( output || verbose )
622 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
624 if(output || verbose)
626 // Translate NULL characters in the output into valid text.
627 // Visual Studio 7 puts these characters in the output of its
628 // build process.
629 for(int i=0; i < length; ++i)
631 if(data[i] == '\0')
633 data[i] = ' ';
637 if ( output )
639 tempOutput.insert(tempOutput.end(), data, data+length);
641 if(verbose)
643 cmSystemTools::Stdout(data, length);
648 cmsysProcess_WaitForExit(cp, 0);
649 if ( output && tempOutput.begin() != tempOutput.end())
651 output->append(&*tempOutput.begin(), tempOutput.size());
654 bool result = true;
655 if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
657 if ( retVal )
659 *retVal = cmsysProcess_GetExitValue(cp);
661 else
663 if ( cmsysProcess_GetExitValue(cp) != 0 )
665 result = false;
669 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
671 const char* exception_str = cmsysProcess_GetExceptionString(cp);
672 if ( verbose )
674 std::cerr << exception_str << std::endl;
676 if ( output )
678 output->append(exception_str, strlen(exception_str));
680 result = false;
682 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
684 const char* error_str = cmsysProcess_GetErrorString(cp);
685 if ( verbose )
687 std::cerr << error_str << std::endl;
689 if ( output )
691 output->append(error_str, strlen(error_str));
693 result = false;
695 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
697 const char* error_str = "Process terminated due to timeout\n";
698 if ( verbose )
700 std::cerr << error_str << std::endl;
702 if ( output )
704 output->append(error_str, strlen(error_str));
706 result = false;
709 cmsysProcess_Delete(cp);
710 return result;
713 bool cmSystemTools::RunSingleCommand(
714 const char* command,
715 std::string* output,
716 int *retVal,
717 const char* dir,
718 bool verbose,
719 double timeout)
721 if(s_DisableRunCommandOutput)
723 verbose = false;
726 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
728 if(args.size() < 1)
730 return false;
732 return cmSystemTools::RunSingleCommand(args, output,retVal,
733 dir, verbose, timeout);
735 bool cmSystemTools::RunCommand(const char* command,
736 std::string& output,
737 const char* dir,
738 bool verbose,
739 int timeout)
741 int dummy;
742 return cmSystemTools::RunCommand(command, output, dummy,
743 dir, verbose, timeout);
746 #if defined(WIN32) && !defined(__CYGWIN__)
747 #include "cmWin32ProcessExecution.h"
748 // use this for shell commands like echo and dir
749 bool RunCommandViaWin32(const char* command,
750 const char* dir,
751 std::string& output,
752 int& retVal,
753 bool verbose,
754 int timeout)
756 #if defined(__BORLANDC__)
757 return
758 cmWin32ProcessExecution::
759 BorlandRunCommand(command, dir, output,
760 retVal,
761 verbose, timeout,
762 cmSystemTools::GetRunCommandHideConsole());
763 #else // Visual studio
764 ::SetLastError(ERROR_SUCCESS);
765 if ( ! command )
767 cmSystemTools::Error("No command specified");
768 return false;
770 cmWin32ProcessExecution resProc;
771 if(cmSystemTools::GetRunCommandHideConsole())
773 resProc.SetHideWindows(true);
776 if ( cmSystemTools::GetWindows9xComspecSubstitute() )
778 resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() );
780 if ( !resProc.StartProcess(command, dir, verbose) )
782 output = resProc.GetOutput();
783 if(verbose)
785 cmSystemTools::Stdout(output.c_str());
787 return false;
789 resProc.Wait(timeout);
790 output = resProc.GetOutput();
791 retVal = resProc.GetExitValue();
792 return true;
793 #endif
796 // use this for shell commands like echo and dir
797 bool RunCommandViaSystem(const char* command,
798 const char* dir,
799 std::string& output,
800 int& retVal,
801 bool verbose)
803 std::cout << "@@ " << command << std::endl;
805 std::string commandInDir;
806 if(dir)
808 commandInDir = "cd ";
809 commandInDir += cmSystemTools::ConvertToOutputPath(dir);
810 commandInDir += " && ";
811 commandInDir += command;
813 else
815 commandInDir = command;
817 command = commandInDir.c_str();
818 std::string commandToFile = command;
819 commandToFile += " > ";
820 std::string tempFile;
821 tempFile += _tempnam(0, "cmake");
823 commandToFile += tempFile;
824 retVal = system(commandToFile.c_str());
825 std::ifstream fin(tempFile.c_str());
826 if(!fin)
828 if(verbose)
830 std::string errormsg = "RunCommand produced no output: command: \"";
831 errormsg += command;
832 errormsg += "\"";
833 errormsg += "\nOutput file: ";
834 errormsg += tempFile;
835 cmSystemTools::Error(errormsg.c_str());
837 fin.close();
838 cmSystemTools::RemoveFile(tempFile.c_str());
839 return false;
841 bool multiLine = false;
842 std::string line;
843 while(cmSystemTools::GetLineFromStream(fin, line))
845 output += line;
846 if(multiLine)
848 output += "\n";
850 multiLine = true;
852 fin.close();
853 cmSystemTools::RemoveFile(tempFile.c_str());
854 return true;
857 #else // We have popen
859 // BeOS seems to return from a successful pclose() before the process has
860 // legitimately exited, or at least before SIGCHLD is thrown...the signal may
861 // come quite some time after pclose returns! This causes havoc with later
862 // parts of CMake that expect to catch the signal from other child processes,
863 // so we explicitly wait to catch it here. This should be safe to do with
864 // popen() so long as we don't actually collect the zombie process ourselves.
865 #ifdef __BEOS__
866 #include <signal.h>
867 #undef SIGBUS // this is the same as SIGSEGV on BeOS and causes issues below.
868 static volatile bool beos_seen_signal = false;
869 static void beos_popen_workaround(int sig)
871 beos_seen_signal = true;
873 #endif
875 bool RunCommandViaPopen(const char* command,
876 const char* dir,
877 std::string& output,
878 int& retVal,
879 bool verbose,
880 int /*timeout*/)
882 // if only popen worked on windows.....
883 std::string commandInDir;
884 if(dir)
886 commandInDir = "cd \"";
887 commandInDir += dir;
888 commandInDir += "\" && ";
889 commandInDir += command;
891 else
893 commandInDir = command;
895 #ifndef __VMS
896 commandInDir += " 2>&1";
897 #endif
898 command = commandInDir.c_str();
899 const int BUFFER_SIZE = 4096;
900 char buffer[BUFFER_SIZE];
901 if(verbose)
903 cmSystemTools::Stdout("running ");
904 cmSystemTools::Stdout(command);
905 cmSystemTools::Stdout("\n");
907 fflush(stdout);
908 fflush(stderr);
910 #ifdef __BEOS__
911 beos_seen_signal = false;
912 signal(SIGCHLD, beos_popen_workaround);
913 #endif
915 FILE* cpipe = popen(command, "r");
916 if(!cpipe)
918 #ifdef __BEOS__
919 signal(SIGCHLD, SIG_DFL);
920 #endif
921 return false;
923 fgets(buffer, BUFFER_SIZE, cpipe);
924 while(!feof(cpipe))
926 if(verbose)
928 cmSystemTools::Stdout(buffer);
930 output += buffer;
931 buffer[0] = 0;
932 fgets(buffer, BUFFER_SIZE, cpipe);
935 retVal = pclose(cpipe);
937 #ifdef __BEOS__
938 for (int i = 0; (!beos_seen_signal) && (i < 3); i++)
940 ::sleep(1); // signals should interrupt this...
943 if (!beos_seen_signal)
945 signal(SIGCHLD, SIG_DFL); // oh well, didn't happen. Go on anyhow.
947 #endif
949 if (WIFEXITED(retVal))
951 retVal = WEXITSTATUS(retVal);
952 return true;
954 if (WIFSIGNALED(retVal))
956 retVal = WTERMSIG(retVal);
957 cmOStringStream error;
958 error << "\nProcess terminated due to ";
959 switch (retVal)
961 #ifdef SIGKILL
962 case SIGKILL:
963 error << "SIGKILL";
964 break;
965 #endif
966 #ifdef SIGFPE
967 case SIGFPE:
968 error << "SIGFPE";
969 break;
970 #endif
971 #ifndef __HAIKU__
972 #ifdef SIGBUS
973 case SIGBUS:
974 error << "SIGBUS";
975 break;
976 #endif
977 #endif
978 #ifdef SIGSEGV
979 case SIGSEGV:
980 error << "SIGSEGV";
981 break;
982 #endif
983 default:
984 error << "signal " << retVal;
985 break;
987 output += error.str();
989 return false;
992 #endif // endif WIN32 not CYGWIN
995 // run a command unix uses popen (easy)
996 // windows uses system and ShortPath
997 bool cmSystemTools::RunCommand(const char* command,
998 std::string& output,
999 int &retVal,
1000 const char* dir,
1001 bool verbose,
1002 int timeout)
1004 if(s_DisableRunCommandOutput)
1006 verbose = false;
1009 #if defined(WIN32) && !defined(__CYGWIN__)
1010 // if the command does not start with a quote, then
1011 // try to find the program, and if the program can not be
1012 // found use system to run the command as it must be a built in
1013 // shell command like echo or dir
1014 int count = 0;
1015 if(command[0] == '\"')
1017 // count the number of quotes
1018 for(const char* s = command; *s != 0; ++s)
1020 if(*s == '\"')
1022 count++;
1023 if(count > 2)
1025 break;
1029 // if there are more than two double quotes use
1030 // GetShortPathName, the cmd.exe program in windows which
1031 // is used by system fails to execute if there are more than
1032 // one set of quotes in the arguments
1033 if(count > 2)
1035 cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
1036 if(quoted.find(command))
1038 std::string shortCmd;
1039 std::string cmd = quoted.match(1);
1040 std::string args = quoted.match(2);
1041 if(! cmSystemTools::FileExists(cmd.c_str()) )
1043 shortCmd = cmd;
1045 else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd))
1047 cmSystemTools::Error("GetShortPath failed for " , cmd.c_str());
1048 return false;
1050 shortCmd += " ";
1051 shortCmd += args;
1053 //return RunCommandViaSystem(shortCmd.c_str(), dir,
1054 // output, retVal, verbose);
1055 //return WindowsRunCommand(shortCmd.c_str(), dir,
1056 //output, retVal, verbose);
1057 return RunCommandViaWin32(shortCmd.c_str(), dir,
1058 output, retVal, verbose, timeout);
1060 else
1062 cmSystemTools::Error("Could not parse command line with quotes ",
1063 command);
1067 // if there is only one set of quotes or no quotes then just run the command
1068 //return RunCommandViaSystem(command, dir, output, retVal, verbose);
1069 //return WindowsRunCommand(command, dir, output, retVal, verbose);
1070 return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout);
1071 #else
1072 return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout);
1073 #endif
1076 bool cmSystemTools::DoesFileExistWithExtensions(
1077 const char* name,
1078 const std::vector<std::string>& headerExts)
1080 std::string hname;
1082 for( std::vector<std::string>::const_iterator ext = headerExts.begin();
1083 ext != headerExts.end(); ++ext )
1085 hname = name;
1086 hname += ".";
1087 hname += *ext;
1088 if(cmSystemTools::FileExists(hname.c_str()))
1090 return true;
1093 return false;
1096 std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
1097 const char* directory, const char* toplevel)
1099 std::string file = fname;
1100 cmSystemTools::ConvertToUnixSlashes(file);
1101 std::string dir = directory;
1102 cmSystemTools::ConvertToUnixSlashes(dir);
1103 std::string prevDir;
1104 while(dir != prevDir)
1106 std::string path = dir + "/" + file;
1107 if ( cmSystemTools::FileExists(path.c_str()) )
1109 return path;
1111 if ( dir.size() < strlen(toplevel) )
1113 break;
1115 prevDir = dir;
1116 dir = cmSystemTools::GetParentDirectory(dir.c_str());
1118 return "";
1121 bool cmSystemTools::cmCopyFile(const char* source, const char* destination)
1123 return Superclass::CopyFileAlways(source, destination);
1126 bool cmSystemTools::CopyFileIfDifferent(const char* source,
1127 const char* destination)
1129 return Superclass::CopyFileIfDifferent(source, destination);
1132 //----------------------------------------------------------------------------
1133 bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
1135 #ifdef _WIN32
1136 /* On Windows the move functions will not replace existing files.
1137 Check if the destination exists. */
1138 struct stat newFile;
1139 if(stat(newname, &newFile) == 0)
1141 /* The destination exists. We have to replace it carefully. The
1142 MoveFileEx function does what we need but is not available on
1143 Win9x. */
1144 OSVERSIONINFO osv;
1145 DWORD attrs;
1147 /* Make sure the destination is not read only. */
1148 attrs = GetFileAttributes(newname);
1149 if(attrs & FILE_ATTRIBUTE_READONLY)
1151 SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY);
1154 /* Check the windows version number. */
1155 osv.dwOSVersionInfoSize = sizeof(osv);
1156 GetVersionEx(&osv);
1157 if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
1159 /* This is Win9x. There is no MoveFileEx implementation. We
1160 cannot quite rename the file atomically. Just delete the
1161 destination and then move the file. */
1162 DeleteFile(newname);
1163 return MoveFile(oldname, newname) != 0;
1165 else
1167 /* This is not Win9x. Use the MoveFileEx implementation. */
1168 return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING) != 0;
1171 else
1173 /* The destination does not exist. Just move the file. */
1174 return MoveFile(oldname, newname) != 0;
1176 #else
1177 /* On UNIX we have an OS-provided call to do this atomically. */
1178 return rename(oldname, newname) == 0;
1179 #endif
1182 bool cmSystemTools::ComputeFileMD5(const char* source, char* md5out)
1184 #if defined(CMAKE_BUILD_WITH_CMAKE)
1185 if(!cmSystemTools::FileExists(source))
1187 return false;
1190 // Open files
1191 #if defined(_WIN32) || defined(__CYGWIN__)
1192 cmsys_ios::ifstream fin(source, cmsys_ios::ios::binary | cmsys_ios::ios::in);
1193 #else
1194 cmsys_ios::ifstream fin(source);
1195 #endif
1196 if(!fin)
1198 return false;
1201 cmsysMD5* md5 = cmsysMD5_New();
1202 cmsysMD5_Initialize(md5);
1204 // Should be efficient enough on most system:
1205 const int bufferSize = 4096;
1206 char buffer[bufferSize];
1207 // This copy loop is very sensitive on certain platforms with
1208 // slightly broken stream libraries (like HPUX). Normally, it is
1209 // incorrect to not check the error condition on the fin.read()
1210 // before using the data, but the fin.gcount() will be zero if an
1211 // error occurred. Therefore, the loop should be safe everywhere.
1212 while(fin)
1214 fin.read(buffer, bufferSize);
1215 if(fin.gcount())
1217 cmsysMD5_Append(md5, reinterpret_cast<unsigned char const*>(buffer),
1218 fin.gcount());
1221 cmsysMD5_FinalizeHex(md5, md5out);
1222 cmsysMD5_Delete(md5);
1224 fin.close();
1225 return true;
1226 #else
1227 (void)source;
1228 (void)md5out;
1229 cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error");
1230 return false;
1231 #endif
1234 std::string cmSystemTools::ComputeStringMD5(const char* input)
1236 #if defined(CMAKE_BUILD_WITH_CMAKE)
1237 char md5out[32];
1238 cmsysMD5* md5 = cmsysMD5_New();
1239 cmsysMD5_Initialize(md5);
1240 cmsysMD5_Append(md5, reinterpret_cast<unsigned char const*>(input), -1);
1241 cmsysMD5_FinalizeHex(md5, md5out);
1242 cmsysMD5_Delete(md5);
1243 return std::string(md5out, 32);
1244 #else
1245 (void)input;
1246 cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error");
1247 return "";
1248 #endif
1251 void cmSystemTools::Glob(const char *directory, const char *regexp,
1252 std::vector<std::string>& files)
1254 cmsys::Directory d;
1255 cmsys::RegularExpression reg(regexp);
1257 if (d.Load(directory))
1259 size_t numf;
1260 unsigned int i;
1261 numf = d.GetNumberOfFiles();
1262 for (i = 0; i < numf; i++)
1264 std::string fname = d.GetFile(i);
1265 if (reg.find(fname))
1267 files.push_back(fname);
1274 void cmSystemTools::GlobDirs(const char *fullPath,
1275 std::vector<std::string>& files)
1277 std::string path = fullPath;
1278 std::string::size_type pos = path.find("/*");
1279 if(pos == std::string::npos)
1281 files.push_back(fullPath);
1282 return;
1284 std::string startPath = path.substr(0, pos);
1285 std::string finishPath = path.substr(pos+2);
1287 cmsys::Directory d;
1288 if (d.Load(startPath.c_str()))
1290 for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
1292 if((std::string(d.GetFile(i)) != ".")
1293 && (std::string(d.GetFile(i)) != ".."))
1295 std::string fname = startPath;
1296 fname +="/";
1297 fname += d.GetFile(i);
1298 if(cmSystemTools::FileIsDirectory(fname.c_str()))
1300 fname += finishPath;
1301 cmSystemTools::GlobDirs(fname.c_str(), files);
1309 void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
1310 std::vector<std::string>& newargs)
1312 std::vector<std::string>::const_iterator i;
1313 for(i = arguments.begin();i != arguments.end(); ++i)
1315 cmSystemTools::ExpandListArgument(*i, newargs);
1319 void cmSystemTools::ExpandListArgument(const std::string& arg,
1320 std::vector<std::string>& newargs,
1321 bool emptyArgs)
1323 // If argument is empty, it is an empty list.
1324 if(arg.length() == 0 && !emptyArgs)
1326 return;
1328 // if there are no ; in the name then just copy the current string
1329 if(arg.find(';') == std::string::npos)
1331 newargs.push_back(arg);
1332 return;
1334 std::vector<char> newArgVec;
1335 // Break the string at non-escaped semicolons not nested in [].
1336 int squareNesting = 0;
1337 for(const char* c = arg.c_str(); *c; ++c)
1339 switch(*c)
1341 case '\\':
1343 // We only want to allow escaping of semicolons. Other
1344 // escapes should not be processed here.
1345 ++c;
1346 if(*c == ';')
1348 newArgVec.push_back(*c);
1350 else
1352 newArgVec.push_back('\\');
1353 if(*c)
1355 newArgVec.push_back(*c);
1357 else
1359 // Terminate the loop properly.
1360 --c;
1363 } break;
1364 case '[':
1366 ++squareNesting;
1367 newArgVec.push_back(*c);
1368 } break;
1369 case ']':
1371 --squareNesting;
1372 newArgVec.push_back(*c);
1373 } break;
1374 case ';':
1376 // Break the string here if we are not nested inside square
1377 // brackets.
1378 if(squareNesting == 0)
1380 if ( newArgVec.size() || emptyArgs )
1382 // Add the last argument if the string is not empty.
1383 newArgVec.push_back(0);
1384 newargs.push_back(&*newArgVec.begin());
1385 newArgVec.clear();
1388 else
1390 newArgVec.push_back(*c);
1392 } break;
1393 default:
1395 // Just append this character.
1396 newArgVec.push_back(*c);
1397 } break;
1400 if ( newArgVec.size() || emptyArgs )
1402 // Add the last argument if the string is not empty.
1403 newArgVec.push_back(0);
1404 newargs.push_back(&*newArgVec.begin());
1408 bool cmSystemTools::SimpleGlob(const cmStdString& glob,
1409 std::vector<cmStdString>& files,
1410 int type /* = 0 */)
1412 files.clear();
1413 if ( glob[glob.size()-1] != '*' )
1415 return false;
1417 std::string path = cmSystemTools::GetFilenamePath(glob);
1418 std::string ppath = cmSystemTools::GetFilenameName(glob);
1419 ppath = ppath.substr(0, ppath.size()-1);
1420 if ( path.size() == 0 )
1422 path = "/";
1425 bool res = false;
1426 cmsys::Directory d;
1427 if (d.Load(path.c_str()))
1429 for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
1431 if((std::string(d.GetFile(i)) != ".")
1432 && (std::string(d.GetFile(i)) != ".."))
1434 std::string fname = path;
1435 if ( path[path.size()-1] != '/' )
1437 fname +="/";
1439 fname += d.GetFile(i);
1440 std::string sfname = d.GetFile(i);
1441 if ( type > 0 && cmSystemTools::FileIsDirectory(fname.c_str()) )
1443 continue;
1445 if ( type < 0 && !cmSystemTools::FileIsDirectory(fname.c_str()) )
1447 continue;
1449 if ( sfname.size() >= ppath.size() &&
1450 sfname.substr(0, ppath.size()) ==
1451 ppath )
1453 files.push_back(fname);
1454 res = true;
1459 return res;
1462 cmSystemTools::FileFormat cmSystemTools::GetFileFormat(const char* cext)
1464 if ( ! cext || *cext == 0 )
1466 return cmSystemTools::NO_FILE_FORMAT;
1468 //std::string ext = cmSystemTools::LowerCase(cext);
1469 std::string ext = cext;
1470 if ( ext == "c" || ext == ".c" ||
1471 ext == "m" || ext == ".m"
1472 ) { return cmSystemTools::C_FILE_FORMAT; }
1473 if (
1474 ext == "C" || ext == ".C" ||
1475 ext == "M" || ext == ".M" ||
1476 ext == "c++" || ext == ".c++" ||
1477 ext == "cc" || ext == ".cc" ||
1478 ext == "cpp" || ext == ".cpp" ||
1479 ext == "cxx" || ext == ".cxx" ||
1480 ext == "mm" || ext == ".mm"
1481 ) { return cmSystemTools::CXX_FILE_FORMAT; }
1482 if (
1483 ext == "f" || ext == ".f" ||
1484 ext == "F" || ext == ".F" ||
1485 ext == "f77" || ext == ".f77" ||
1486 ext == "f90" || ext == ".f90" ||
1487 ext == "for" || ext == ".for" ||
1488 ext == "f95" || ext == ".f95"
1489 ) { return cmSystemTools::FORTRAN_FILE_FORMAT; }
1490 if ( ext == "java" || ext == ".java" )
1491 { return cmSystemTools::JAVA_FILE_FORMAT; }
1492 if (
1493 ext == "H" || ext == ".H" ||
1494 ext == "h" || ext == ".h" ||
1495 ext == "h++" || ext == ".h++" ||
1496 ext == "hm" || ext == ".hm" ||
1497 ext == "hpp" || ext == ".hpp" ||
1498 ext == "hxx" || ext == ".hxx" ||
1499 ext == "in" || ext == ".in" ||
1500 ext == "txx" || ext == ".txx"
1501 ) { return cmSystemTools::HEADER_FILE_FORMAT; }
1502 if ( ext == "rc" || ext == ".rc" )
1503 { return cmSystemTools::RESOURCE_FILE_FORMAT; }
1504 if ( ext == "def" || ext == ".def" )
1505 { return cmSystemTools::DEFINITION_FILE_FORMAT; }
1506 if ( ext == "lib" || ext == ".lib" ||
1507 ext == "a" || ext == ".a")
1508 { return cmSystemTools::STATIC_LIBRARY_FILE_FORMAT; }
1509 if ( ext == "o" || ext == ".o" ||
1510 ext == "obj" || ext == ".obj")
1511 { return cmSystemTools::OBJECT_FILE_FORMAT; }
1512 #ifdef __APPLE__
1513 if ( ext == "dylib" || ext == ".dylib" )
1514 { return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT; }
1515 if ( ext == "so" || ext == ".so" ||
1516 ext == "bundle" || ext == ".bundle" )
1517 { return cmSystemTools::MODULE_FILE_FORMAT; }
1518 #else // __APPLE__
1519 if ( ext == "so" || ext == ".so" ||
1520 ext == "sl" || ext == ".sl" ||
1521 ext == "dll" || ext == ".dll" )
1522 { return cmSystemTools::SHARED_LIBRARY_FILE_FORMAT; }
1523 #endif // __APPLE__
1524 return cmSystemTools::UNKNOWN_FILE_FORMAT;
1527 bool cmSystemTools::Split(const char* s, std::vector<cmStdString>& l)
1529 std::vector<std::string> temp;
1530 bool res = Superclass::Split(s, temp);
1531 for(std::vector<std::string>::const_iterator i = temp.begin();
1532 i != temp.end(); ++i)
1534 l.push_back(*i);
1536 return res;
1539 std::string cmSystemTools::ConvertToOutputPath(const char* path)
1541 #if defined(_WIN32) && !defined(__CYGWIN__)
1542 if(s_ForceUnixPaths)
1544 return cmSystemTools::ConvertToUnixOutputPath(path);
1546 return cmSystemTools::ConvertToWindowsOutputPath(path);
1547 #else
1548 return cmSystemTools::ConvertToUnixOutputPath(path);
1549 #endif
1552 void cmSystemTools::ConvertToOutputSlashes(std::string& path)
1554 #if defined(_WIN32) && !defined(__CYGWIN__)
1555 if(!s_ForceUnixPaths)
1557 // Convert to windows slashes.
1558 std::string::size_type pos = 0;
1559 while((pos = path.find('/', pos)) != std::string::npos)
1561 path[pos++] = '\\';
1564 #else
1565 static_cast<void>(path);
1566 #endif
1569 std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
1571 #if defined(_WIN32) && !defined(__CYGWIN__)
1572 return cmSystemTools::ConvertToWindowsOutputPath(path);
1573 #else
1574 return cmSystemTools::ConvertToUnixOutputPath(path);
1575 #endif
1578 bool cmSystemTools::StringEndsWith(const char* str1, const char* str2)
1580 if ( !str1 || !str2 || strlen(str1) < strlen(str2) )
1582 return 0;
1584 return !strncmp(str1 + (strlen(str1)-strlen(str2)), str2, strlen(str2));
1587 // compute the relative path from here to there
1588 std::string cmSystemTools::RelativePath(const char* local, const char* remote)
1590 if(!cmSystemTools::FileIsFullPath(local))
1592 cmSystemTools::Error("RelativePath must be passed a full path to local: ",
1593 local);
1595 if(!cmSystemTools::FileIsFullPath(remote))
1597 cmSystemTools::Error
1598 ("RelativePath must be passed a full path to remote: ", remote);
1600 return cmsys::SystemTools::RelativePath(local, remote);
1603 #ifdef CMAKE_BUILD_WITH_CMAKE
1604 //----------------------------------------------------------------------
1605 bool cmSystemTools::UnsetEnv(const char* value)
1607 #if !defined(HAVE_UNSETENV)
1608 std::string var = value;
1609 var += "=";
1610 return cmSystemTools::PutEnv(var.c_str());
1611 #else
1612 unsetenv(value);
1613 return true;
1614 #endif
1617 //----------------------------------------------------------------------
1618 std::vector<std::string> cmSystemTools::GetEnvironmentVariables()
1620 std::vector<std::string> env;
1621 int cc;
1622 for ( cc = 0; environ[cc]; ++ cc )
1624 env.push_back(environ[cc]);
1626 return env;
1629 //----------------------------------------------------------------------
1630 std::vector<std::string> cmSystemTools::AppendEnv(
1631 std::vector<std::string>* env)
1633 std::vector<std::string> origEnv = GetEnvironmentVariables();
1635 if (env && env->size()>0)
1637 std::vector<std::string>::const_iterator eit;
1639 for (eit = env->begin(); eit!= env->end(); ++eit)
1641 PutEnv(eit->c_str());
1645 return origEnv;
1648 //----------------------------------------------------------------------
1649 void cmSystemTools::RestoreEnv(const std::vector<std::string>& env)
1651 std::vector<std::string>::const_iterator eit;
1653 // First clear everything in the current environment:
1655 std::vector<std::string> currentEnv = GetEnvironmentVariables();
1656 for (eit = currentEnv.begin(); eit!= currentEnv.end(); ++eit)
1658 std::string var(*eit);
1660 std::string::size_type pos = var.find("=");
1661 if (pos != std::string::npos)
1663 var = var.substr(0, pos);
1666 UnsetEnv(var.c_str());
1669 // Then put back each entry from the original environment:
1671 for (eit = env.begin(); eit!= env.end(); ++eit)
1673 PutEnv(eit->c_str());
1676 #endif
1678 void cmSystemTools::EnableVSConsoleOutput()
1680 // Visual Studio 8 2005 (devenv.exe or VCExpress.exe) will not
1681 // display output to the console unless this environment variable is
1682 // set. We need it to capture the output of these build tools.
1683 // Note for future work that one could pass "/out \\.\pipe\NAME" to
1684 // either of these executables where NAME is created with
1685 // CreateNamedPipe. This would bypass the internal buffering of the
1686 // output and allow it to be captured on the fly.
1687 #ifdef _WIN32
1688 cmSystemTools::PutEnv("vsconsoleoutput=1");
1689 #endif
1692 bool cmSystemTools::IsPathToFramework(const char* path)
1694 if(cmSystemTools::FileIsFullPath(path))
1696 std::string libname = path;
1697 if(libname.find(".framework") == libname.size()+1-sizeof(".framework"))
1699 return true;
1702 return false;
1705 #if defined(CMAKE_BUILD_WITH_CMAKE)
1706 struct cmSystemToolsGZStruct
1708 gzFile GZFile;
1711 extern "C" {
1712 int cmSystemToolsGZStructOpen(void* call_data, const char *pathname,
1713 int oflags, mode_t mode);
1714 int cmSystemToolsGZStructClose(void* call_data);
1715 ssize_t cmSystemToolsGZStructRead(void* call_data, void* buf, size_t count);
1716 ssize_t cmSystemToolsGZStructWrite(void* call_data, const void* buf,
1717 size_t count);
1720 int cmSystemToolsGZStructOpen(void* call_data, const char *pathname,
1721 int oflags, mode_t mode)
1723 const char *gzoflags;
1724 int fd;
1726 cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data);
1728 switch (oflags & O_ACCMODE)
1730 case O_WRONLY:
1731 gzoflags = "wb";
1732 break;
1733 case O_RDONLY:
1734 gzoflags = "rb";
1735 break;
1736 default:
1737 case O_RDWR:
1738 errno = EINVAL;
1739 return -1;
1742 fd = open(pathname, oflags, mode);
1743 if (fd == -1)
1745 return -1;
1748 // no fchmod on BeOS 5...do pathname instead.
1749 #if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__)
1750 if ((oflags & O_CREAT) && chmod(pathname, mode))
1752 return -1;
1754 #elif !defined(_WIN32) || defined(__CYGWIN__)
1755 if ((oflags & O_CREAT) && fchmod(fd, mode))
1757 return -1;
1759 #endif
1761 gzf->GZFile = gzdopen(fd, gzoflags);
1762 if (!gzf->GZFile)
1764 errno = ENOMEM;
1765 return -1;
1768 return fd;
1771 int cmSystemToolsGZStructClose(void* call_data)
1773 cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data);
1774 return gzclose(gzf->GZFile);
1777 ssize_t cmSystemToolsGZStructRead(void* call_data, void* buf, size_t count)
1779 cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data);
1780 return gzread(gzf->GZFile, buf, static_cast<int>(count));
1783 ssize_t cmSystemToolsGZStructWrite(void* call_data, const void* buf,
1784 size_t count)
1786 cmSystemToolsGZStruct* gzf = static_cast<cmSystemToolsGZStruct*>(call_data);
1787 return gzwrite(gzf->GZFile, (void*)buf, static_cast<int>(count));
1790 #endif
1792 bool cmSystemTools::CreateTar(const char* outFileName,
1793 const std::vector<cmStdString>& files,
1794 bool gzip, bool verbose)
1796 #if defined(CMAKE_BUILD_WITH_CMAKE)
1797 TAR *t;
1798 char buf[TAR_MAXPATHLEN];
1799 char pathname[TAR_MAXPATHLEN];
1800 cmSystemToolsGZStruct gzs;
1802 tartype_t gztype = {
1803 (openfunc_t)cmSystemToolsGZStructOpen,
1804 (closefunc_t)cmSystemToolsGZStructClose,
1805 (readfunc_t)cmSystemToolsGZStructRead,
1806 (writefunc_t)cmSystemToolsGZStructWrite,
1807 &gzs
1810 // Ok, this libtar is not const safe. for now use auto_ptr hack
1811 char* realName = new char[ strlen(outFileName) + 1 ];
1812 std::auto_ptr<char> realNamePtr(realName);
1813 strcpy(realName, outFileName);
1814 int options = 0;
1815 if(verbose)
1817 options |= TAR_VERBOSE;
1819 #ifdef __CYGWIN__
1820 options |= TAR_GNU;
1821 #endif
1822 if (tar_open(&t, realName,
1823 (gzip? &gztype : NULL),
1824 O_WRONLY | O_CREAT, 0644,
1825 options) == -1)
1827 cmSystemTools::Error("Problem with tar_open(): ", strerror(errno));
1828 return false;
1831 std::vector<cmStdString>::const_iterator it;
1832 for (it = files.begin(); it != files.end(); ++ it )
1834 strncpy(pathname, it->c_str(), sizeof(pathname));
1835 pathname[sizeof(pathname)-1] = 0;
1836 strncpy(buf, pathname, sizeof(buf));
1837 buf[sizeof(buf)-1] = 0;
1838 if (tar_append_tree(t, buf, pathname) != 0)
1840 cmOStringStream ostr;
1841 ostr << "Problem with tar_append_tree(\"" << buf << "\", \""
1842 << pathname << "\"): "
1843 << strerror(errno);
1844 cmSystemTools::Error(ostr.str().c_str());
1845 tar_close(t);
1846 return false;
1850 if (tar_append_eof(t) != 0)
1852 cmSystemTools::Error("Problem with tar_append_eof(): ", strerror(errno));
1853 tar_close(t);
1854 return false;
1857 if (tar_close(t) != 0)
1859 cmSystemTools::Error("Problem with tar_close(): ", strerror(errno));
1860 return false;
1862 return true;
1863 #else
1864 (void)outFileName;
1865 (void)files;
1866 (void)gzip;
1867 (void)verbose;
1868 return false;
1869 #endif
1872 bool cmSystemTools::ExtractTar(const char* outFileName,
1873 const std::vector<cmStdString>& files,
1874 bool gzip, bool verbose)
1876 (void)files;
1877 #if defined(CMAKE_BUILD_WITH_CMAKE)
1878 TAR *t;
1879 cmSystemToolsGZStruct gzs;
1881 tartype_t gztype = {
1882 cmSystemToolsGZStructOpen,
1883 cmSystemToolsGZStructClose,
1884 cmSystemToolsGZStructRead,
1885 cmSystemToolsGZStructWrite,
1886 &gzs
1889 // Ok, this libtar is not const safe. for now use auto_ptr hack
1890 char* realName = new char[ strlen(outFileName) + 1 ];
1891 std::auto_ptr<char> realNamePtr(realName);
1892 strcpy(realName, outFileName);
1893 if (tar_open(&t, realName,
1894 (gzip? &gztype : NULL),
1895 O_RDONLY
1896 #ifdef _WIN32
1897 | O_BINARY
1898 #endif
1899 , 0,
1900 (verbose?TAR_VERBOSE:0)
1901 | 0) == -1)
1903 cmSystemTools::Error("Problem with tar_open(): ", strerror(errno));
1904 return false;
1907 if (tar_extract_all(t, 0) != 0)
1909 cmSystemTools::Error("Problem with tar_extract_all(): ", strerror(errno));
1910 return false;
1913 if (tar_close(t) != 0)
1915 cmSystemTools::Error("Problem with tar_close(): ", strerror(errno));
1916 return false;
1918 return true;
1919 #else
1920 (void)outFileName;
1921 (void)gzip;
1922 (void)verbose;
1923 return false;
1924 #endif
1927 bool cmSystemTools::ListTar(const char* outFileName,
1928 std::vector<cmStdString>& files, bool gzip,
1929 bool verbose)
1931 #if defined(CMAKE_BUILD_WITH_CMAKE)
1932 TAR *t;
1933 cmSystemToolsGZStruct gzs;
1935 tartype_t gztype = {
1936 cmSystemToolsGZStructOpen,
1937 cmSystemToolsGZStructClose,
1938 cmSystemToolsGZStructRead,
1939 cmSystemToolsGZStructWrite,
1940 &gzs
1943 // Ok, this libtar is not const safe. for now use auto_ptr hack
1944 char* realName = new char[ strlen(outFileName) + 1 ];
1945 std::auto_ptr<char> realNamePtr(realName);
1946 strcpy(realName, outFileName);
1947 if (tar_open(&t, realName,
1948 (gzip? &gztype : NULL),
1949 O_RDONLY
1950 #ifdef _WIN32
1951 | O_BINARY
1952 #endif
1953 , 0,
1954 (verbose?TAR_VERBOSE:0)
1955 | 0) == -1)
1957 cmSystemTools::Error("Problem with tar_open(): ", strerror(errno));
1958 return false;
1961 while ((th_read(t)) == 0)
1963 const char* filename = th_get_pathname(t);
1964 files.push_back(filename);
1966 if ( verbose )
1968 th_print_long_ls(t);
1970 else
1972 std::cout << filename << std::endl;
1975 #ifdef DEBUG
1976 th_print(t);
1977 #endif
1978 if (TH_ISREG(t) && tar_skip_regfile(t) != 0)
1980 cmSystemTools::Error("Problem with tar_skip_regfile(): ",
1981 strerror(errno));
1982 return false;
1986 if (tar_close(t) != 0)
1988 cmSystemTools::Error("Problem with tar_close(): ", strerror(errno));
1989 return false;
1991 return true;
1992 #else
1993 (void)outFileName;
1994 (void)files;
1995 (void)gzip;
1996 (void)verbose;
1997 return false;
1998 #endif
2001 int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
2002 double timeout,
2003 std::vector<char>& out,
2004 std::vector<char>& err)
2006 line = "";
2007 std::vector<char>::iterator outiter = out.begin();
2008 std::vector<char>::iterator erriter = err.begin();
2009 while(1)
2011 // Check for a newline in stdout.
2012 for(;outiter != out.end(); ++outiter)
2014 if((*outiter == '\r') && ((outiter+1) == out.end()))
2016 break;
2018 else if(*outiter == '\n' || *outiter == '\0')
2020 int length = outiter-out.begin();
2021 if(length > 1 && *(outiter-1) == '\r')
2023 --length;
2025 if(length > 0)
2027 line.append(&out[0], length);
2029 out.erase(out.begin(), outiter+1);
2030 return cmsysProcess_Pipe_STDOUT;
2034 // Check for a newline in stderr.
2035 for(;erriter != err.end(); ++erriter)
2037 if((*erriter == '\r') && ((erriter+1) == err.end()))
2039 break;
2041 else if(*erriter == '\n' || *erriter == '\0')
2043 int length = erriter-err.begin();
2044 if(length > 1 && *(erriter-1) == '\r')
2046 --length;
2048 if(length > 0)
2050 line.append(&err[0], length);
2052 err.erase(err.begin(), erriter+1);
2053 return cmsysProcess_Pipe_STDERR;
2057 // No newlines found. Wait for more data from the process.
2058 int length;
2059 char* data;
2060 int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout);
2061 if(pipe == cmsysProcess_Pipe_Timeout)
2063 // Timeout has been exceeded.
2064 return pipe;
2066 else if(pipe == cmsysProcess_Pipe_STDOUT)
2068 // Append to the stdout buffer.
2069 std::vector<char>::size_type size = out.size();
2070 out.insert(out.end(), data, data+length);
2071 outiter = out.begin()+size;
2073 else if(pipe == cmsysProcess_Pipe_STDERR)
2075 // Append to the stderr buffer.
2076 std::vector<char>::size_type size = err.size();
2077 err.insert(err.end(), data, data+length);
2078 erriter = err.begin()+size;
2080 else if(pipe == cmsysProcess_Pipe_None)
2082 // Both stdout and stderr pipes have broken. Return leftover data.
2083 if(!out.empty())
2085 line.append(&out[0], outiter-out.begin());
2086 out.erase(out.begin(), out.end());
2087 return cmsysProcess_Pipe_STDOUT;
2089 else if(!err.empty())
2091 line.append(&err[0], erriter-err.begin());
2092 err.erase(err.begin(), err.end());
2093 return cmsysProcess_Pipe_STDERR;
2095 else
2097 return cmsysProcess_Pipe_None;
2103 void cmSystemTools::DoNotInheritStdPipes()
2105 #ifdef _WIN32
2106 // Check to see if we are attached to a console
2107 // if so, then do not stop the inherited pipes
2108 // or stdout and stderr will not show up in dos
2109 // shell windows
2110 CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
2111 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
2112 if(GetConsoleScreenBufferInfo(hOut, &hOutInfo))
2114 return;
2117 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
2118 DuplicateHandle(GetCurrentProcess(), out,
2119 GetCurrentProcess(), &out, 0, FALSE,
2120 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2121 SetStdHandle(STD_OUTPUT_HANDLE, out);
2124 HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
2125 DuplicateHandle(GetCurrentProcess(), out,
2126 GetCurrentProcess(), &out, 0, FALSE,
2127 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2128 SetStdHandle(STD_ERROR_HANDLE, out);
2130 #endif
2133 //----------------------------------------------------------------------------
2134 bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
2136 #if defined(_WIN32) && !defined(__CYGWIN__)
2137 cmSystemToolsWindowsHandle hFrom =
2138 CreateFile(fromFile, GENERIC_READ, FILE_SHARE_READ, 0,
2139 OPEN_EXISTING, 0, 0);
2140 cmSystemToolsWindowsHandle hTo =
2141 CreateFile(toFile, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
2142 if(!hFrom || !hTo)
2144 return false;
2146 FILETIME timeCreation;
2147 FILETIME timeLastAccess;
2148 FILETIME timeLastWrite;
2149 if(!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite))
2151 return false;
2153 if(!SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite))
2155 return false;
2157 #else
2158 struct stat fromStat;
2159 if(stat(fromFile, &fromStat) < 0)
2161 return false;
2164 struct utimbuf buf;
2165 buf.actime = fromStat.st_atime;
2166 buf.modtime = fromStat.st_mtime;
2167 if(utime(toFile, &buf) < 0)
2169 return false;
2171 #endif
2172 return true;
2175 //----------------------------------------------------------------------------
2176 cmSystemToolsFileTime* cmSystemTools::FileTimeNew()
2178 return new cmSystemToolsFileTime;
2181 //----------------------------------------------------------------------------
2182 void cmSystemTools::FileTimeDelete(cmSystemToolsFileTime* t)
2184 delete t;
2187 //----------------------------------------------------------------------------
2188 bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t)
2190 #if defined(_WIN32) && !defined(__CYGWIN__)
2191 cmSystemToolsWindowsHandle h =
2192 CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
2193 if(!h)
2195 return false;
2197 if(!GetFileTime(h, &t->timeCreation, &t->timeLastAccess, &t->timeLastWrite))
2199 return false;
2201 #else
2202 struct stat st;
2203 if(stat(fname, &st) < 0)
2205 return false;
2207 t->timeBuf.actime = st.st_atime;
2208 t->timeBuf.modtime = st.st_mtime;
2209 #endif
2210 return true;
2213 //----------------------------------------------------------------------------
2214 bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
2216 #if defined(_WIN32) && !defined(__CYGWIN__)
2217 cmSystemToolsWindowsHandle h =
2218 CreateFile(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
2219 if(!h)
2221 return false;
2223 if(!SetFileTime(h, &t->timeCreation, &t->timeLastAccess, &t->timeLastWrite))
2225 return false;
2227 #else
2228 if(utime(fname, &t->timeBuf) < 0)
2230 return false;
2232 #endif
2233 return true;
2236 //----------------------------------------------------------------------------
2237 static std::string cmSystemToolsExecutableDirectory;
2238 void cmSystemTools::FindExecutableDirectory(const char* argv0)
2240 #if defined(_WIN32) && !defined(__CYGWIN__)
2241 (void)argv0; // ignore this on windows
2242 char modulepath[_MAX_PATH];
2243 ::GetModuleFileName(NULL, modulepath, sizeof(modulepath));
2244 cmSystemToolsExecutableDirectory =
2245 cmSystemTools::GetFilenamePath(modulepath);
2246 return;
2247 #else
2248 std::string errorMsg;
2249 std::string exe;
2250 if(cmSystemTools::FindProgramPath(argv0, exe, errorMsg))
2252 // remove symlinks
2253 exe = cmSystemTools::GetRealPath(exe.c_str());
2254 cmSystemToolsExecutableDirectory =
2255 cmSystemTools::GetFilenamePath(exe.c_str());
2257 else
2259 // ???
2261 #endif
2264 //----------------------------------------------------------------------------
2265 const char* cmSystemTools::GetExecutableDirectory()
2267 return cmSystemToolsExecutableDirectory.c_str();
2270 //----------------------------------------------------------------------------
2271 #if defined(CMAKE_BUILD_WITH_CMAKE)
2272 void cmSystemTools::MakefileColorEcho(int color, const char* message,
2273 bool newline, bool enabled)
2275 // On some platforms (an MSYS prompt) cmsysTerminal may not be able
2276 // to determine whether the stream is displayed on a tty. In this
2277 // case it assumes no unless we tell it otherwise. Since we want
2278 // color messages to be displayed for users we will assume yes.
2279 // However, we can test for some situations when the answer is most
2280 // likely no.
2281 int assumeTTY = cmsysTerminal_Color_AssumeTTY;
2282 if(cmSystemTools::GetEnv("DART_TEST_FROM_DART") ||
2283 cmSystemTools::GetEnv("DASHBOARD_TEST_FROM_CTEST") ||
2284 cmSystemTools::GetEnv("CTEST_INTERACTIVE_DEBUG_MODE"))
2286 // Avoid printing color escapes during dashboard builds.
2287 assumeTTY = 0;
2290 if(enabled)
2292 cmsysTerminal_cfprintf(color | assumeTTY, stdout, "%s%s",
2293 message, newline? "\n" : "");
2295 else
2297 // Color is disabled. Print without color.
2298 fprintf(stdout, "%s%s", message, newline? "\n" : "");
2301 #endif
2303 //----------------------------------------------------------------------------
2304 bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
2305 std::string& soname)
2307 // For ELF shared libraries use a real parser to get the correct
2308 // soname.
2309 #if defined(CMAKE_USE_ELF_PARSER)
2310 cmELF elf(fullPath.c_str());
2311 if(elf)
2313 return elf.GetSOName(soname);
2315 #endif
2317 // If the file is not a symlink we have no guess for its soname.
2318 if(!cmSystemTools::FileIsSymlink(fullPath.c_str()))
2320 return false;
2322 if(!cmSystemTools::ReadSymlink(fullPath.c_str(), soname))
2324 return false;
2327 // If the symlink has a path component we have no guess for the soname.
2328 if(!cmSystemTools::GetFilenamePath(soname).empty())
2330 return false;
2333 // If the symlink points at an extended version of the same name
2334 // assume it is the soname.
2335 std::string name = cmSystemTools::GetFilenameName(fullPath);
2336 if(soname.length() > name.length() &&
2337 soname.substr(0, name.length()) == name)
2339 return true;
2341 return false;
2344 //----------------------------------------------------------------------------
2345 #if defined(CMAKE_USE_ELF_PARSER)
2346 std::string::size_type cmSystemToolsFindRPath(std::string const& have,
2347 std::string const& want)
2349 // Search for the desired rpath.
2350 std::string::size_type pos = have.find(want);
2352 // If the path is not present we are done.
2353 if(pos == std::string::npos)
2355 return pos;
2358 // Build a regex to match a properly separated path instance.
2359 std::string regex_str = "(^|:)(";
2360 for(std::string::const_iterator i = want.begin(); i != want.end(); ++i)
2362 int ch = *i;
2363 if(!(('a' <= ch && ch <= 'z') ||
2364 ('A' <= ch && ch <= 'Z') ||
2365 ('0' <= ch && ch <= '9')))
2367 // Escape the non-alphanumeric character.
2368 regex_str += "\\";
2370 // Store the character.
2371 regex_str.append(1, static_cast<char>(ch));
2373 regex_str += ")(:|$)";
2375 // Look for the separated path.
2376 cmsys::RegularExpression regex(regex_str.c_str());
2377 if(regex.find(have))
2379 // Return the position of the path portion.
2380 return regex.start(2);
2382 else
2384 // The desired rpath was not found.
2385 return std::string::npos;
2388 #endif
2390 #if defined(CMAKE_USE_ELF_PARSER)
2391 struct cmSystemToolsRPathInfo
2393 unsigned long Position;
2394 unsigned long Size;
2395 std::string Name;
2396 std::string Value;
2398 #endif
2400 //----------------------------------------------------------------------------
2401 bool cmSystemTools::ChangeRPath(std::string const& file,
2402 std::string const& oldRPath,
2403 std::string const& newRPath,
2404 std::string* emsg,
2405 bool* changed)
2407 #if defined(CMAKE_USE_ELF_PARSER)
2408 if(changed)
2410 *changed = false;
2412 int rp_count = 0;
2413 cmSystemToolsRPathInfo rp[2];
2415 // Parse the ELF binary.
2416 cmELF elf(file.c_str());
2418 // Get the RPATH and RUNPATH entries from it.
2419 int se_count = 0;
2420 cmELF::StringEntry const* se[2] = {0, 0};
2421 const char* se_name[2] = {0, 0};
2422 if(cmELF::StringEntry const* se_rpath = elf.GetRPath())
2424 se[se_count] = se_rpath;
2425 se_name[se_count] = "RPATH";
2426 ++se_count;
2428 if(cmELF::StringEntry const* se_runpath = elf.GetRunPath())
2430 se[se_count] = se_runpath;
2431 se_name[se_count] = "RUNPATH";
2432 ++se_count;
2434 if(se_count == 0)
2436 if(newRPath.empty())
2438 // The new rpath is empty and there is no rpath anyway so it is
2439 // okay.
2440 return true;
2442 else
2444 if(emsg)
2446 *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; ";
2447 *emsg += elf.GetErrorMessage();
2449 return false;
2453 for(int i=0; i < se_count; ++i)
2455 // If both RPATH and RUNPATH refer to the same string literal it
2456 // needs to be changed only once.
2457 if(rp_count && rp[0].Position == se[i]->Position)
2459 continue;
2462 // Make sure the current rpath contains the old rpath.
2463 std::string::size_type pos =
2464 cmSystemToolsFindRPath(se[i]->Value, oldRPath);
2465 if(pos == std::string::npos)
2467 // If it contains the new rpath instead then it is okay.
2468 if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos)
2470 continue;
2472 if(emsg)
2474 cmOStringStream e;
2475 e << "The current " << se_name[i] << " is:\n"
2476 << " " << se[i]->Value << "\n"
2477 << "which does not contain:\n"
2478 << " " << oldRPath << "\n"
2479 << "as was expected.";
2480 *emsg = e.str();
2482 return false;
2485 // Store information about the entry in the file.
2486 rp[rp_count].Position = se[i]->Position;
2487 rp[rp_count].Size = se[i]->Size;
2488 rp[rp_count].Name = se_name[i];
2490 // Construct the new value which preserves the part of the path
2491 // not being changed.
2492 rp[rp_count].Value = se[i]->Value.substr(0, pos);
2493 rp[rp_count].Value += newRPath;
2494 rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(),
2495 oldRPath.npos);
2497 // Make sure there is enough room to store the new rpath and at
2498 // least one null terminator.
2499 if(rp[rp_count].Size < rp[rp_count].Value.length()+1)
2501 if(emsg)
2503 *emsg = "The replacement path is too long for the ";
2504 *emsg += se_name[i];
2505 *emsg += " entry.";
2507 return false;
2510 // This entry is ready for update.
2511 ++rp_count;
2515 // If no runtime path needs to be changed, we are done.
2516 if(rp_count == 0)
2518 return true;
2522 // Open the file for update.
2523 std::ofstream f(file.c_str(),
2524 std::ios::in | std::ios::out | std::ios::binary);
2525 if(!f)
2527 if(emsg)
2529 *emsg = "Error opening file for update.";
2531 return false;
2534 // Store the new RPATH and RUNPATH strings.
2535 for(int i=0; i < rp_count; ++i)
2537 // Seek to the RPATH position.
2538 if(!f.seekp(rp[i].Position))
2540 if(emsg)
2542 *emsg = "Error seeking to ";
2543 *emsg += rp[i].Name;
2544 *emsg += " position.";
2546 return false;
2549 // Write the new rpath. Follow it with enough null terminators to
2550 // fill the string table entry.
2551 f << rp[i].Value;
2552 for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j)
2554 f << '\0';
2557 // Make sure it wrote correctly.
2558 if(!f)
2560 if(emsg)
2562 *emsg = "Error writing the new ";
2563 *emsg += rp[i].Name;
2564 *emsg += " string to the file.";
2566 return false;
2571 // Everything was updated successfully.
2572 if(changed)
2574 *changed = true;
2576 return true;
2577 #else
2578 (void)file;
2579 (void)oldRPath;
2580 (void)newRPath;
2581 (void)emsg;
2582 (void)changed;
2583 return false;
2584 #endif
2587 //----------------------------------------------------------------------------
2588 bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
2589 bool* removed)
2591 #if defined(CMAKE_USE_ELF_PARSER)
2592 if(removed)
2594 *removed = false;
2596 int zeroCount = 0;
2597 unsigned long zeroPosition[2] = {0,0};
2598 unsigned long zeroSize[2] = {0,0};
2599 unsigned long bytesBegin = 0;
2600 std::vector<char> bytes;
2602 // Parse the ELF binary.
2603 cmELF elf(file.c_str());
2605 // Get the RPATH and RUNPATH entries from it and sort them by index
2606 // in the dynamic section header.
2607 int se_count = 0;
2608 cmELF::StringEntry const* se[2] = {0, 0};
2609 if(cmELF::StringEntry const* se_rpath = elf.GetRPath())
2611 se[se_count++] = se_rpath;
2613 if(cmELF::StringEntry const* se_runpath = elf.GetRunPath())
2615 se[se_count++] = se_runpath;
2617 if(se_count == 0)
2619 // There is no RPATH or RUNPATH anyway.
2620 return true;
2622 if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection)
2624 cmsys_stl::swap(se[0], se[1]);
2627 // Get the size of the dynamic section header.
2628 unsigned int count = elf.GetDynamicEntryCount();
2629 if(count == 0)
2631 // This should happen only for invalid ELF files where a DT_NULL
2632 // appears before the end of the table.
2633 if(emsg)
2635 *emsg = "DYNAMIC section contains a DT_NULL before the end.";
2637 return false;
2640 // Save information about the string entries to be zeroed.
2641 zeroCount = se_count;
2642 for(int i=0; i < se_count; ++i)
2644 zeroPosition[i] = se[i]->Position;
2645 zeroSize[i] = se[i]->Size;
2648 // Get the range of file positions corresponding to each entry and
2649 // the rest of the table after them.
2650 unsigned long entryBegin[3] = {0,0,0};
2651 unsigned long entryEnd[2] = {0,0};
2652 for(int i=0; i < se_count; ++i)
2654 entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection);
2655 entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1);
2657 entryBegin[se_count] = elf.GetDynamicEntryPosition(count);
2659 // The data are to be written over the old table entries starting at
2660 // the first one being removed.
2661 bytesBegin = entryBegin[0];
2662 unsigned long bytesEnd = entryBegin[se_count];
2664 // Allocate a buffer to hold the part of the file to be written.
2665 // Initialize it with zeros.
2666 bytes.resize(bytesEnd - bytesBegin, 0);
2668 // Read the part of the DYNAMIC section header that will move.
2669 // The remainder of the buffer will be left with zeros which
2670 // represent a DT_NULL entry.
2671 char* data = &bytes[0];
2672 for(int i=0; i < se_count; ++i)
2674 // Read data between the entries being removed.
2675 unsigned long sz = entryBegin[i+1] - entryEnd[i];
2676 if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data))
2678 if(emsg)
2680 *emsg = "Failed to read DYNAMIC section header.";
2682 return false;
2684 data += sz;
2688 // Open the file for update.
2689 std::ofstream f(file.c_str(),
2690 std::ios::in | std::ios::out | std::ios::binary);
2691 if(!f)
2693 if(emsg)
2695 *emsg = "Error opening file for update.";
2697 return false;
2700 // Write the new DYNAMIC table header.
2701 if(!f.seekp(bytesBegin))
2703 if(emsg)
2705 *emsg = "Error seeking to DYNAMIC table header for RPATH.";
2707 return false;
2709 if(!f.write(&bytes[0], bytes.size()))
2711 if(emsg)
2713 *emsg = "Error replacing DYNAMIC table header.";
2715 return false;
2718 // Fill the RPATH and RUNPATH strings with zero bytes.
2719 for(int i=0; i < zeroCount; ++i)
2721 if(!f.seekp(zeroPosition[i]))
2723 if(emsg)
2725 *emsg = "Error seeking to RPATH position.";
2727 return false;
2729 for(unsigned long j=0; j < zeroSize[i]; ++j)
2731 f << '\0';
2733 if(!f)
2735 if(emsg)
2737 *emsg = "Error writing the empty rpath string to the file.";
2739 return false;
2743 // Everything was updated successfully.
2744 if(removed)
2746 *removed = true;
2748 return true;
2749 #else
2750 (void)file;
2751 (void)emsg;
2752 (void)removed;
2753 return false;
2754 #endif
2757 //----------------------------------------------------------------------------
2758 bool cmSystemTools::CheckRPath(std::string const& file,
2759 std::string const& newRPath)
2761 #if defined(CMAKE_USE_ELF_PARSER)
2762 // Parse the ELF binary.
2763 cmELF elf(file.c_str());
2765 // Get the RPATH or RUNPATH entry from it.
2766 cmELF::StringEntry const* se = elf.GetRPath();
2767 if(!se)
2769 se = elf.GetRunPath();
2772 // Make sure the current rpath contains the new rpath.
2773 if(newRPath.empty())
2775 if(!se)
2777 return true;
2780 else
2782 if(se &&
2783 cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos)
2785 return true;
2788 return false;
2789 #else
2790 (void)file;
2791 (void)newRPath;
2792 return false;
2793 #endif