1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmProcess.cxx,v $
6 Date: $Date: 2009-01-14 18:48:03 $
7 Version: $Revision: 1.6 $
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 =========================================================================*/
18 #include <cmProcess.h>
19 #include <cmSystemTools.h>
21 cmProcess::cmProcess()
27 cmProcess::~cmProcess()
29 cmsysProcess_Delete(this->Process
);
31 void cmProcess::SetCommand(const char* command
)
33 this->Command
= command
;
36 void cmProcess::SetCommandArguments(std::vector
<std::string
> const& args
)
38 this->Arguments
= args
;
41 bool cmProcess::StartProcess()
43 if(this->Command
.size() == 0)
47 this->StartTime
= cmSystemTools::GetTime();
48 this->ProcessArgs
.clear();
49 // put the command as arg0
50 this->ProcessArgs
.push_back(this->Command
.c_str());
51 // now put the command arguments in
52 for(std::vector
<std::string
>::iterator i
= this->Arguments
.begin();
53 i
!= this->Arguments
.end(); ++i
)
55 this->ProcessArgs
.push_back(i
->c_str());
57 this->ProcessArgs
.push_back(0); // null terminate the list
58 this->Process
= cmsysProcess_New();
59 cmsysProcess_SetCommand(this->Process
, &*this->ProcessArgs
.begin());
60 if(this->WorkingDirectory
.size())
62 cmsysProcess_SetWorkingDirectory(this->Process
,
63 this->WorkingDirectory
.c_str());
65 cmsysProcess_SetOption(this->Process
, cmsysProcess_Option_HideWindow
, 1);
66 cmsysProcess_SetTimeout(this->Process
, this->Timeout
);
67 cmsysProcess_Execute(this->Process
);
68 return (cmsysProcess_GetState(this->Process
)
69 == cmsysProcess_State_Executing
);
72 // return true if there is a new line of data
73 // return false if there is no new data
74 int cmProcess::CheckOutput(double timeout
,
75 std::string
& stdOutLine
,
76 std::string
& stdErrLine
)
80 std::vector
<char>::iterator outiter
=
81 this->StdOutBuffer
.begin();
82 std::vector
<char>::iterator erriter
=
83 this->StdErrorBuffer
.begin();
86 // Check for a newline in stdout.
87 for(;outiter
!= this->StdOutBuffer
.end(); ++outiter
)
89 if((*outiter
== '\r') && ((outiter
+1) == this->StdOutBuffer
.end()))
93 else if(*outiter
== '\n' || *outiter
== '\0')
95 int length
= outiter
-this->StdOutBuffer
.begin();
96 if(length
> 1 && *(outiter
-1) == '\r')
102 stdOutLine
.append(&this->StdOutBuffer
[0], length
);
104 this->StdOutBuffer
.erase(this->StdOutBuffer
.begin(), outiter
+1);
105 this->LastOutputPipe
= cmsysProcess_Pipe_STDOUT
;
106 return this->LastOutputPipe
;;
110 // Check for a newline in stderr.
111 for(;erriter
!= this->StdErrorBuffer
.end(); ++erriter
)
113 if((*erriter
== '\r') && ((erriter
+1) == this->StdErrorBuffer
.end()))
117 else if(*erriter
== '\n' || *erriter
== '\0')
119 int length
= erriter
-this->StdErrorBuffer
.begin();
120 if(length
> 1 && *(erriter
-1) == '\r')
126 stdErrLine
.append(&this->StdErrorBuffer
[0], length
);
128 this->StdErrorBuffer
.erase(this->StdErrorBuffer
.begin(), erriter
+1);
129 this->LastOutputPipe
= cmsysProcess_Pipe_STDERR
;
130 return this->LastOutputPipe
;
134 // No newlines found. Wait for more data from the process.
137 int pipe
= cmsysProcess_WaitForData(this->Process
, &data
,
139 if(pipe
== cmsysProcess_Pipe_Timeout
)
141 // Timeout has been exceeded.
142 this->LastOutputPipe
= pipe
;
145 else if(pipe
== cmsysProcess_Pipe_STDOUT
)
147 // Append to the stdout buffer.
148 std::vector
<char>::size_type size
= this->StdOutBuffer
.size();
149 this->StdOutBuffer
.insert(this->StdOutBuffer
.end(), data
, data
+length
);
150 outiter
= this->StdOutBuffer
.begin()+size
;
152 else if(pipe
== cmsysProcess_Pipe_STDERR
)
154 // Append to the stderr buffer.
155 std::vector
<char>::size_type size
= this->StdErrorBuffer
.size();
156 this->StdErrorBuffer
.insert(this->StdErrorBuffer
.end(),
158 erriter
= this->StdErrorBuffer
.begin()+size
;
160 else if(pipe
== cmsysProcess_Pipe_None
)
162 // Both stdout and stderr pipes have broken. Return leftover data.
163 if(!this->StdOutBuffer
.empty())
165 stdOutLine
.append(&this->StdOutBuffer
[0],
166 outiter
-this->StdOutBuffer
.begin());
167 this->StdOutBuffer
.erase(this->StdOutBuffer
.begin(),
168 this->StdOutBuffer
.end());
169 this->LastOutputPipe
= cmsysProcess_Pipe_STDOUT
;
170 return this->LastOutputPipe
;
172 else if(!this->StdErrorBuffer
.empty())
174 stdErrLine
.append(&this->StdErrorBuffer
[0],
175 erriter
-this->StdErrorBuffer
.begin());
176 this->StdErrorBuffer
.erase(this->StdErrorBuffer
.begin(),
177 this->StdErrorBuffer
.end());
178 this->LastOutputPipe
= cmsysProcess_Pipe_STDERR
;
179 return this->LastOutputPipe
;
183 this->LastOutputPipe
= cmsysProcess_Pipe_None
;
184 return this->LastOutputPipe
;
191 // return the process status
192 int cmProcess::GetProcessStatus()
196 return cmsysProcess_State_Exited
;
198 return cmsysProcess_GetState(this->Process
);
201 // return true if the process is running
202 bool cmProcess::IsRunning()
204 int status
= this->GetProcessStatus();
205 if(status
== cmsysProcess_State_Executing
)
207 if(this->LastOutputPipe
!= 0)
212 // if the process is done, then wait for it to exit
213 cmsysProcess_WaitForExit(this->Process
, 0);
214 this->ExitValue
= cmsysProcess_GetExitValue(this->Process
);
215 this->TotalTime
= cmSystemTools::GetTime() - this->StartTime
;
216 // std::cerr << "Time to run: " << this->TotalTime << "\n";
221 int cmProcess::ReportStatus()
224 switch(cmsysProcess_GetState(this->Process
))
226 case cmsysProcess_State_Starting
:
228 std::cerr
<< "cmProcess: Never started "
229 << this->Command
<< " process.\n";
231 case cmsysProcess_State_Error
:
233 std::cerr
<< "cmProcess: Error executing " << this->Command
235 << cmsysProcess_GetErrorString(this->Process
)
238 case cmsysProcess_State_Exception
:
240 std::cerr
<< "cmProcess: " << this->Command
241 << " process exited with an exception: ";
242 switch(cmsysProcess_GetExitException(this->Process
))
244 case cmsysProcess_Exception_None
:
248 case cmsysProcess_Exception_Fault
:
250 std::cerr
<< "Segmentation fault";
252 case cmsysProcess_Exception_Illegal
:
254 std::cerr
<< "Illegal instruction";
256 case cmsysProcess_Exception_Interrupt
:
258 std::cerr
<< "Interrupted by user";
260 case cmsysProcess_Exception_Numerical
:
262 std::cerr
<< "Numerical exception";
264 case cmsysProcess_Exception_Other
:
266 std::cerr
<< "Unknown";
271 case cmsysProcess_State_Executing
:
273 std::cerr
<< "cmProcess: Never terminated " <<
274 this->Command
<< " process.\n";
276 case cmsysProcess_State_Exited
:
278 result
= cmsysProcess_GetExitValue(this->Process
);
279 std::cerr
<< "cmProcess: " << this->Command
280 << " process exited with code "
283 case cmsysProcess_State_Expired
:
285 std::cerr
<< "cmProcess: killed " << this->Command
286 << " process due to timeout.\n";
288 case cmsysProcess_State_Killed
:
290 std::cerr
<< "cmProcess: killed " << this->Command
<< " process.\n";