diff options
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r-- | Source/cmSystemTools.cxx | 338 |
1 files changed, 252 insertions, 86 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index d6ec70f..ecdfb48 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -22,7 +22,6 @@ #include <cmsys/RegularExpression.hxx> #include <cmsys/Directory.hxx> -#include <cmsys/Process.h> // support for realpath call #ifndef _WIN32 @@ -302,116 +301,283 @@ bool cmSystemTools::RunCommand(const char* command, dir, verbose, timeout); } -bool cmSystemTools::RunCommand(const char* command, - std::string& output, - int &retVal, - const char* dir, - bool verbose, - int) +#if defined(WIN32) && !defined(__CYGWIN__) +#include "cmWin32ProcessExecution.h" +// use this for shell commands like echo and dir +bool RunCommandViaWin32(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose, + int timeout) { - if(s_DisableRunCommandOutput) +#if defined(__BORLANDC__) + return cmWin32ProcessExecution::BorlandRunCommand(command, dir, output, + retVal, + verbose, timeout, + cmSystemTools::GetRunCommandHideConsole()); +#else // Visual studio + ::SetLastError(ERROR_SUCCESS); + if ( ! command ) + { + cmSystemTools::Error("No command specified"); + return false; + } + + cmWin32ProcessExecution resProc; + if(cmSystemTools::GetRunCommandHideConsole()) { - verbose = false; + resProc.SetHideWindows(true); } - std::vector<std::string> args; - std::string arg; - - // Split the command into an argv array. - for(const char* c = command; *c;) + if ( cmSystemTools::GetWindows9xComspecSubstitute() ) { - // Skip over whitespace. - while(*c == ' ' || *c == '\t') - { - ++c; - } - arg = ""; - if(*c == '"') + resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() ); + } + if ( !resProc.StartProcess(command, dir, verbose) ) + { + return false; + } + resProc.Wait(timeout); + output = resProc.GetOutput(); + retVal = resProc.GetExitValue(); + return true; +#endif +} + +// use this for shell commands like echo and dir +bool RunCommandViaSystem(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose) +{ + std::cout << "@@ " << command << std::endl; + + std::string commandInDir; + if(dir) + { + commandInDir = "cd "; + commandInDir += cmSystemTools::ConvertToOutputPath(dir); + commandInDir += " && "; + commandInDir += command; + } + else + { + commandInDir = command; + } + command = commandInDir.c_str(); + std::string commandToFile = command; + commandToFile += " > "; + std::string tempFile; + tempFile += _tempnam(0, "cmake"); + + commandToFile += tempFile; + retVal = system(commandToFile.c_str()); + std::ifstream fin(tempFile.c_str()); + if(!fin) + { + if(verbose) { - // Parse a quoted argument. - ++c; - while(*c && *c != '"') - { - if(*c == '\\') - { - ++c; - if(*c) - { - arg.append(1, *c); - ++c; - } - } - else - { - arg.append(1, *c); - ++c; - } - } - if(*c) - { - ++c; - } - args.push_back(arg); + std::string errormsg = "RunCommand produced no output: command: \""; + errormsg += command; + errormsg += "\""; + errormsg += "\nOutput file: "; + errormsg += tempFile; + cmSystemTools::Error(errormsg.c_str()); } - else if(*c) + fin.close(); + cmSystemTools::RemoveFile(tempFile.c_str()); + return false; + } + bool multiLine = false; + std::string line; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + output += line; + if(multiLine) { - // Parse an unquoted argument. - while(*c && *c != ' ' && *c != '\t') - { - arg.append(1, *c); - ++c; - } - args.push_back(arg); + output += "\n"; } + multiLine = true; } - - std::vector<const char*> argv; - for(std::vector<std::string>::const_iterator a = args.begin(); - a != args.end(); ++a) + fin.close(); + cmSystemTools::RemoveFile(tempFile.c_str()); + return true; +} + +#else // We have popen + +bool RunCommandViaPopen(const char* command, + const char* dir, + std::string& output, + int& retVal, + bool verbose, + int /*timeout*/) +{ + // if only popen worked on windows..... + std::string commandInDir; + if(dir) { - argv.push_back(a->c_str()); + commandInDir = "cd \""; + commandInDir += dir; + commandInDir += "\" && "; + commandInDir += command; } - argv.push_back(0); - - if(argv.size() < 2) + else + { + commandInDir = command; + } + commandInDir += " 2>&1"; + command = commandInDir.c_str(); + const int BUFFER_SIZE = 4096; + char buffer[BUFFER_SIZE]; + if(verbose) + { + std::cout << "running " << command << std::endl; + } + fflush(stdout); + fflush(stderr); + FILE* cpipe = popen(command, "r"); + if(!cpipe) { return false; } - - output = ""; - cmsysProcess* cp = cmsysProcess_New(); - cmsysProcess_SetCommand(cp, &*argv.begin()); - cmsysProcess_SetWorkingDirectory(cp, dir); - cmsysProcess_Execute(cp); - - char* data; - int length; - while(cmsysProcess_WaitForData(cp, (cmsysProcess_Pipe_STDOUT | - cmsysProcess_Pipe_STDERR), - &data, &length, 0)) + fgets(buffer, BUFFER_SIZE, cpipe); + while(!feof(cpipe)) { - output.append(data, length); if(verbose) { - std::cout.write(data, length); + std::cout << buffer << std::flush; } + output += buffer; + fgets(buffer, BUFFER_SIZE, cpipe); } - - cmsysProcess_WaitForExit(cp, 0); - - bool result = true; - if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) + + retVal = pclose(cpipe); + if (WIFEXITED(retVal)) { - retVal = cmsysProcess_GetExitValue(cp); + retVal = WEXITSTATUS(retVal); + return true; } - else + if (WIFSIGNALED(retVal)) { - result = false; + retVal = WTERMSIG(retVal); + cmOStringStream error; + error << "\nProcess terminated due to "; + switch (retVal) + { +#ifdef SIGKILL + case SIGKILL: + error << "SIGKILL"; + break; +#endif +#ifdef SIGFPE + case SIGFPE: + error << "SIGFPE"; + break; +#endif +#ifdef SIGBUS + case SIGBUS: + error << "SIGBUS"; + break; +#endif +#ifdef SIGSEGV + case SIGSEGV: + error << "SIGSEGV"; + break; +#endif + default: + error << "signal " << retVal; + break; + } + output += error.str(); + } + return false; +} + +#endif // endif WIN32 not CYGWIN + + +// run a command unix uses popen (easy) +// windows uses system and ShortPath +bool cmSystemTools::RunCommand(const char* command, + std::string& output, + int &retVal, + const char* dir, + bool verbose, + int timeout) +{ + if(s_DisableRunCommandOutput) + { + verbose = false; } - cmsysProcess_Delete(cp); - - return result; +#if defined(WIN32) && !defined(__CYGWIN__) + // if the command does not start with a quote, then + // try to find the program, and if the program can not be + // found use system to run the command as it must be a built in + // shell command like echo or dir + int count = 0; + if(command[0] == '\"') + { + // count the number of quotes + for(const char* s = command; *s != 0; ++s) + { + if(*s == '\"') + { + count++; + if(count > 2) + { + break; + } + } + } + // if there are more than two double quotes use + // GetShortPathName, the cmd.exe program in windows which + // is used by system fails to execute if there are more than + // one set of quotes in the arguments + if(count > 2) + { + cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)"); + if(quoted.find(command)) + { + std::string shortCmd; + std::string cmd = quoted.match(1); + std::string args = quoted.match(2); + if(! cmSystemTools::FileExists(cmd.c_str()) ) + { + shortCmd = cmd; + } + else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) + { + cmSystemTools::Error("GetShortPath failed for " , cmd.c_str()); + return false; + } + shortCmd += " "; + shortCmd += args; + + //return RunCommandViaSystem(shortCmd.c_str(), dir, + // output, retVal, verbose); + //return WindowsRunCommand(shortCmd.c_str(), dir, + //output, retVal, verbose); + return RunCommandViaWin32(shortCmd.c_str(), dir, + output, retVal, verbose, timeout); + } + else + { + cmSystemTools::Error("Could not parse command line with quotes ", + command); + } + } + } + // if there is only one set of quotes or no quotes then just run the command + //return RunCommandViaSystem(command, dir, output, retVal, verbose); + //return WindowsRunCommand(command, dir, output, retVal, verbose); + return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout); +#else + return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout); +#endif } bool cmSystemTools::DoesFileExistWithExtensions( |