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