/*============================================================================ 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); }