diff options
Diffstat (limited to 'Source/CTest/cmProcess.cxx')
-rw-r--r-- | Source/CTest/cmProcess.cxx | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx new file mode 100644 index 0000000..0ee631f --- /dev/null +++ b/Source/CTest/cmProcess.cxx @@ -0,0 +1,272 @@ +/*============================================================================ + 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. +============================================================================*/ + +#include <cmProcess.h> +#include <cmSystemTools.h> + +cmProcess::cmProcess() +{ + this->Process = 0; + this->Timeout = 0; + this->TotalTime = 0; + this->ExitValue = 0; + this->Id = 0; + this->StartTime = 0; +} + +cmProcess::~cmProcess() +{ + cmsysProcess_Delete(this->Process); +} +void cmProcess::SetCommand(const char* command) +{ + this->Command = command; +} + +void cmProcess::SetCommandArguments(std::vector<std::string> const& args) +{ + this->Arguments = args; +} + +bool cmProcess::StartProcess() +{ + if(this->Command.size() == 0) + { + return false; + } + this->StartTime = cmSystemTools::GetTime(); + this->ProcessArgs.clear(); + // put the command as arg0 + this->ProcessArgs.push_back(this->Command.c_str()); + // now put the command arguments in + for(std::vector<std::string>::iterator i = this->Arguments.begin(); + i != this->Arguments.end(); ++i) + { + this->ProcessArgs.push_back(i->c_str()); + } + this->ProcessArgs.push_back(0); // null terminate the list + this->Process = cmsysProcess_New(); + cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin()); + if(this->WorkingDirectory.size()) + { + cmsysProcess_SetWorkingDirectory(this->Process, + this->WorkingDirectory.c_str()); + } + cmsysProcess_SetTimeout(this->Process, this->Timeout); + cmsysProcess_Execute(this->Process); + return (cmsysProcess_GetState(this->Process) + == cmsysProcess_State_Executing); +} + +//---------------------------------------------------------------------------- +bool cmProcess::Buffer::GetLine(std::string& line) +{ + // Scan for the next newline. + for(size_type sz = this->size(); this->Last != sz; ++this->Last) + { + if((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') + { + // Extract the range first..last as a line. + const char* text = &*this->begin() + this->First; + size_type length = this->Last - this->First; + while(length && text[length-1] == '\r') + { + length --; + } + line.assign(text, length); + + // Start a new range for the next line. + ++this->Last; + this->First = Last; + + // Return the line extracted. + return true; + } + } + + // Available data have been exhausted without a newline. + if(this->First != 0) + { + // Move the partial line to the beginning of the buffer. + this->erase(this->begin(), this->begin() + this->First); + this->First = 0; + this->Last = this->size(); + } + return false; +} + +//---------------------------------------------------------------------------- +bool cmProcess::Buffer::GetLast(std::string& line) +{ + // Return the partial last line, if any. + if(!this->empty()) + { + line.assign(&*this->begin(), this->size()); + this->First = this->Last = 0; + this->clear(); + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +int cmProcess::GetNextOutputLine(std::string& line, double timeout) +{ + for(;;) + { + // Look for lines already buffered. + if(this->StdOut.GetLine(line)) + { + return cmsysProcess_Pipe_STDOUT; + } + else if(this->StdErr.GetLine(line)) + { + return cmsysProcess_Pipe_STDERR; + } + + // Check for more data from the process. + char* data; + int length; + int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout); + if(p == cmsysProcess_Pipe_Timeout) + { + return cmsysProcess_Pipe_Timeout; + } + else if(p == cmsysProcess_Pipe_STDOUT) + { + this->StdOut.insert(this->StdOut.end(), data, data+length); + } + else if(p == cmsysProcess_Pipe_STDERR) + { + this->StdErr.insert(this->StdErr.end(), data, data+length); + } + else // p == cmsysProcess_Pipe_None + { + // The process will provide no more data. + break; + } + } + + // Look for partial last lines. + if(this->StdOut.GetLast(line)) + { + return cmsysProcess_Pipe_STDOUT; + } + else if(this->StdErr.GetLast(line)) + { + return cmsysProcess_Pipe_STDERR; + } + + // No more data. Wait for process exit. + if(!cmsysProcess_WaitForExit(this->Process, &timeout)) + { + return cmsysProcess_Pipe_Timeout; + } + + // Record exit information. + this->ExitValue = cmsysProcess_GetExitValue(this->Process); + this->TotalTime = cmSystemTools::GetTime() - this->StartTime; + // std::cerr << "Time to run: " << this->TotalTime << "\n"; + return cmsysProcess_Pipe_None; +} + +// return the process status +int cmProcess::GetProcessStatus() +{ + if(!this->Process) + { + return cmsysProcess_State_Exited; + } + return cmsysProcess_GetState(this->Process); +} + +int cmProcess::ReportStatus() +{ + int result = 1; + switch(cmsysProcess_GetState(this->Process)) + { + case cmsysProcess_State_Starting: + { + std::cerr << "cmProcess: Never started " + << this->Command << " process.\n"; + } break; + case cmsysProcess_State_Error: + { + std::cerr << "cmProcess: Error executing " << this->Command + << " process: " + << cmsysProcess_GetErrorString(this->Process) + << "\n"; + } break; + case cmsysProcess_State_Exception: + { + std::cerr << "cmProcess: " << this->Command + << " process exited with an exception: "; + switch(cmsysProcess_GetExitException(this->Process)) + { + case cmsysProcess_Exception_None: + { + std::cerr << "None"; + } break; + case cmsysProcess_Exception_Fault: + { + std::cerr << "Segmentation fault"; + } break; + case cmsysProcess_Exception_Illegal: + { + std::cerr << "Illegal instruction"; + } break; + case cmsysProcess_Exception_Interrupt: + { + std::cerr << "Interrupted by user"; + } break; + case cmsysProcess_Exception_Numerical: + { + std::cerr << "Numerical exception"; + } break; + case cmsysProcess_Exception_Other: + { + std::cerr << "Unknown"; + } break; + } + std::cerr << "\n"; + } break; + case cmsysProcess_State_Executing: + { + std::cerr << "cmProcess: Never terminated " << + this->Command << " process.\n"; + } break; + case cmsysProcess_State_Exited: + { + result = cmsysProcess_GetExitValue(this->Process); + std::cerr << "cmProcess: " << this->Command + << " process exited with code " + << result << "\n"; + } break; + case cmsysProcess_State_Expired: + { + std::cerr << "cmProcess: killed " << this->Command + << " process due to timeout.\n"; + } break; + case cmsysProcess_State_Killed: + { + std::cerr << "cmProcess: killed " << this->Command << " process.\n"; + } break; + } + return result; + +} + + +int cmProcess::GetExitException() +{ + return cmsysProcess_GetExitException(this->Process); +} |