cmExecuteProcessCommand.cxx 9.3 KB

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