You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
11 KiB

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