cmExecuteProcessCommand.cxx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. if ( !this->Makefile->CanIWriteThisFile(output_file.c_str()) )
  167. {
  168. std::string e = "attempted to output into a file: " + output_file
  169. + " into a source directory.";
  170. this->SetError(e.c_str());
  171. cmSystemTools::SetFatalErrorOccured();
  172. return false;
  173. }
  174. // Check for commands given.
  175. if(cmds.empty())
  176. {
  177. this->SetError(" called with no COMMAND argument.");
  178. return false;
  179. }
  180. for(unsigned int i=0; i < cmds.size(); ++i)
  181. {
  182. if(cmds[i].empty())
  183. {
  184. this->SetError(" given COMMAND argument with no value.");
  185. return false;
  186. }
  187. else
  188. {
  189. // Add the null terminating pointer to the command argument list.
  190. cmds[i].push_back(0);
  191. }
  192. }
  193. // Parse the timeout string.
  194. double timeout = -1;
  195. if(!timeout_string.empty())
  196. {
  197. if(sscanf(timeout_string.c_str(), "%lg", &timeout) != 1)
  198. {
  199. this->SetError(" called with TIMEOUT value that could not be parsed.");
  200. return false;
  201. }
  202. }
  203. // Create a process instance.
  204. cmsysProcess* cp = cmsysProcess_New();
  205. // Set the command sequence.
  206. for(unsigned int i=0; i < cmds.size(); ++i)
  207. {
  208. cmsysProcess_AddCommand(cp, &*cmds[i].begin());
  209. }
  210. // Set the process working directory.
  211. if(!working_directory.empty())
  212. {
  213. cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
  214. }
  215. // Always hide the process window.
  216. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  217. // Check the output variables.
  218. bool merge_output = (output_variable == error_variable);
  219. if(error_variable.empty() && !error_quiet)
  220. {
  221. cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
  222. }
  223. if(!input_file.empty())
  224. {
  225. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
  226. }
  227. if(!output_file.empty())
  228. {
  229. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT, output_file.c_str());
  230. }
  231. if(!error_file.empty())
  232. {
  233. cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR, error_file.c_str());
  234. }
  235. // Set the timeout if any.
  236. if(timeout >= 0)
  237. {
  238. cmsysProcess_SetTimeout(cp, timeout);
  239. }
  240. // Start the process.
  241. cmsysProcess_Execute(cp);
  242. // Read the process output.
  243. std::vector<char> tempOutput;
  244. std::vector<char> tempError;
  245. int length;
  246. char* data;
  247. int p;
  248. while((p = cmsysProcess_WaitForData(cp, &data, &length, 0), p))
  249. {
  250. // Put the output in the right place.
  251. if(p == cmsysProcess_Pipe_STDOUT && !output_quiet ||
  252. p == cmsysProcess_Pipe_STDERR && !error_quiet && merge_output)
  253. {
  254. if(output_variable.empty())
  255. {
  256. cmSystemTools::Stdout(data, length);
  257. }
  258. else
  259. {
  260. tempOutput.insert(tempOutput.end(), data, data+length);
  261. }
  262. }
  263. else if(p == cmsysProcess_Pipe_STDERR && !error_quiet)
  264. {
  265. if(!error_variable.empty())
  266. {
  267. tempError.insert(tempError.end(), data, data+length);
  268. }
  269. }
  270. }
  271. // All output has been read. Wait for the process to exit.
  272. cmsysProcess_WaitForExit(cp, 0);
  273. // Fix the text in the output strings.
  274. cmExecuteProcessCommandFixText(tempOutput);
  275. cmExecuteProcessCommandFixText(tempError);
  276. // Store the output obtained.
  277. if(!output_variable.empty() && tempOutput.size())
  278. {
  279. this->Makefile->AddDefinition(output_variable.c_str(), &*tempOutput.begin());
  280. }
  281. if(!merge_output && !error_variable.empty() && tempError.size())
  282. {
  283. this->Makefile->AddDefinition(error_variable.c_str(), &*tempError.begin());
  284. }
  285. // Store the result of running the process.
  286. if(!result_variable.empty())
  287. {
  288. switch(cmsysProcess_GetState(cp))
  289. {
  290. case cmsysProcess_State_Exited:
  291. {
  292. int v = cmsysProcess_GetExitValue(cp);
  293. char buf[100];
  294. sprintf(buf, "%d", v);
  295. this->Makefile->AddDefinition(result_variable.c_str(), buf);
  296. }
  297. break;
  298. case cmsysProcess_State_Exception:
  299. this->Makefile->AddDefinition(result_variable.c_str(),
  300. cmsysProcess_GetExceptionString(cp));
  301. break;
  302. case cmsysProcess_State_Error:
  303. this->Makefile->AddDefinition(result_variable.c_str(),
  304. cmsysProcess_GetErrorString(cp));
  305. break;
  306. case cmsysProcess_State_Expired:
  307. this->Makefile->AddDefinition(result_variable.c_str(),
  308. "Process terminated due to timeout");
  309. break;
  310. }
  311. }
  312. // Delete the process instance.
  313. cmsysProcess_Delete(cp);
  314. return true;
  315. }
  316. //----------------------------------------------------------------------------
  317. void cmExecuteProcessCommandFixText(std::vector<char>& output)
  318. {
  319. // Remove \0 characters and the \r part of \r\n pairs.
  320. unsigned int in_index = 0;
  321. unsigned int out_index = 0;
  322. while(in_index < output.size())
  323. {
  324. char c = output[in_index++];
  325. if((c != '\r' || !(in_index < output.size() && output[in_index] == '\n'))
  326. && c != '\0')
  327. {
  328. output[out_index++] = c;
  329. }
  330. }
  331. output.resize(out_index);
  332. // Put a terminator on the text string.
  333. output.push_back('\0');
  334. }