cmExecuteProcessCommand.cxx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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 "cmExecuteProcessCommand.h"
  14. #include "cmSystemTools.h"
  15. #include <cmsys/Process.h>
  16. void cmExecuteProcessCommandFixText(std::vector<char>& output);
  17. // cmExecuteProcessCommand
  18. bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args)
  19. {
  20. if(args.size() < 1 )
  21. {
  22. this->SetError("called with incorrect number of arguments");
  23. return false;
  24. }
  25. std::vector< std::vector<const char*> > cmds;
  26. std::string arguments;
  27. bool doing_command = false;
  28. unsigned int command_index = 0;
  29. bool output_quiet = false;
  30. bool error_quiet = false;
  31. std::string timeout_string;
  32. std::string input_file;
  33. std::string output_file;
  34. std::string error_file;
  35. std::string output_variable;
  36. std::string error_variable;
  37. std::string result_variable;
  38. std::string working_directory;
  39. for(size_t i=0; i < args.size(); ++i)
  40. {
  41. if(args[i] == "COMMAND")
  42. {
  43. doing_command = true;
  44. command_index = cmds.size();
  45. cmds.push_back(std::vector<const char*>());
  46. }
  47. else if(args[i] == "OUTPUT_VARIABLE")
  48. {
  49. doing_command = false;
  50. if(++i < args.size())
  51. {
  52. output_variable = args[i];
  53. }
  54. else
  55. {
  56. this->SetError(" called with no value for OUTPUT_VARIABLE.");
  57. return false;
  58. }
  59. }
  60. else if(args[i] == "ERROR_VARIABLE")
  61. {
  62. doing_command = false;
  63. if(++i < args.size())
  64. {
  65. error_variable = args[i];
  66. }
  67. else
  68. {
  69. this->SetError(" called with no value for ERROR_VARIABLE.");
  70. return false;
  71. }
  72. }
  73. else if(args[i] == "RESULT_VARIABLE")
  74. {
  75. doing_command = false;
  76. if(++i < args.size())
  77. {
  78. result_variable = args[i];
  79. }
  80. else
  81. {
  82. this->SetError(" called with no value for RESULT_VARIABLE.");
  83. return false;
  84. }
  85. }
  86. else if(args[i] == "WORKING_DIRECTORY")
  87. {
  88. doing_command = false;
  89. if(++i < args.size())
  90. {
  91. working_directory = args[i];
  92. }
  93. else
  94. {
  95. this->SetError(" called with no value for WORKING_DIRECTORY.");
  96. return false;
  97. }
  98. }
  99. else if(args[i] == "INPUT_FILE")
  100. {
  101. doing_command = false;
  102. if(++i < args.size())
  103. {
  104. input_file = args[i];
  105. }
  106. else
  107. {
  108. this->SetError(" called with no value for INPUT_FILE.");
  109. return false;
  110. }
  111. }
  112. else if(args[i] == "OUTPUT_FILE")
  113. {
  114. doing_command = false;
  115. if(++i < args.size())
  116. {
  117. output_file = args[i];
  118. }
  119. else
  120. {
  121. this->SetError(" called with no value for OUTPUT_FILE.");
  122. return false;
  123. }
  124. }
  125. else if(args[i] == "ERROR_FILE")
  126. {
  127. doing_command = false;
  128. if(++i < args.size())
  129. {
  130. error_file = args[i];
  131. }
  132. else
  133. {
  134. this->SetError(" called with no value for ERROR_FILE.");
  135. return false;
  136. }
  137. }
  138. else if(args[i] == "TIMEOUT")
  139. {
  140. doing_command = false;
  141. if(++i < args.size())
  142. {
  143. timeout_string = args[i];
  144. }
  145. else
  146. {
  147. this->SetError(" called with no value for TIMEOUT.");
  148. return false;
  149. }
  150. }
  151. else if(args[i] == "OUTPUT_QUIET")
  152. {
  153. doing_command = false;
  154. output_quiet = true;
  155. }
  156. else if(args[i] == "ERROR_QUIET")
  157. {
  158. doing_command = false;
  159. error_quiet = true;
  160. }
  161. else if(doing_command)
  162. {
  163. cmds[command_index].push_back(args[i].c_str());
  164. }
  165. }
  166. // Check for commands given.
  167. if(cmds.empty())
  168. {
  169. this->SetError(" called with no COMMAND argument.");
  170. return false;
  171. }
  172. for(unsigned int i=0; i < cmds.size(); ++i)
  173. {
  174. if(cmds[i].empty())
  175. {
  176. this->SetError(" given COMMAND argument with no value.");
  177. return false;
  178. }
  179. else
  180. {
  181. // Add the null terminating pointer to the command argument list.
  182. cmds[i].push_back(0);
  183. }
  184. }
  185. // Parse the timeout string.
  186. double timeout = -1;
  187. if(!timeout_string.empty())
  188. {
  189. if(sscanf(timeout_string.c_str(), "%lg", &timeout) != 1)
  190. {
  191. this->SetError(" called with TIMEOUT value that could not be parsed.");
  192. return false;
  193. }
  194. }
  195. // Create a process instance.
  196. cmsysProcess* cp = cmsysProcess_New();
  197. // Set the command sequence.
  198. for(unsigned int i=0; i < cmds.size(); ++i)
  199. {
  200. cmsysProcess_AddCommand(cp, &*cmds[i].begin());
  201. }
  202. // Set the process working directory.
  203. if(!working_directory.empty())
  204. {
  205. cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
  206. }
  207. // Always hide the process window.
  208. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  209. // Check the output variables.
  210. bool merge_output = (output_variable == error_variable);
  211. if(error_variable.empty() && !error_quiet)
  212. {
  213. cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
  214. }
  215. if(!input_file.empty())
  216. {
  217. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
  218. }
  219. if(!output_file.empty())
  220. {
  221. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT, output_file.c_str());
  222. }
  223. if(!error_file.empty())
  224. {
  225. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR, error_file.c_str());
  226. }
  227. // Set the timeout if any.
  228. if(timeout >= 0)
  229. {
  230. cmsysProcess_SetTimeout(cp, timeout);
  231. }
  232. // Start the process.
  233. cmsysProcess_Execute(cp);
  234. // Read the process output.
  235. std::vector<char> tempOutput;
  236. std::vector<char> tempError;
  237. int length;
  238. char* data;
  239. int p;
  240. while((p = cmsysProcess_WaitForData(cp, &data, &length, 0), p))
  241. {
  242. // Put the output in the right place.
  243. if(p == cmsysProcess_Pipe_STDOUT && !output_quiet ||
  244. p == cmsysProcess_Pipe_STDERR && !error_quiet && merge_output)
  245. {
  246. if(output_variable.empty())
  247. {
  248. cmSystemTools::Stdout(data, length);
  249. }
  250. else
  251. {
  252. tempOutput.insert(tempOutput.end(), data, data+length);
  253. }
  254. }
  255. else if(p == cmsysProcess_Pipe_STDERR && !error_quiet)
  256. {
  257. if(!error_variable.empty())
  258. {
  259. tempError.insert(tempError.end(), data, data+length);
  260. }
  261. }
  262. }
  263. // All output has been read. Wait for the process to exit.
  264. cmsysProcess_WaitForExit(cp, 0);
  265. // Fix the text in the output strings.
  266. cmExecuteProcessCommandFixText(tempOutput);
  267. cmExecuteProcessCommandFixText(tempError);
  268. // Store the output obtained.
  269. if(!output_variable.empty())
  270. {
  271. this->Makefile->AddDefinition(output_variable.c_str(), &*tempOutput.begin());
  272. }
  273. if(!merge_output && !error_variable.empty())
  274. {
  275. this->Makefile->AddDefinition(error_variable.c_str(), &*tempError.begin());
  276. }
  277. // Store the result of running the process.
  278. if(!result_variable.empty())
  279. {
  280. switch(cmsysProcess_GetState(cp))
  281. {
  282. case cmsysProcess_State_Exited:
  283. {
  284. int v = cmsysProcess_GetExitValue(cp);
  285. char buf[100];
  286. sprintf(buf, "%d", v);
  287. this->Makefile->AddDefinition(result_variable.c_str(), buf);
  288. }
  289. break;
  290. case cmsysProcess_State_Exception:
  291. this->Makefile->AddDefinition(result_variable.c_str(),
  292. cmsysProcess_GetExceptionString(cp));
  293. break;
  294. case cmsysProcess_State_Error:
  295. this->Makefile->AddDefinition(result_variable.c_str(),
  296. cmsysProcess_GetErrorString(cp));
  297. break;
  298. case cmsysProcess_State_Expired:
  299. this->Makefile->AddDefinition(result_variable.c_str(),
  300. "Process terminated due to timeout");
  301. break;
  302. }
  303. }
  304. // Delete the process instance.
  305. cmsysProcess_Delete(cp);
  306. return true;
  307. }
  308. //----------------------------------------------------------------------------
  309. void cmExecuteProcessCommandFixText(std::vector<char>& output)
  310. {
  311. // Remove \0 characters and the \r part of \r\n pairs.
  312. unsigned int in_index = 0;
  313. unsigned int out_index = 0;
  314. while(in_index < output.size())
  315. {
  316. char c = output[in_index++];
  317. if((c != '\r' || !(in_index < output.size() && output[in_index] == '\n'))
  318. && c != '\0')
  319. {
  320. output[out_index++] = c;
  321. }
  322. }
  323. output.resize(out_index);
  324. // Put a terminator on the text string.
  325. output.push_back('\0');
  326. }