summaryrefslogtreecommitdiffstats
path: root/Source/CTest/cmProcess.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest/cmProcess.cxx')
-rw-r--r--Source/CTest/cmProcess.cxx241
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);
+}