/*========================================================================= 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 #include 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 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::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::iterator outiter = this->StdOutBuffer.begin(); std::vector::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::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::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); this->TotalTime = cmSystemTools::GetTime() - this->StartTime; // std::cerr << "Time to run: " << this->TotalTime << "\n"; 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; }