cmProcess.cxx 8.3 KB

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