diff options
author | Brad King <brad.king@kitware.com> | 2003-07-07 22:27:57 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2003-07-07 22:27:57 (GMT) |
commit | cbb1de923a3fb977f3910d4054191cdffc478134 (patch) | |
tree | 27640401c236292a08197f627c6a009977a98277 /Source | |
parent | 2a6e9970b322296ecad4a8f3a6bec0e88ff989dc (diff) | |
download | CMake-cbb1de923a3fb977f3910d4054191cdffc478134.zip CMake-cbb1de923a3fb977f3910d4054191cdffc478134.tar.gz CMake-cbb1de923a3fb977f3910d4054191cdffc478134.tar.bz2 |
BUG: Parsing of arguments from string by RunCommand before passing to Process execution does not work with backslashes in path names. Until this is fixed, we cannot use Process execution from kwsys.
Diffstat (limited to 'Source')
-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( |