processutils.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "processutils.h"
  2. #include <QProcess>
  3. #include <QScopedPointer>
  4. #include <QDebug>
  5. #include "utils.h"
  6. using namespace vnotex;
  7. ProcessUtils::State ProcessUtils::start(const QString &p_program,
  8. const QStringList &p_args,
  9. const QByteArray &p_stdIn,
  10. int &p_exitCodeOnSuccess,
  11. QByteArray &p_stdOut,
  12. QByteArray &p_stdErr)
  13. {
  14. QScopedPointer<QProcess> proc(new QProcess());
  15. proc->start(p_program, p_args);
  16. return handleProcess(proc.data(), p_stdIn, p_exitCodeOnSuccess, p_stdOut, p_stdErr);
  17. }
  18. ProcessUtils::State ProcessUtils::handleProcess(QProcess *p_process,
  19. const QByteArray &p_stdIn,
  20. int &p_exitCodeOnSuccess,
  21. QByteArray &p_stdOut,
  22. QByteArray &p_stdErr)
  23. {
  24. if (!p_process->waitForStarted()) {
  25. return State::FailedToStart;
  26. }
  27. if (!p_stdIn.isEmpty()) {
  28. if (p_process->write(p_stdIn) == -1) {
  29. p_process->closeWriteChannel();
  30. qWarning() << "failed to write to stdin of QProcess" << p_process->errorString();
  31. return State::FailedToWrite;
  32. } else {
  33. p_process->closeWriteChannel();
  34. }
  35. }
  36. p_process->waitForFinished();
  37. State state = State::Succeeded;
  38. if (p_process->exitStatus() == QProcess::CrashExit) {
  39. state = State::Crashed;
  40. } else {
  41. p_exitCodeOnSuccess = p_process->exitCode();
  42. }
  43. p_stdOut = p_process->readAllStandardOutput();
  44. p_stdErr = p_process->readAllStandardError();
  45. return state;
  46. }
  47. QStringList ProcessUtils::parseCombinedArgString(const QString &p_args)
  48. {
  49. QStringList args;
  50. QString tmp;
  51. int quoteCount = 0;
  52. bool inQuote = false;
  53. // Handle quoting.
  54. // Tokens can be surrounded by double quotes "hello world".
  55. // Three consecutive double quotes represent the quote character itself.
  56. for (int i = 0; i < p_args.size(); ++i) {
  57. if (p_args.at(i) == QLatin1Char('"')) {
  58. ++quoteCount;
  59. if (quoteCount == 3) {
  60. // Third consecutive quote.
  61. quoteCount = 0;
  62. tmp += p_args.at(i);
  63. }
  64. continue;
  65. }
  66. if (quoteCount) {
  67. if (quoteCount == 1) {
  68. inQuote = !inQuote;
  69. }
  70. quoteCount = 0;
  71. }
  72. if (!inQuote && p_args.at(i).isSpace()) {
  73. if (!tmp.isEmpty()) {
  74. args += tmp;
  75. tmp.clear();
  76. }
  77. } else {
  78. tmp += p_args.at(i);
  79. }
  80. }
  81. if (!tmp.isEmpty()) {
  82. args += tmp;
  83. }
  84. return args;
  85. }
  86. QString ProcessUtils::combineArgString(const QStringList &p_args)
  87. {
  88. QString argStr;
  89. for (const auto &arg : p_args) {
  90. QString tmp(arg);
  91. tmp.replace("\"", "\"\"\"");
  92. if (tmp.contains(' ')) {
  93. tmp = '"' + tmp + '"';
  94. }
  95. if (argStr.isEmpty()) {
  96. argStr = tmp;
  97. } else {
  98. argStr = argStr + ' ' + tmp;
  99. }
  100. }
  101. return argStr;
  102. }
  103. ProcessUtils::State ProcessUtils::start(const QString &p_program,
  104. const QStringList &p_args,
  105. const std::function<void(const QString &)> &p_logger,
  106. const bool &p_askedToStop)
  107. {
  108. QProcess proc;
  109. proc.start(p_program, p_args);
  110. if (!proc.waitForStarted()) {
  111. return State::FailedToStart;
  112. }
  113. while (proc.state() != QProcess::NotRunning) {
  114. Utils::sleepWait(100);
  115. auto outBa = proc.readAllStandardOutput();
  116. auto errBa = proc.readAllStandardError();
  117. QString msg;
  118. if (!outBa.isEmpty()) {
  119. msg += QString::fromLocal8Bit(outBa);
  120. }
  121. if (!errBa.isEmpty()) {
  122. msg += QString::fromLocal8Bit(errBa);
  123. }
  124. if (!msg.isEmpty()) {
  125. p_logger(msg);
  126. }
  127. if (p_askedToStop) {
  128. break;
  129. }
  130. }
  131. return proc.exitStatus() == QProcess::NormalExit ? State::Succeeded : State::Crashed;
  132. }