cmExecuteProcessCommand.cxx 8.4 KB

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