cmProcess.cxx 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. //If process terminated, flush the buffer
  85. if(!running)
  86. {
  87. if(!this->StdErrorBuffer.empty())
  88. {
  89. gotStdErr = true;
  90. stdErrLine.append(&this->StdErrorBuffer[0], this->StdErrorBuffer.size());
  91. this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(),
  92. this->StdErrorBuffer.end());
  93. }
  94. if(!this->StdOutBuffer.empty())
  95. {
  96. gotStdOut = true;
  97. stdOutLine.append(&this->StdOutBuffer[0], this->StdOutBuffer.size());
  98. this->StdOutBuffer.erase(this->StdOutBuffer.begin(),
  99. this->StdOutBuffer.end());
  100. }
  101. return cmsysProcess_Pipe_None;
  102. }
  103. // Check for a newline in stdout.
  104. for(;outiter != this->StdOutBuffer.end(); ++outiter)
  105. {
  106. if((*outiter == '\r') && ((outiter+1) == this->StdOutBuffer.end()))
  107. {
  108. break;
  109. }
  110. else if(*outiter == '\n' || *outiter == '\0')
  111. {
  112. int length = outiter-this->StdOutBuffer.begin();
  113. if(length > 1 && *(outiter-1) == '\r')
  114. {
  115. --length;
  116. }
  117. if(length > 0)
  118. {
  119. stdOutLine.append(&this->StdOutBuffer[0], length);
  120. }
  121. this->StdOutBuffer.erase(this->StdOutBuffer.begin(), outiter+1);
  122. this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
  123. gotStdOut = true;
  124. break;
  125. }
  126. }
  127. // Check for a newline in stderr.
  128. for(;erriter != this->StdErrorBuffer.end(); ++erriter)
  129. {
  130. if((*erriter == '\r') && ((erriter+1) == this->StdErrorBuffer.end()))
  131. {
  132. break;
  133. }
  134. else if(*erriter == '\n' || *erriter == '\0')
  135. {
  136. int length = erriter-this->StdErrorBuffer.begin();
  137. if(length > 1 && *(erriter-1) == '\r')
  138. {
  139. --length;
  140. }
  141. if(length > 0)
  142. {
  143. stdErrLine.append(&this->StdErrorBuffer[0], length);
  144. }
  145. this->StdErrorBuffer.erase(this->StdErrorBuffer.begin(), erriter+1);
  146. this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
  147. gotStdErr = true;
  148. break;
  149. }
  150. }
  151. //If we get here, we have stuff waiting in the buffers, but no newline
  152. return this->LastOutputPipe;
  153. }
  154. // return true if there is a new line of data
  155. // return false if there is no new data
  156. bool cmProcess::CheckOutput(double timeout)
  157. {
  158. // Wait for data from the process.
  159. int length;
  160. char* data;
  161. while(1)
  162. {
  163. int pipe = cmsysProcess_WaitForData(this->Process, &data,
  164. &length, &timeout);
  165. if(pipe == cmsysProcess_Pipe_Timeout)
  166. {
  167. // Timeout has been exceeded.
  168. this->LastOutputPipe = pipe;
  169. return true;
  170. }
  171. else if(pipe == cmsysProcess_Pipe_STDOUT)
  172. {
  173. // Append to the stdout buffer.
  174. this->StdOutBuffer.insert(this->StdOutBuffer.end(), data, data+length);
  175. this->LastOutputPipe = pipe;
  176. }
  177. else if(pipe == cmsysProcess_Pipe_STDERR)
  178. {
  179. // Append to the stderr buffer.
  180. this->StdErrorBuffer.insert(this->StdErrorBuffer.end(),
  181. data, data+length);
  182. this->LastOutputPipe = pipe;
  183. }
  184. else if(pipe == cmsysProcess_Pipe_None)
  185. {
  186. // Both stdout and stderr pipes have broken. Return leftover data.
  187. if(!this->StdOutBuffer.empty())
  188. {
  189. this->LastOutputPipe = cmsysProcess_Pipe_STDOUT;
  190. return false;
  191. }
  192. else if(!this->StdErrorBuffer.empty())
  193. {
  194. this->LastOutputPipe = cmsysProcess_Pipe_STDERR;
  195. return false;
  196. }
  197. else
  198. {
  199. this->LastOutputPipe = cmsysProcess_Pipe_None;
  200. return false;
  201. }
  202. }
  203. }
  204. }
  205. // return the process status
  206. int cmProcess::GetProcessStatus()
  207. {
  208. if(!this->Process)
  209. {
  210. return cmsysProcess_State_Exited;
  211. }
  212. return cmsysProcess_GetState(this->Process);
  213. }
  214. // return true if the process is running
  215. bool cmProcess::IsRunning()
  216. {
  217. int status = this->GetProcessStatus();
  218. if(status == cmsysProcess_State_Executing )
  219. {
  220. if(this->LastOutputPipe != 0)
  221. {
  222. return true;
  223. }
  224. }
  225. // if the process is done, then wait for it to exit
  226. cmsysProcess_WaitForExit(this->Process, 0);
  227. this->ExitValue = cmsysProcess_GetExitValue(this->Process);
  228. this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
  229. // std::cerr << "Time to run: " << this->TotalTime << "\n";
  230. return false;
  231. }
  232. int cmProcess::ReportStatus()
  233. {
  234. int result = 1;
  235. switch(cmsysProcess_GetState(this->Process))
  236. {
  237. case cmsysProcess_State_Starting:
  238. {
  239. std::cerr << "cmProcess: Never started "
  240. << this->Command << " process.\n";
  241. } break;
  242. case cmsysProcess_State_Error:
  243. {
  244. std::cerr << "cmProcess: Error executing " << this->Command
  245. << " process: "
  246. << cmsysProcess_GetErrorString(this->Process)
  247. << "\n";
  248. } break;
  249. case cmsysProcess_State_Exception:
  250. {
  251. std::cerr << "cmProcess: " << this->Command
  252. << " process exited with an exception: ";
  253. switch(cmsysProcess_GetExitException(this->Process))
  254. {
  255. case cmsysProcess_Exception_None:
  256. {
  257. std::cerr << "None";
  258. } break;
  259. case cmsysProcess_Exception_Fault:
  260. {
  261. std::cerr << "Segmentation fault";
  262. } break;
  263. case cmsysProcess_Exception_Illegal:
  264. {
  265. std::cerr << "Illegal instruction";
  266. } break;
  267. case cmsysProcess_Exception_Interrupt:
  268. {
  269. std::cerr << "Interrupted by user";
  270. } break;
  271. case cmsysProcess_Exception_Numerical:
  272. {
  273. std::cerr << "Numerical exception";
  274. } break;
  275. case cmsysProcess_Exception_Other:
  276. {
  277. std::cerr << "Unknown";
  278. } break;
  279. }
  280. std::cerr << "\n";
  281. } break;
  282. case cmsysProcess_State_Executing:
  283. {
  284. std::cerr << "cmProcess: Never terminated " <<
  285. this->Command << " process.\n";
  286. } break;
  287. case cmsysProcess_State_Exited:
  288. {
  289. result = cmsysProcess_GetExitValue(this->Process);
  290. std::cerr << "cmProcess: " << this->Command
  291. << " process exited with code "
  292. << result << "\n";
  293. } break;
  294. case cmsysProcess_State_Expired:
  295. {
  296. std::cerr << "cmProcess: killed " << this->Command
  297. << " process due to timeout.\n";
  298. } break;
  299. case cmsysProcess_State_Killed:
  300. {
  301. std::cerr << "cmProcess: killed " << this->Command << " process.\n";
  302. } break;
  303. }
  304. return result;
  305. }