summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CTest/cmProcess.cxx288
-rw-r--r--Source/CTest/cmProcess.h73
2 files changed, 361 insertions, 0 deletions
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
new file mode 100644
index 0000000..a109b3f
--- /dev/null
+++ b/Source/CTest/cmProcess.cxx
@@ -0,0 +1,288 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+
+#include <cmProcess.h>
+#include <iostream>
+
+cmProcess::cmProcess()
+{
+ this->Process = 0;
+ this->Timeout = 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->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_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(this->Process, this->Timeout);
+ cmsysProcess_Execute(this->Process);
+ return (cmsysProcess_GetState(this->Process)
+ == cmsysProcess_State_Executing);
+}
+
+// return true if there is a new line of data
+// return false if there is no new data
+int cmProcess::CheckOutput(double timeout,
+ std::string& stdOutLine,
+ std::string& stdErrLine)
+{
+ stdOutLine = "";
+ stdErrLine = "";
+ std::vector<char>::iterator outiter =
+ this->StdOutBuffer.begin();
+ std::vector<char>::iterator erriter =
+ this->StdErrorBuffer.begin();
+ while(1)
+ {
+ // Check for a newline in stdout.
+ for(;outiter != this->StdOutBuffer.end(); ++outiter)
+ {
+ if((*outiter == '\r') && ((outiter+1) == this->StdOutBuffer.end()))
+ {
+ break;
+ }
+ else if(*outiter == '\n' || *outiter == '\0')
+ {
+ int length = outiter-this->StdOutBuffer.begin();
+ if(length > 1 && *(outiter-1) == '\r')
+ {
+ --length;
+ }
+ if(length > 0)
+ {
+ stdOutLine.append(&this->StdOutBuffer[0], length);
+ }
+ this->StdOutBuffer.erase(this->StdOutBuffer.begin(), outiter+1);
+ this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
+ return this->LastOutputPipe;;
+ }
+ }
+
+ // Check for a newline in stderr.
+ for(;erriter != this->StdErrorBuffer.end(); ++erriter)
+ {
+ if((*erriter == '\r') && ((erriter+1) == this->StdErrorBuffer.end()))
+ {
+ break;
+ }
+ else if(*erriter == '\n' || *erriter == '\0')
+ {
+ int length = erriter-this->StdErrorBuffer.begin();
+ if(length > 1 && *(erriter-1) == '\r')
+ {
+ --length;
+ }
+ if(length > 0)
+ {
+ stdErrLine.append(&this->StdErrorBuffer[0], length);
+ }
+ this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(), erriter+1);
+ this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
+ return this->LastOutputPipe;
+ }
+ }
+
+ // No newlines found. Wait for more data from the process.
+ int length;
+ char* data;
+ int pipe = cmsysProcess_WaitForData(this->Process, &data,
+ &length, &timeout);
+ if(pipe == cmsysProcess_Pipe_Timeout)
+ {
+ // Timeout has been exceeded.
+ this->LastOutputPipe = pipe;
+ return pipe;
+ }
+ else if(pipe == cmsysProcess_Pipe_STDOUT)
+ {
+ // Append to the stdout buffer.
+ std::vector<char>::size_type size = this->StdOutBuffer.size();
+ this->StdOutBuffer.insert(this->StdOutBuffer.end(), data, data+length);
+ outiter = this->StdOutBuffer.begin()+size;
+ }
+ else if(pipe == cmsysProcess_Pipe_STDERR)
+ {
+ // Append to the stderr buffer.
+ std::vector<char>::size_type size = this->StdErrorBuffer.size();
+ this->StdErrorBuffer.insert(this->StdErrorBuffer.end(),
+ data, data+length);
+ erriter = this->StdErrorBuffer.begin()+size;
+ }
+ else if(pipe == cmsysProcess_Pipe_None)
+ {
+ // Both stdout and stderr pipes have broken. Return leftover data.
+ if(!this->StdOutBuffer.empty())
+ {
+ stdOutLine.append(&this->StdOutBuffer[0],
+ outiter-this->StdOutBuffer.begin());
+ this->StdOutBuffer.erase(this->StdOutBuffer.begin(),
+ this->StdOutBuffer.end());
+ this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
+ return this->LastOutputPipe;
+ }
+ else if(!this->StdErrorBuffer.empty())
+ {
+ stdErrLine.append(&this->StdErrorBuffer[0],
+ erriter-this->StdErrorBuffer.begin());
+ this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(),
+ this->StdErrorBuffer.end());
+ this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
+ return this->LastOutputPipe;
+ }
+ else
+ {
+ this->LastOutputPipe = cmsysProcess_Pipe_None;
+ return this->LastOutputPipe;
+ }
+ }
+ }
+}
+
+
+// return the process status
+int cmProcess::GetProcessStatus()
+{
+ if(!this->Process)
+ {
+ return cmsysProcess_State_Exited;
+ }
+ return cmsysProcess_GetState(this->Process);
+}
+
+// return true if the process is running
+bool cmProcess::IsRunning()
+{
+ int status = this->GetProcessStatus();
+ if(status == cmsysProcess_State_Executing )
+ {
+ if(this->LastOutputPipe != 0)
+ {
+ return true;
+ }
+ }
+ // if the process is done, then wait for it to exit
+ cmsysProcess_WaitForExit(this->Process, 0);
+ this->ExitValue = cmsysProcess_GetExitValue(this->Process);
+ return false;
+}
+
+
+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;
+
+}
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
new file mode 100644
index 0000000..7898f2d
--- /dev/null
+++ b/Source/CTest/cmProcess.h
@@ -0,0 +1,73 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmProcess_h
+#define cmProcess_h
+
+#include <set>
+#include <map>
+#include <string>
+#include <vector>
+#include <cmsys/Process.h>
+
+
+/** \class cmProcess
+ * \brief run a process with c++
+ *
+ * cmProcess wraps the kwsys process stuff in a c++ class.
+ */
+class cmProcess
+{
+public:
+ cmProcess();
+ ~cmProcess();
+ const char* GetCommand() { return this->Command.c_str();}
+ void SetCommand(const char* command);
+ void SetCommandArguments(std::vector<std::string> const& arg);
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir;}
+ void SetTimeout(double t) { this->Timeout = t;}
+ // Return true if the process starts
+ bool StartProcess();
+
+ // return process state
+ int CheckOutput(double timeout,
+ std::string& stdOutLine,
+ std::string& stdErrLine);
+ // return the process status
+ int GetProcessStatus();
+ // return true if the process is running
+ bool IsRunning();
+ // Report the status of the program
+ int ReportStatus();
+ int GetId() { return this->Id; }
+ void SetId(int id) { this->Id = id;}
+ int GetExitValue() { return this->ExitValue;}
+private:
+ int LastOutputPipe;
+ double Timeout;
+ cmsysProcess* Process;
+ std::vector<char> StdErrorBuffer;
+ std::vector<char> StdOutBuffer;
+ std::string Command;
+ std::string WorkingDirectory;
+ std::vector<std::string> Arguments;
+ std::vector<const char*> ProcessArgs;
+ std::string Output;
+ int Id;
+ int ExitValue;
+};
+
+#endif