| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file Copyright.txt or https://cmake.org/licensing for details.  */#include "cmExecProgramCommand.h"#include "cmsys/Process.h"#include <stdio.h>#include "cmMakefile.h"#include "cmProcessOutput.h"#include "cmSystemTools.h"class cmExecutionStatus;// cmExecProgramCommandbool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,                                       cmExecutionStatus&){  if (args.empty()) {    this->SetError("called with incorrect number of arguments");    return false;  }  std::string arguments;  bool doingargs = false;  int count = 0;  std::string output_variable;  bool haveoutput_variable = false;  std::string return_variable;  bool havereturn_variable = false;  for (std::string const& arg : args) {    if (arg == "OUTPUT_VARIABLE") {      count++;      doingargs = false;      havereturn_variable = false;      haveoutput_variable = true;    } else if (haveoutput_variable) {      if (!output_variable.empty()) {        this->SetError("called with incorrect number of arguments");        return false;      }      output_variable = arg;      haveoutput_variable = false;      count++;    } else if (arg == "RETURN_VALUE") {      count++;      doingargs = false;      haveoutput_variable = false;      havereturn_variable = true;    } else if (havereturn_variable) {      if (!return_variable.empty()) {        this->SetError("called with incorrect number of arguments");        return false;      }      return_variable = arg;      havereturn_variable = false;      count++;    } else if (arg == "ARGS") {      count++;      havereturn_variable = false;      haveoutput_variable = false;      doingargs = true;    } else if (doingargs) {      arguments += arg;      arguments += " ";      count++;    }  }  std::string command;  if (!arguments.empty()) {    command = cmSystemTools::ConvertToRunCommandPath(args[0]);    command += " ";    command += arguments;  } else {    command = args[0];  }  bool verbose = true;  if (!output_variable.empty()) {    verbose = false;  }  int retVal = 0;  std::string output;  bool result = true;  if (args.size() - count == 2) {    cmSystemTools::MakeDirectory(args[1]);    result = cmExecProgramCommand::RunCommand(command, output, retVal,                                              args[1].c_str(), verbose);  } else {    result = cmExecProgramCommand::RunCommand(command, output, retVal, nullptr,                                              verbose);  }  if (!result) {    retVal = -1;  }  if (!output_variable.empty()) {    std::string::size_type first = output.find_first_not_of(" \n\t\r");    std::string::size_type last = output.find_last_not_of(" \n\t\r");    if (first == std::string::npos) {      first = 0;    }    if (last == std::string::npos) {      last = output.size() - 1;    }    std::string coutput = std::string(output, first, last - first + 1);    this->Makefile->AddDefinition(output_variable, coutput);  }  if (!return_variable.empty()) {    char buffer[100];    sprintf(buffer, "%d", retVal);    this->Makefile->AddDefinition(return_variable, buffer);  }  return true;}bool cmExecProgramCommand::RunCommand(std::string command, std::string& output,                                      int& retVal, const char* dir,                                      bool verbose, Encoding encoding){  if (cmSystemTools::GetRunCommandOutput()) {    verbose = false;  }#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  if (!command.empty() && command[0] == '\"') {    // count the number of quotes    int count = 0;    for (char c : command) {      if (c == '\"') {        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)) {          shortCmd = cmd;        } else if (!cmSystemTools::GetShortPath(cmd, shortCmd)) {          cmSystemTools::Error("GetShortPath failed for " + cmd);          return false;        }        shortCmd += " ";        shortCmd += args;        command = shortCmd;      } else {        cmSystemTools::Error("Could not parse command line with quotes " +                             command);      }    }  }#endif  // Allocate a process instance.  cmsysProcess* cp = cmsysProcess_New();  if (!cp) {    cmSystemTools::Error("Error allocating process instance.");    return false;  }#if defined(_WIN32) && !defined(__CYGWIN__)  if (dir) {    cmsysProcess_SetWorkingDirectory(cp, dir);  }  if (cmSystemTools::GetRunCommandHideConsole()) {    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);  }  cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);  const char* cmd[] = { command.c_str(), nullptr };  cmsysProcess_SetCommand(cp, cmd);#else  std::string commandInDir;  if (dir) {    commandInDir = "cd \"";    commandInDir += dir;    commandInDir += "\" && ";    commandInDir += command;  } else {    commandInDir = command;  }#  ifndef __VMS  commandInDir += " 2>&1";#  endif  command = commandInDir;  if (verbose) {    cmSystemTools::Stdout("running ");    cmSystemTools::Stdout(command);    cmSystemTools::Stdout("\n");  }  fflush(stdout);  fflush(stderr);  const char* cmd[] = { "/bin/sh", "-c", command.c_str(), nullptr };  cmsysProcess_SetCommand(cp, cmd);#endif  cmsysProcess_Execute(cp);  // Read the process output.  int length;  char* data;  int p;  cmProcessOutput processOutput(encoding);  std::string strdata;  while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {    if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {      if (verbose) {        processOutput.DecodeText(data, length, strdata);        cmSystemTools::Stdout(strdata);      }      output.append(data, length);    }  }  if (verbose) {    processOutput.DecodeText(std::string(), strdata);    if (!strdata.empty()) {      cmSystemTools::Stdout(strdata);    }  }  // All output has been read.  Wait for the process to exit.  cmsysProcess_WaitForExit(cp, nullptr);  processOutput.DecodeText(output, output);  // Check the result of running the process.  std::string msg;  switch (cmsysProcess_GetState(cp)) {    case cmsysProcess_State_Exited:      retVal = cmsysProcess_GetExitValue(cp);      break;    case cmsysProcess_State_Exception:      retVal = -1;      msg += "\nProcess terminated due to: ";      msg += cmsysProcess_GetExceptionString(cp);      break;    case cmsysProcess_State_Error:      retVal = -1;      msg += "\nProcess failed because: ";      msg += cmsysProcess_GetErrorString(cp);      break;    case cmsysProcess_State_Expired:      retVal = -1;      msg += "\nProcess terminated due to timeout.";      break;  }  if (!msg.empty()) {#if defined(_WIN32) && !defined(__CYGWIN__)    // Old Windows process execution printed this info.    msg += "\n\nfor command: ";    msg += command;    if (dir) {      msg += "\nin dir: ";      msg += dir;    }    msg += "\n";    if (verbose) {      cmSystemTools::Stdout(msg);    }    output += msg;#else    // Old UNIX process execution only put message in output.    output += msg;#endif  }  // Delete the process instance.  cmsysProcess_Delete(cp);  return true;}
 |