1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
13 #include <cmProcess.h>
14 #include <cmSystemTools.h>
16 cmProcess::cmProcess()
26 cmProcess::~cmProcess()
28 cmsysProcess_Delete(this->Process);
30 void cmProcess::SetCommand(const char* command)
32 this->Command = command;
35 void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
37 this->Arguments = args;
40 bool cmProcess::StartProcess()
42 if(this->Command.size() == 0)
46 this->StartTime = cmSystemTools::GetTime();
47 this->ProcessArgs.clear();
48 // put the command as arg0
49 this->ProcessArgs.push_back(this->Command.c_str());
50 // now put the command arguments in
51 for(std::vector<std::string>::iterator i = this->Arguments.begin();
52 i != this->Arguments.end(); ++i)
54 this->ProcessArgs.push_back(i->c_str());
56 this->ProcessArgs.push_back(0); // null terminate the list
57 this->Process = cmsysProcess_New();
58 cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
59 if(this->WorkingDirectory.size())
61 cmsysProcess_SetWorkingDirectory(this->Process,
62 this->WorkingDirectory.c_str());
64 cmsysProcess_SetTimeout(this->Process, this->Timeout);
65 cmsysProcess_Execute(this->Process);
66 return (cmsysProcess_GetState(this->Process)
67 == cmsysProcess_State_Executing);
70 //----------------------------------------------------------------------------
71 bool cmProcess::Buffer::GetLine(std::string& line)
73 // Scan for the next newline.
74 for(size_type sz = this->size(); this->Last != sz; ++this->Last)
76 if((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0')
78 // Extract the range first..last as a line.
79 const char* text = &*this->begin() + this->First;
80 size_type length = this->Last - this->First;
81 while(length && text[length-1] == '\r')
85 line.assign(text, length);
87 // Start a new range for the next line.
91 // Return the line extracted.
96 // Available data have been exhausted without a newline.
99 // Move the partial line to the beginning of the buffer.
100 this->erase(this->begin(), this->begin() + this->First);
102 this->Last = this->size();
107 //----------------------------------------------------------------------------
108 bool cmProcess::Buffer::GetLast(std::string& line)
110 // Return the partial last line, if any.
113 line.assign(&*this->begin(), this->size());
114 this->First = this->Last = 0;
121 //----------------------------------------------------------------------------
122 int cmProcess::GetNextOutputLine(std::string& line, double timeout)
126 // Look for lines already buffered.
127 if(this->StdOut.GetLine(line))
129 return cmsysProcess_Pipe_STDOUT;
131 else if(this->StdErr.GetLine(line))
133 return cmsysProcess_Pipe_STDERR;
136 // Check for more data from the process.
139 int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
140 if(p == cmsysProcess_Pipe_Timeout)
142 return cmsysProcess_Pipe_Timeout;
144 else if(p == cmsysProcess_Pipe_STDOUT)
146 this->StdOut.insert(this->StdOut.end(), data, data+length);
148 else if(p == cmsysProcess_Pipe_STDERR)
150 this->StdErr.insert(this->StdErr.end(), data, data+length);
152 else // p == cmsysProcess_Pipe_None
154 // The process will provide no more data.
159 // Look for partial last lines.
160 if(this->StdOut.GetLast(line))
162 return cmsysProcess_Pipe_STDOUT;
164 else if(this->StdErr.GetLast(line))
166 return cmsysProcess_Pipe_STDERR;
169 // No more data. Wait for process exit.
170 if(!cmsysProcess_WaitForExit(this->Process, &timeout))
172 return cmsysProcess_Pipe_Timeout;
175 // Record exit information.
176 this->ExitValue = cmsysProcess_GetExitValue(this->Process);
177 this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
178 // Because of a processor clock scew the runtime may become slightly
179 // negative. If someone changed the system clock while the process was
180 // running this may be even more. Make sure not to report a negative
182 if (this->TotalTime <= 0.0)
184 this->TotalTime = 0.0;
186 // std::cerr << "Time to run: " << this->TotalTime << "\n";
187 return cmsysProcess_Pipe_None;
190 // return the process status
191 int cmProcess::GetProcessStatus()
195 return cmsysProcess_State_Exited;
197 return cmsysProcess_GetState(this->Process);
200 int cmProcess::ReportStatus()
203 switch(cmsysProcess_GetState(this->Process))
205 case cmsysProcess_State_Starting:
207 std::cerr << "cmProcess: Never started "
208 << this->Command << " process.\n";
210 case cmsysProcess_State_Error:
212 std::cerr << "cmProcess: Error executing " << this->Command
214 << cmsysProcess_GetErrorString(this->Process)
217 case cmsysProcess_State_Exception:
219 std::cerr << "cmProcess: " << this->Command
220 << " process exited with an exception: ";
221 switch(cmsysProcess_GetExitException(this->Process))
223 case cmsysProcess_Exception_None:
227 case cmsysProcess_Exception_Fault:
229 std::cerr << "Segmentation fault";
231 case cmsysProcess_Exception_Illegal:
233 std::cerr << "Illegal instruction";
235 case cmsysProcess_Exception_Interrupt:
237 std::cerr << "Interrupted by user";
239 case cmsysProcess_Exception_Numerical:
241 std::cerr << "Numerical exception";
243 case cmsysProcess_Exception_Other:
245 std::cerr << "Unknown";
250 case cmsysProcess_State_Executing:
252 std::cerr << "cmProcess: Never terminated " <<
253 this->Command << " process.\n";
255 case cmsysProcess_State_Exited:
257 result = cmsysProcess_GetExitValue(this->Process);
258 std::cerr << "cmProcess: " << this->Command
259 << " process exited with code "
262 case cmsysProcess_State_Expired:
264 std::cerr << "cmProcess: killed " << this->Command
265 << " process due to timeout.\n";
267 case cmsysProcess_State_Killed:
269 std::cerr << "cmProcess: killed " << this->Command << " process.\n";
277 int cmProcess::GetExitException()
279 return cmsysProcess_GetExitException(this->Process);