cmProcess.cxx 8.8 KB

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