diff options
Diffstat (limited to 'Source/CTest/cmProcess.cxx')
-rw-r--r-- | Source/CTest/cmProcess.cxx | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx new file mode 100644 index 0000000..92fe642 --- /dev/null +++ b/Source/CTest/cmProcess.cxx @@ -0,0 +1,241 @@ +/*============================================================================ + 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 = CM_NULLPTR; + 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.empty()) { + 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(CM_NULLPTR); // null terminate the list + this->Process = cmsysProcess_New(); + cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin()); + if (!this->WorkingDirectory.empty()) { + cmsysProcess_SetWorkingDirectory(this->Process, + this->WorkingDirectory.c_str()); + } + cmsysProcess_SetTimeout(this->Process, this->Timeout); + cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1); + 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->Output.GetLine(line)) { + return cmsysProcess_Pipe_STDOUT; + } + + // 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->Output.insert(this->Output.end(), data, data + length); + } else // p == cmsysProcess_Pipe_None + { + // The process will provide no more data. + break; + } + } + + // Look for partial last lines. + if (this->Output.GetLast(line)) { + return cmsysProcess_Pipe_STDOUT; + } + + // 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; + // Because of a processor clock scew the runtime may become slightly + // negative. If someone changed the system clock while the process was + // running this may be even more. Make sure not to report a negative + // duration here. + if (this->TotalTime <= 0.0) { + this->TotalTime = 0.0; + } + // 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; +} + +void cmProcess::ChangeTimeout(double t) +{ + this->Timeout = t; + cmsysProcess_SetTimeout(this->Process, this->Timeout); +} + +void cmProcess::ResetStartTime() +{ + cmsysProcess_ResetStartTime(this->Process); +} + +int cmProcess::GetExitException() +{ + return cmsysProcess_GetExitException(this->Process); +} |