cmProcess.cxx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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->LastOutputPipe = cmsysProcess_Pipe_None;
  21. this->ExitValue = 0;
  22. this->Id = 0;
  23. this->StartTime = 0;
  24. }
  25. cmProcess::~cmProcess()
  26. {
  27. cmsysProcess_Delete(this->Process);
  28. }
  29. void cmProcess::SetCommand(const char* command)
  30. {
  31. this->Command = command;
  32. }
  33. void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
  34. {
  35. this->Arguments = args;
  36. }
  37. bool cmProcess::StartProcess()
  38. {
  39. if(this->Command.size() == 0)
  40. {
  41. return false;
  42. }
  43. this->StartTime = cmSystemTools::GetTime();
  44. this->ProcessArgs.clear();
  45. // put the command as arg0
  46. this->ProcessArgs.push_back(this->Command.c_str());
  47. // now put the command arguments in
  48. for(std::vector<std::string>::iterator i = this->Arguments.begin();
  49. i != this->Arguments.end(); ++i)
  50. {
  51. this->ProcessArgs.push_back(i->c_str());
  52. }
  53. this->ProcessArgs.push_back(0); // null terminate the list
  54. this->Process = cmsysProcess_New();
  55. cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
  56. if(this->WorkingDirectory.size())
  57. {
  58. cmsysProcess_SetWorkingDirectory(this->Process,
  59. this->WorkingDirectory.c_str());
  60. }
  61. cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
  62. cmsysProcess_SetTimeout(this->Process, this->Timeout);
  63. cmsysProcess_Execute(this->Process);
  64. return (cmsysProcess_GetState(this->Process)
  65. == cmsysProcess_State_Executing);
  66. }
  67. int cmProcess::GetNextOutputLine(std::string& stdOutLine,
  68. std::string& stdErrLine,
  69. bool& gotStdOut,
  70. bool& gotStdErr,
  71. bool running)
  72. {
  73. if(this->StdErrorBuffer.empty() && this->StdOutBuffer.empty())
  74. {
  75. return cmsysProcess_Pipe_Timeout;
  76. }
  77. stdOutLine = "";
  78. stdErrLine = "";
  79. this->LastOutputPipe = cmsysProcess_Pipe_Timeout;
  80. std::vector<char>::iterator outiter =
  81. this->StdOutBuffer.begin();
  82. std::vector<char>::iterator erriter =
  83. this->StdErrorBuffer.begin();
  84. // Check for a newline in stdout.
  85. for(;outiter != this->StdOutBuffer.end(); ++outiter)
  86. {
  87. if((*outiter == '\r') && ((outiter+1) == this->StdOutBuffer.end()))
  88. {
  89. break;
  90. }
  91. else if(*outiter == '\n' || *outiter == '\0')
  92. {
  93. int length = outiter-this->StdOutBuffer.begin();
  94. if(length > 1 && *(outiter-1) == '\r')
  95. {
  96. --length;
  97. }
  98. if(length > 0)
  99. {
  100. stdOutLine.append(&this->StdOutBuffer[0], length);
  101. }
  102. this->StdOutBuffer.erase(this->StdOutBuffer.begin(), outiter+1);
  103. this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
  104. gotStdOut = true;
  105. break;
  106. }
  107. }
  108. // Check for a newline in stderr.
  109. for(;erriter != this->StdErrorBuffer.end(); ++erriter)
  110. {
  111. if((*erriter == '\r') && ((erriter+1) == this->StdErrorBuffer.end()))
  112. {
  113. break;
  114. }
  115. else if(*erriter == '\n' || *erriter == '\0')
  116. {
  117. int length = erriter-this->StdErrorBuffer.begin();
  118. if(length > 1 && *(erriter-1) == '\r')
  119. {
  120. --length;
  121. }
  122. if(length > 0)
  123. {
  124. stdErrLine.append(&this->StdErrorBuffer[0], length);
  125. }
  126. this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(), erriter+1);
  127. this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
  128. gotStdErr = true;
  129. break;
  130. }
  131. }
  132. if(!running && !gotStdErr && !gotStdOut)
  133. {
  134. //If process terminated with no newline, flush the buffer
  135. if(!running)
  136. {
  137. if(!this->StdErrorBuffer.empty())
  138. {
  139. gotStdErr = true;
  140. stdErrLine.append(&this->StdErrorBuffer[0],
  141. this->StdErrorBuffer.size());
  142. this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(),
  143. this->StdErrorBuffer.end());
  144. }
  145. if(!this->StdOutBuffer.empty())
  146. {
  147. gotStdOut = true;
  148. stdOutLine.append(&this->StdOutBuffer[0],
  149. this->StdOutBuffer.size());
  150. this->StdOutBuffer.erase(this->StdOutBuffer.begin(),
  151. this->StdOutBuffer.end());
  152. }
  153. return cmsysProcess_Pipe_None;
  154. }
  155. }
  156. //If we get here, we have stuff waiting in the buffers, but no newline
  157. return this->LastOutputPipe;
  158. }
  159. // return true if there is a new line of data
  160. // return false if there is no new data
  161. bool cmProcess::CheckOutput(double timeout)
  162. {
  163. // Wait for data from the process.
  164. int length;
  165. char* data;
  166. while(1)
  167. {
  168. int pipe = cmsysProcess_WaitForData(this->Process, &data,
  169. &length, &timeout);
  170. if(pipe == cmsysProcess_Pipe_Timeout)
  171. {
  172. // Timeout has been exceeded.
  173. this->LastOutputPipe = pipe;
  174. return true;
  175. }
  176. else if(pipe == cmsysProcess_Pipe_STDOUT)
  177. {
  178. // Append to the stdout buffer.
  179. this->StdOutBuffer.insert(this->StdOutBuffer.end(), data, data+length);
  180. this->LastOutputPipe = pipe;
  181. }
  182. else if(pipe == cmsysProcess_Pipe_STDERR)
  183. {
  184. // Append to the stderr buffer.
  185. this->StdErrorBuffer.insert(this->StdErrorBuffer.end(),
  186. data, data+length);
  187. this->LastOutputPipe = pipe;
  188. }
  189. else if(pipe == cmsysProcess_Pipe_None)
  190. {
  191. // Both stdout and stderr pipes have broken. Return leftover data.
  192. if(!this->StdOutBuffer.empty())
  193. {
  194. this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
  195. return false;
  196. }
  197. else if(!this->StdErrorBuffer.empty())
  198. {
  199. this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
  200. return false;
  201. }
  202. else
  203. {
  204. this->LastOutputPipe = cmsysProcess_Pipe_None;
  205. return false;
  206. }
  207. }
  208. }
  209. }
  210. // return the process status
  211. int cmProcess::GetProcessStatus()
  212. {
  213. if(!this->Process)
  214. {
  215. return cmsysProcess_State_Exited;
  216. }
  217. return cmsysProcess_GetState(this->Process);
  218. }
  219. // return true if the process is running
  220. bool cmProcess::IsRunning()
  221. {
  222. int status = this->GetProcessStatus();
  223. if(status == cmsysProcess_State_Executing )
  224. {
  225. if(this->LastOutputPipe != 0)
  226. {
  227. return true;
  228. }
  229. }
  230. // if the process is done, then wait for it to exit
  231. cmsysProcess_WaitForExit(this->Process, 0);
  232. this->ExitValue = cmsysProcess_GetExitValue(this->Process);
  233. this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
  234. // std::cerr << "Time to run: " << this->TotalTime << "\n";
  235. return false;
  236. }
  237. int cmProcess::ReportStatus()
  238. {
  239. int result = 1;
  240. switch(cmsysProcess_GetState(this->Process))
  241. {
  242. case cmsysProcess_State_Starting:
  243. {
  244. std::cerr << "cmProcess: Never started "
  245. << this->Command << " process.\n";
  246. } break;
  247. case cmsysProcess_State_Error:
  248. {
  249. std::cerr << "cmProcess: Error executing " << this->Command
  250. << " process: "
  251. << cmsysProcess_GetErrorString(this->Process)
  252. << "\n";
  253. } break;
  254. case cmsysProcess_State_Exception:
  255. {
  256. std::cerr << "cmProcess: " << this->Command
  257. << " process exited with an exception: ";
  258. switch(cmsysProcess_GetExitException(this->Process))
  259. {
  260. case cmsysProcess_Exception_None:
  261. {
  262. std::cerr << "None";
  263. } break;
  264. case cmsysProcess_Exception_Fault:
  265. {
  266. std::cerr << "Segmentation fault";
  267. } break;
  268. case cmsysProcess_Exception_Illegal:
  269. {
  270. std::cerr << "Illegal instruction";
  271. } break;
  272. case cmsysProcess_Exception_Interrupt:
  273. {
  274. std::cerr << "Interrupted by user";
  275. } break;
  276. case cmsysProcess_Exception_Numerical:
  277. {
  278. std::cerr << "Numerical exception";
  279. } break;
  280. case cmsysProcess_Exception_Other:
  281. {
  282. std::cerr << "Unknown";
  283. } break;
  284. }
  285. std::cerr << "\n";
  286. } break;
  287. case cmsysProcess_State_Executing:
  288. {
  289. std::cerr << "cmProcess: Never terminated " <<
  290. this->Command << " process.\n";
  291. } break;
  292. case cmsysProcess_State_Exited:
  293. {
  294. result = cmsysProcess_GetExitValue(this->Process);
  295. std::cerr << "cmProcess: " << this->Command
  296. << " process exited with code "
  297. << result << "\n";
  298. } break;
  299. case cmsysProcess_State_Expired:
  300. {
  301. std::cerr << "cmProcess: killed " << this->Command
  302. << " process due to timeout.\n";
  303. } break;
  304. case cmsysProcess_State_Killed:
  305. {
  306. std::cerr << "cmProcess: killed " << this->Command << " process.\n";
  307. } break;
  308. }
  309. return result;
  310. }