000bc8503d46d40828173be506185a432553dc95
[platform/upstream/cmake.git] / Source / CTest / cmProcess.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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 ============================================================================*/
12
13 #include <cmProcess.h>
14 #include <cmSystemTools.h>
15
16 cmProcess::cmProcess()
17 {
18   this->Process = 0;
19   this->Timeout = 0;
20   this->TotalTime = 0;
21   this->ExitValue = 0;
22   this->Id = 0;
23   this->StartTime = 0;
24 }
25
26 cmProcess::~cmProcess()
27 {
28   cmsysProcess_Delete(this->Process);
29 }
30 void cmProcess::SetCommand(const char* command)
31 {
32   this->Command = command;
33 }
34
35 void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
36 {
37   this->Arguments = args;
38 }
39
40 bool cmProcess::StartProcess()
41 {
42   if(this->Command.size() == 0)
43     {
44     return false;
45     }
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)
53     {
54     this->ProcessArgs.push_back(i->c_str());
55     }
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())
60     {
61     cmsysProcess_SetWorkingDirectory(this->Process,
62                                      this->WorkingDirectory.c_str());
63     }
64   cmsysProcess_SetTimeout(this->Process, this->Timeout);
65   cmsysProcess_Execute(this->Process);
66   return (cmsysProcess_GetState(this->Process)
67           == cmsysProcess_State_Executing);
68 }
69
70 //----------------------------------------------------------------------------
71 bool cmProcess::Buffer::GetLine(std::string& line)
72 {
73   // Scan for the next newline.
74   for(size_type sz = this->size(); this->Last != sz; ++this->Last)
75     {
76     if((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0')
77       {
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')
82         {
83         length --;
84         }
85       line.assign(text, length);
86
87       // Start a new range for the next line.
88       ++this->Last;
89       this->First = Last;
90
91       // Return the line extracted.
92       return true;
93       }
94     }
95
96   // Available data have been exhausted without a newline.
97   if(this->First != 0)
98     {
99     // Move the partial line to the beginning of the buffer.
100     this->erase(this->begin(), this->begin() + this->First);
101     this->First = 0;
102     this->Last = this->size();
103     }
104   return false;
105 }
106
107 //----------------------------------------------------------------------------
108 bool cmProcess::Buffer::GetLast(std::string& line)
109 {
110   // Return the partial last line, if any.
111   if(!this->empty())
112     {
113     line.assign(&*this->begin(), this->size());
114     this->First = this->Last = 0;
115     this->clear();
116     return true;
117     }
118   return false;
119 }
120
121 //----------------------------------------------------------------------------
122 int cmProcess::GetNextOutputLine(std::string& line, double timeout)
123 {
124   for(;;)
125     {
126     // Look for lines already buffered.
127     if(this->StdOut.GetLine(line))
128       {
129       return cmsysProcess_Pipe_STDOUT;
130       }
131     else if(this->StdErr.GetLine(line))
132       {
133       return cmsysProcess_Pipe_STDERR;
134       }
135
136     // Check for more data from the process.
137     char* data;
138     int length;
139     int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
140     if(p == cmsysProcess_Pipe_Timeout)
141       {
142       return cmsysProcess_Pipe_Timeout;
143       }
144     else if(p == cmsysProcess_Pipe_STDOUT)
145       {
146       this->StdOut.insert(this->StdOut.end(), data, data+length);
147       }
148     else if(p == cmsysProcess_Pipe_STDERR)
149       {
150       this->StdErr.insert(this->StdErr.end(), data, data+length);
151       }
152     else // p == cmsysProcess_Pipe_None
153       {
154       // The process will provide no more data.
155       break;
156       }
157     }
158
159   // Look for partial last lines.
160   if(this->StdOut.GetLast(line))
161     {
162     return cmsysProcess_Pipe_STDOUT;
163     }
164   else if(this->StdErr.GetLast(line))
165     {
166     return cmsysProcess_Pipe_STDERR;
167     }
168
169   // No more data.  Wait for process exit.
170   if(!cmsysProcess_WaitForExit(this->Process, &timeout))
171     {
172     return cmsysProcess_Pipe_Timeout;
173     }
174
175   // Record exit information.
176   this->ExitValue = cmsysProcess_GetExitValue(this->Process);
177   this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
178   //  std::cerr << "Time to run: " << this->TotalTime << "\n";
179   return cmsysProcess_Pipe_None;
180 }
181
182 // return the process status
183 int cmProcess::GetProcessStatus()
184 {
185   if(!this->Process)
186     {
187     return cmsysProcess_State_Exited;
188     }
189   return cmsysProcess_GetState(this->Process);
190 }
191
192 int cmProcess::ReportStatus()
193 {
194   int result = 1;
195   switch(cmsysProcess_GetState(this->Process))
196     {
197     case cmsysProcess_State_Starting:
198       {
199       std::cerr << "cmProcess: Never started "
200            << this->Command << " process.\n";
201       } break;
202     case cmsysProcess_State_Error:
203       {
204       std::cerr << "cmProcess: Error executing " << this->Command
205                 << " process: "
206                 << cmsysProcess_GetErrorString(this->Process)
207                 << "\n";
208       } break;
209     case cmsysProcess_State_Exception:
210       {
211       std::cerr << "cmProcess: " << this->Command
212                       << " process exited with an exception: ";
213       switch(cmsysProcess_GetExitException(this->Process))
214         {
215         case cmsysProcess_Exception_None:
216           {
217           std::cerr << "None";
218           } break;
219         case cmsysProcess_Exception_Fault:
220           {
221           std::cerr << "Segmentation fault";
222           } break;
223         case cmsysProcess_Exception_Illegal:
224           {
225           std::cerr << "Illegal instruction";
226           } break;
227         case cmsysProcess_Exception_Interrupt:
228           {
229           std::cerr << "Interrupted by user";
230           } break;
231         case cmsysProcess_Exception_Numerical:
232           {
233           std::cerr << "Numerical exception";
234           } break;
235         case cmsysProcess_Exception_Other:
236           {
237           std::cerr << "Unknown";
238           } break;
239         }
240       std::cerr << "\n";
241       } break;
242     case cmsysProcess_State_Executing:
243       {
244       std::cerr << "cmProcess: Never terminated " <<
245         this->Command << " process.\n";
246       } break;
247     case cmsysProcess_State_Exited:
248       {
249       result = cmsysProcess_GetExitValue(this->Process);
250       std::cerr << "cmProcess: " << this->Command
251                 << " process exited with code "
252                 << result << "\n";
253       } break;
254     case cmsysProcess_State_Expired:
255       {
256       std::cerr << "cmProcess: killed " << this->Command
257                 << " process due to timeout.\n";
258       } break;
259     case cmsysProcess_State_Killed:
260       {
261       std::cerr << "cmProcess: killed " << this->Command << " process.\n";
262       } break;
263     }
264   return result;
265
266 }
267
268
269 int cmProcess::GetExitException()
270 {
271   return cmsysProcess_GetExitException(this->Process);
272 }