cmProcess.cxx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include <cmProcess.h>
  14. #include <cmSystemTools.h>
  15. cmProcess::cmProcess()
  16. {
  17. this->Process = 0;
  18. this->Timeout = 0;
  19. this->TotalTime = 0;
  20. this->ExitValue = 0;
  21. this->Id = 0;
  22. this->StartTime = 0;
  23. }
  24. cmProcess::~cmProcess()
  25. {
  26. cmsysProcess_Delete(this->Process);
  27. }
  28. void cmProcess::SetCommand(const char* command)
  29. {
  30. this->Command = command;
  31. }
  32. void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
  33. {
  34. this->Arguments = args;
  35. }
  36. bool cmProcess::StartProcess()
  37. {
  38. if(this->Command.size() == 0)
  39. {
  40. return false;
  41. }
  42. this->StartTime = cmSystemTools::GetTime();
  43. this->ProcessArgs.clear();
  44. // put the command as arg0
  45. this->ProcessArgs.push_back(this->Command.c_str());
  46. // now put the command arguments in
  47. for(std::vector<std::string>::iterator i = this->Arguments.begin();
  48. i != this->Arguments.end(); ++i)
  49. {
  50. this->ProcessArgs.push_back(i->c_str());
  51. }
  52. this->ProcessArgs.push_back(0); // null terminate the list
  53. this->Process = cmsysProcess_New();
  54. cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
  55. if(this->WorkingDirectory.size())
  56. {
  57. cmsysProcess_SetWorkingDirectory(this->Process,
  58. this->WorkingDirectory.c_str());
  59. }
  60. cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
  61. cmsysProcess_SetTimeout(this->Process, this->Timeout);
  62. cmsysProcess_Execute(this->Process);
  63. return (cmsysProcess_GetState(this->Process)
  64. == cmsysProcess_State_Executing);
  65. }
  66. //----------------------------------------------------------------------------
  67. bool cmProcess::Buffer::GetLine(std::string& line)
  68. {
  69. // Scan for the next newline.
  70. for(size_type sz = this->size(); this->Last != sz; ++this->Last)
  71. {
  72. if((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0')
  73. {
  74. // Extract the range first..last as a line.
  75. const char* data = &*this->begin() + this->First;
  76. size_type length = this->Last - this->First;
  77. length -= (length && data[length-1] == '\r')? 1:0;
  78. line.assign(data, length);
  79. // Start a new range for the next line.
  80. ++this->Last;
  81. this->First = Last;
  82. // Return the line extracted.
  83. return true;
  84. }
  85. }
  86. // Available data have been exhausted without a newline.
  87. if(this->First != 0)
  88. {
  89. // Move the partial line to the beginning of the buffer.
  90. this->erase(this->begin(), this->begin() + this->First);
  91. this->First = 0;
  92. this->Last = this->size();
  93. }
  94. return false;
  95. }
  96. //----------------------------------------------------------------------------
  97. bool cmProcess::Buffer::GetLast(std::string& line)
  98. {
  99. // Return the partial last line, if any.
  100. if(!this->empty())
  101. {
  102. line.assign(&*this->begin(), this->size());
  103. this->clear();
  104. return true;
  105. }
  106. return false;
  107. }
  108. //----------------------------------------------------------------------------
  109. int cmProcess::GetNextOutputLine(std::string& line, double timeout)
  110. {
  111. for(;;)
  112. {
  113. // Look for lines already buffered.
  114. if(this->StdOut.GetLine(line))
  115. {
  116. return cmsysProcess_Pipe_STDOUT;
  117. }
  118. else if(this->StdErr.GetLine(line))
  119. {
  120. return cmsysProcess_Pipe_STDERR;
  121. }
  122. // Check for more data from the process.
  123. char* data;
  124. int length;
  125. int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
  126. if(p == cmsysProcess_Pipe_Timeout)
  127. {
  128. return cmsysProcess_Pipe_Timeout;
  129. }
  130. else if(p == cmsysProcess_Pipe_STDOUT)
  131. {
  132. this->StdOut.insert(this->StdOut.end(), data, data+length);
  133. }
  134. else if(p == cmsysProcess_Pipe_STDERR)
  135. {
  136. this->StdErr.insert(this->StdErr.end(), data, data+length);
  137. }
  138. else // p == cmsysProcess_Pipe_None
  139. {
  140. // The process will provide no more data.
  141. break;
  142. }
  143. }
  144. // Look for partial last lines.
  145. if(this->StdOut.GetLast(line))
  146. {
  147. return cmsysProcess_Pipe_STDOUT;
  148. }
  149. else if(this->StdErr.GetLast(line))
  150. {
  151. return cmsysProcess_Pipe_STDERR;
  152. }
  153. // No more data. Wait for process exit.
  154. if(!cmsysProcess_WaitForExit(this->Process, &timeout))
  155. {
  156. return cmsysProcess_Pipe_Timeout;
  157. }
  158. // Record exit information.
  159. this->ExitValue = cmsysProcess_GetExitValue(this->Process);
  160. this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
  161. // std::cerr << "Time to run: " << this->TotalTime << "\n";
  162. return cmsysProcess_Pipe_None;
  163. }
  164. // return the process status
  165. int cmProcess::GetProcessStatus()
  166. {
  167. if(!this->Process)
  168. {
  169. return cmsysProcess_State_Exited;
  170. }
  171. return cmsysProcess_GetState(this->Process);
  172. }
  173. int cmProcess::ReportStatus()
  174. {
  175. int result = 1;
  176. switch(cmsysProcess_GetState(this->Process))
  177. {
  178. case cmsysProcess_State_Starting:
  179. {
  180. std::cerr << "cmProcess: Never started "
  181. << this->Command << " process.\n";
  182. } break;
  183. case cmsysProcess_State_Error:
  184. {
  185. std::cerr << "cmProcess: Error executing " << this->Command
  186. << " process: "
  187. << cmsysProcess_GetErrorString(this->Process)
  188. << "\n";
  189. } break;
  190. case cmsysProcess_State_Exception:
  191. {
  192. std::cerr << "cmProcess: " << this->Command
  193. << " process exited with an exception: ";
  194. switch(cmsysProcess_GetExitException(this->Process))
  195. {
  196. case cmsysProcess_Exception_None:
  197. {
  198. std::cerr << "None";
  199. } break;
  200. case cmsysProcess_Exception_Fault:
  201. {
  202. std::cerr << "Segmentation fault";
  203. } break;
  204. case cmsysProcess_Exception_Illegal:
  205. {
  206. std::cerr << "Illegal instruction";
  207. } break;
  208. case cmsysProcess_Exception_Interrupt:
  209. {
  210. std::cerr << "Interrupted by user";
  211. } break;
  212. case cmsysProcess_Exception_Numerical:
  213. {
  214. std::cerr << "Numerical exception";
  215. } break;
  216. case cmsysProcess_Exception_Other:
  217. {
  218. std::cerr << "Unknown";
  219. } break;
  220. }
  221. std::cerr << "\n";
  222. } break;
  223. case cmsysProcess_State_Executing:
  224. {
  225. std::cerr << "cmProcess: Never terminated " <<
  226. this->Command << " process.\n";
  227. } break;
  228. case cmsysProcess_State_Exited:
  229. {
  230. result = cmsysProcess_GetExitValue(this->Process);
  231. std::cerr << "cmProcess: " << this->Command
  232. << " process exited with code "
  233. << result << "\n";
  234. } break;
  235. case cmsysProcess_State_Expired:
  236. {
  237. std::cerr << "cmProcess: killed " << this->Command
  238. << " process due to timeout.\n";
  239. } break;
  240. case cmsysProcess_State_Killed:
  241. {
  242. std::cerr << "cmProcess: killed " << this->Command << " process.\n";
  243. } break;
  244. }
  245. return result;
  246. }