Pārlūkot izejas kodu

ENH: Using kwsys Process implementation to implement RunCommand.

Brad King 22 gadi atpakaļ
vecāks
revīzija
ccc629702c
1 mainītis faili ar 98 papildinājumiem un 249 dzēšanām
  1. 98 249
      Source/cmSystemTools.cxx

+ 98 - 249
Source/cmSystemTools.cxx

@@ -22,6 +22,7 @@
 
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/Directory.hxx>
+#include <cmsys/Process.h>
 
 // support for realpath call
 #ifndef _WIN32
@@ -301,283 +302,131 @@ bool cmSystemTools::RunCommand(const char* command,
                                    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)
+bool cmSystemTools::RunCommand(const char* command, 
+                               std::string& output,
+                               int &retVal, 
+                               const char* dir,
+                               bool verbose,
+                               int)
 {
-#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())
+  if(s_DisableRunCommandOutput)
     {
-    resProc.SetHideWindows(true);
+    verbose = false;
     }
   
-  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)
+  std::vector<std::string> args;
+  std::string arg;
+  
+  // Split the command into an argv array.
+  for(const char* c = command; *c;)
     {
-    if(verbose)
+    // Skip over whitespace.
+    while(*c == ' ' || *c == '\t')
       {
-      std::string errormsg = "RunCommand produced no output: command: \"";
-      errormsg += command;
-      errormsg += "\"";
-      errormsg += "\nOutput file: ";
-      errormsg += tempFile;
-      cmSystemTools::Error(errormsg.c_str());
+      ++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)
+    arg = "";
+    if(*c == '"')
+      {
+      // 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);
+      }
+    else if(*c)
       {
-      output += "\n";
+      // Parse an unquoted argument.
+      while(*c && *c != ' ' && *c != '\t')
+        {
+        arg.append(1, *c);
+        ++c;
+        }
+      args.push_back(arg);
       }
-    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
+  
+  std::vector<const char*> argv;
+  for(std::vector<std::string>::const_iterator a = args.begin();
+      a != args.end(); ++a)
     {
-    commandInDir = command;
+    argv.push_back(a->c_str());
     }
-  commandInDir += " 2>&1";
-  command = commandInDir.c_str();
-  const int BUFFER_SIZE = 4096;
-  char buffer[BUFFER_SIZE];
-  if(verbose)
+  argv.push_back(0);
+  
+  if(argv.size() < 2)
     {
-    std::cout << "running " << command << std::endl;
+    return false;
     }
-  fflush(stdout);
-  fflush(stderr);
-  FILE* cpipe = popen(command, "r");
-  if(!cpipe)
+  
+  // Change to specified working directory.
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+  if(dir)
     {
-    return false;
+    if(cmSystemTools::ChangeDirectory(dir) < 0)
+      {
+      return false;
+      }
     }
-  fgets(buffer, BUFFER_SIZE, cpipe);
-  while(!feof(cpipe))
+  
+  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 << buffer << std::flush;
+      std::cout.write(data, length);
       }
-    output += buffer;
-    fgets(buffer, BUFFER_SIZE, cpipe);
     }
-
-  retVal = pclose(cpipe);
-  if (WIFEXITED(retVal))
+  
+  cmsysProcess_WaitForExit(cp, 0);
+  
+  bool result = true;
+  if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
     {
-    retVal = WEXITSTATUS(retVal);
-    return true;
+    retVal = cmsysProcess_GetExitValue(cp);
     }
-  if (WIFSIGNALED(retVal))
+  else
     {
-    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();
+    result = false;
     }
-  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)
+  
+  cmsysProcess_Delete(cp);
+  
+  // Restore old working directory.
+  if(dir)
     {
-    verbose = false;
+    cmSystemTools::ChangeDirectory(cwd.c_str());
     }
   
-#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
+  return result;
 }
 
 bool cmSystemTools::DoesFileExistWithExtensions(