1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmExecuteProcessCommand.h"
13 #include "cmSystemTools.h"
15 #include <cmsys/Process.h>
17 #include <ctype.h> /* isspace */
19 static bool cmExecuteProcessCommandIsWhitespace(char c)
21 return (isspace((int)c) || c == '\n' || c == '\r');
24 void cmExecuteProcessCommandFixText(std::vector<char>& output,
25 bool strip_trailing_whitespace);
26 void cmExecuteProcessCommandAppend(std::vector<char>& output,
27 const char* data, int length);
29 // cmExecuteProcessCommand
30 bool cmExecuteProcessCommand
31 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
35 this->SetError("called with incorrect number of arguments");
38 std::vector< std::vector<const char*> > cmds;
39 std::string arguments;
40 bool doing_command = false;
41 size_t command_index = 0;
42 bool output_quiet = false;
43 bool error_quiet = false;
44 bool output_strip_trailing_whitespace = false;
45 bool error_strip_trailing_whitespace = false;
46 std::string timeout_string;
47 std::string input_file;
48 std::string output_file;
49 std::string error_file;
50 std::string output_variable;
51 std::string error_variable;
52 std::string result_variable;
53 std::string working_directory;
54 for(size_t i=0; i < args.size(); ++i)
56 if(args[i] == "COMMAND")
59 command_index = cmds.size();
60 cmds.push_back(std::vector<const char*>());
62 else if(args[i] == "OUTPUT_VARIABLE")
64 doing_command = false;
67 output_variable = args[i];
71 this->SetError(" called with no value for OUTPUT_VARIABLE.");
75 else if(args[i] == "ERROR_VARIABLE")
77 doing_command = false;
80 error_variable = args[i];
84 this->SetError(" called with no value for ERROR_VARIABLE.");
88 else if(args[i] == "RESULT_VARIABLE")
90 doing_command = false;
93 result_variable = args[i];
97 this->SetError(" called with no value for RESULT_VARIABLE.");
101 else if(args[i] == "WORKING_DIRECTORY")
103 doing_command = false;
104 if(++i < args.size())
106 working_directory = args[i];
110 this->SetError(" called with no value for WORKING_DIRECTORY.");
114 else if(args[i] == "INPUT_FILE")
116 doing_command = false;
117 if(++i < args.size())
119 input_file = args[i];
123 this->SetError(" called with no value for INPUT_FILE.");
127 else if(args[i] == "OUTPUT_FILE")
129 doing_command = false;
130 if(++i < args.size())
132 output_file = args[i];
136 this->SetError(" called with no value for OUTPUT_FILE.");
140 else if(args[i] == "ERROR_FILE")
142 doing_command = false;
143 if(++i < args.size())
145 error_file = args[i];
149 this->SetError(" called with no value for ERROR_FILE.");
153 else if(args[i] == "TIMEOUT")
155 doing_command = false;
156 if(++i < args.size())
158 timeout_string = args[i];
162 this->SetError(" called with no value for TIMEOUT.");
166 else if(args[i] == "OUTPUT_QUIET")
168 doing_command = false;
171 else if(args[i] == "ERROR_QUIET")
173 doing_command = false;
176 else if(args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE")
178 doing_command = false;
179 output_strip_trailing_whitespace = true;
181 else if(args[i] == "ERROR_STRIP_TRAILING_WHITESPACE")
183 doing_command = false;
184 error_strip_trailing_whitespace = true;
186 else if(doing_command)
188 cmds[command_index].push_back(args[i].c_str());
193 e << " given unknown argument \"" << args[i] << "\".";
194 this->SetError(e.str().c_str());
199 if ( !this->Makefile->CanIWriteThisFile(output_file.c_str()) )
201 std::string e = "attempted to output into a file: " + output_file
202 + " into a source directory.";
203 this->SetError(e.c_str());
204 cmSystemTools::SetFatalErrorOccured();
208 // Check for commands given.
211 this->SetError(" called with no COMMAND argument.");
214 for(unsigned int i=0; i < cmds.size(); ++i)
218 this->SetError(" given COMMAND argument with no value.");
223 // Add the null terminating pointer to the command argument list.
224 cmds[i].push_back(0);
228 // Parse the timeout string.
230 if(!timeout_string.empty())
232 if(sscanf(timeout_string.c_str(), "%lg", &timeout) != 1)
234 this->SetError(" called with TIMEOUT value that could not be parsed.");
239 // Create a process instance.
240 cmsysProcess* cp = cmsysProcess_New();
242 // Set the command sequence.
243 for(unsigned int i=0; i < cmds.size(); ++i)
245 cmsysProcess_AddCommand(cp, &*cmds[i].begin());
248 // Set the process working directory.
249 if(!working_directory.empty())
251 cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
254 // Always hide the process window.
255 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
257 // Check the output variables.
258 bool merge_output = (output_variable == error_variable);
259 if(error_variable.empty() && !error_quiet)
261 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
263 if(!input_file.empty())
265 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
267 if(!output_file.empty())
269 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
270 output_file.c_str());
272 if(!error_file.empty())
274 cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
278 // Set the timeout if any.
281 cmsysProcess_SetTimeout(cp, timeout);
284 // Start the process.
285 cmsysProcess_Execute(cp);
287 // Read the process output.
288 std::vector<char> tempOutput;
289 std::vector<char> tempError;
293 while((p = cmsysProcess_WaitForData(cp, &data, &length, 0), p))
295 // Put the output in the right place.
296 if((p == cmsysProcess_Pipe_STDOUT && !output_quiet) ||
297 (p == cmsysProcess_Pipe_STDERR && !error_quiet && merge_output))
299 if(output_variable.empty())
301 cmSystemTools::Stdout(data, length);
305 cmExecuteProcessCommandAppend(tempOutput, data, length);
308 else if(p == cmsysProcess_Pipe_STDERR && !error_quiet)
310 if(!error_variable.empty())
312 cmExecuteProcessCommandAppend(tempError, data, length);
317 // All output has been read. Wait for the process to exit.
318 cmsysProcess_WaitForExit(cp, 0);
320 // Fix the text in the output strings.
321 cmExecuteProcessCommandFixText(tempOutput,
322 output_strip_trailing_whitespace);
323 cmExecuteProcessCommandFixText(tempError,
324 error_strip_trailing_whitespace);
326 // Store the output obtained.
327 if(!output_variable.empty() && tempOutput.size())
329 this->Makefile->AddDefinition(output_variable.c_str(),
330 &*tempOutput.begin());
332 if(!merge_output && !error_variable.empty() && tempError.size())
334 this->Makefile->AddDefinition(error_variable.c_str(),
335 &*tempError.begin());
338 // Store the result of running the process.
339 if(!result_variable.empty())
341 switch(cmsysProcess_GetState(cp))
343 case cmsysProcess_State_Exited:
345 int v = cmsysProcess_GetExitValue(cp);
347 sprintf(buf, "%d", v);
348 this->Makefile->AddDefinition(result_variable.c_str(), buf);
351 case cmsysProcess_State_Exception:
352 this->Makefile->AddDefinition(result_variable.c_str(),
353 cmsysProcess_GetExceptionString(cp));
355 case cmsysProcess_State_Error:
356 this->Makefile->AddDefinition(result_variable.c_str(),
357 cmsysProcess_GetErrorString(cp));
359 case cmsysProcess_State_Expired:
360 this->Makefile->AddDefinition(result_variable.c_str(),
361 "Process terminated due to timeout");
366 // Delete the process instance.
367 cmsysProcess_Delete(cp);
372 //----------------------------------------------------------------------------
373 void cmExecuteProcessCommandFixText(std::vector<char>& output,
374 bool strip_trailing_whitespace)
376 // Remove \0 characters and the \r part of \r\n pairs.
377 unsigned int in_index = 0;
378 unsigned int out_index = 0;
379 while(in_index < output.size())
381 char c = output[in_index++];
382 if((c != '\r' || !(in_index < output.size() && output[in_index] == '\n'))
385 output[out_index++] = c;
389 // Remove trailing whitespace if requested.
390 if(strip_trailing_whitespace)
392 while(out_index > 0 &&
393 cmExecuteProcessCommandIsWhitespace(output[out_index-1]))
399 // Shrink the vector to the size needed.
400 output.resize(out_index);
402 // Put a terminator on the text string.
403 output.push_back('\0');
406 //----------------------------------------------------------------------------
407 void cmExecuteProcessCommandAppend(std::vector<char>& output,
408 const char* data, int length)
410 #if defined(__APPLE__)
411 // HACK on Apple to work around bug with inserting at the
412 // end of an empty vector. This resulted in random failures
413 // that were hard to reproduce.
414 if(output.empty() && length > 0)
416 output.push_back(data[0]);
421 output.insert(output.end(), data, data+length);