ENH: Using kwsys Process implementation to implement RunCommand.

This commit is contained in:
Brad King 2003-07-07 08:41:28 -04:00
parent 125b795637
commit ccc629702c
1 changed files with 101 additions and 252 deletions

View File

@ -22,6 +22,7 @@
#include <cmsys/RegularExpression.hxx> #include <cmsys/RegularExpression.hxx>
#include <cmsys/Directory.hxx> #include <cmsys/Directory.hxx>
#include <cmsys/Process.h>
// support for realpath call // support for realpath call
#ifndef _WIN32 #ifndef _WIN32
@ -301,283 +302,131 @@ bool cmSystemTools::RunCommand(const char* command,
dir, verbose, timeout); dir, verbose, timeout);
} }
#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 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())
{
resProc.SetHideWindows(true);
}
if ( cmSystemTools::GetWindows9xComspecSubstitute() )
{
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)
{
std::string errormsg = "RunCommand produced no output: command: \"";
errormsg += command;
errormsg += "\"";
errormsg += "\nOutput file: ";
errormsg += tempFile;
cmSystemTools::Error(errormsg.c_str());
}
fin.close();
cmSystemTools::RemoveFile(tempFile.c_str());
return false;
}
bool multiLine = false;
std::string line;
while(cmSystemTools::GetLineFromStream(fin, line))
{
output += line;
if(multiLine)
{
output += "\n";
}
multiLine = true;
}
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)
{
commandInDir = "cd \"";
commandInDir += dir;
commandInDir += "\" && ";
commandInDir += command;
}
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;
}
fgets(buffer, BUFFER_SIZE, cpipe);
while(!feof(cpipe))
{
if(verbose)
{
std::cout << buffer << std::flush;
}
output += buffer;
fgets(buffer, BUFFER_SIZE, cpipe);
}
retVal = pclose(cpipe);
if (WIFEXITED(retVal))
{
retVal = WEXITSTATUS(retVal);
return true;
}
if (WIFSIGNALED(retVal))
{
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, bool cmSystemTools::RunCommand(const char* command,
std::string& output, std::string& output,
int &retVal, int &retVal,
const char* dir, const char* dir,
bool verbose, bool verbose,
int timeout) int)
{ {
if(s_DisableRunCommandOutput) if(s_DisableRunCommandOutput)
{ {
verbose = false; verbose = false;
} }
#if defined(WIN32) && !defined(__CYGWIN__) std::vector<std::string> args;
// if the command does not start with a quote, then std::string arg;
// 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 // Split the command into an argv array.
// shell command like echo or dir for(const char* c = command; *c;)
int count = 0;
if(command[0] == '\"')
{ {
// count the number of quotes // Skip over whitespace.
for(const char* s = command; *s != 0; ++s) while(*c == ' ' || *c == '\t')
{ {
if(*s == '\"') ++c;
{
count++;
if(count > 2)
{
break;
}
}
} }
// if there are more than two double quotes use arg = "";
// GetShortPathName, the cmd.exe program in windows which if(*c == '"')
// 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](.*)"); // Parse a quoted argument.
if(quoted.find(command)) ++c;
while(*c && *c != '"')
{ {
std::string shortCmd; if(*c == '\\')
std::string cmd = quoted.match(1);
std::string args = quoted.match(2);
if(! cmSystemTools::FileExists(cmd.c_str()) )
{ {
shortCmd = cmd; ++c;
if(*c)
{
arg.append(1, *c);
++c;
}
} }
else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) else
{ {
cmSystemTools::Error("GetShortPath failed for " , cmd.c_str()); arg.append(1, *c);
return false; ++c;
} }
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 if(*c)
{ {
cmSystemTools::Error("Could not parse command line with quotes ", ++c;
command);
} }
args.push_back(arg);
}
else if(*c)
{
// Parse an unquoted argument.
while(*c && *c != ' ' && *c != '\t')
{
arg.append(1, *c);
++c;
}
args.push_back(arg);
} }
} }
// if there is only one set of quotes or no quotes then just run the command
//return RunCommandViaSystem(command, dir, output, retVal, verbose); std::vector<const char*> argv;
//return WindowsRunCommand(command, dir, output, retVal, verbose); for(std::vector<std::string>::const_iterator a = args.begin();
return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout); a != args.end(); ++a)
#else {
return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout); argv.push_back(a->c_str());
#endif }
argv.push_back(0);
if(argv.size() < 2)
{
return false;
}
// Change to specified working directory.
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
if(dir)
{
if(cmSystemTools::ChangeDirectory(dir) < 0)
{
return false;
}
}
output = "";
cmsysProcess* cp = cmsysProcess_New();
cmsysProcess_SetCommand(cp, &*argv.begin());
cmsysProcess_Execute(cp);
char* data;
int length;
while(cmsysProcess_WaitForData(cp, (cmsysProcess_Pipe_STDOUT |
cmsysProcess_Pipe_STDERR),
&data, &length, 0))
{
output.append(data, length);
if(verbose)
{
std::cout.write(data, length);
}
}
cmsysProcess_WaitForExit(cp, 0);
bool result = true;
if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
{
retVal = cmsysProcess_GetExitValue(cp);
}
else
{
result = false;
}
cmsysProcess_Delete(cp);
// Restore old working directory.
if(dir)
{
cmSystemTools::ChangeDirectory(cwd.c_str());
}
return result;
} }
bool cmSystemTools::DoesFileExistWithExtensions( bool cmSystemTools::DoesFileExistWithExtensions(