Subprocess.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #include <Atomic/IO/Log.h>
  5. #include <Atomic/Core/Timer.h>
  6. #include "Subprocess.h"
  7. #include "SubprocessSystem.h"
  8. namespace ToolCore
  9. {
  10. Subprocess::Subprocess(Context* context) :
  11. Object(context),
  12. handle_(NULL),
  13. inStream_(pipeOut_),
  14. errorStream_(pipeError_),
  15. returnCode_(-1)
  16. {
  17. }
  18. Subprocess::~Subprocess()
  19. {
  20. if (handle_)
  21. delete handle_;
  22. }
  23. void Subprocess::ThreadFunction()
  24. {
  25. while (shouldRun_)
  26. {
  27. int read;
  28. char data[129];
  29. if (!Poco::Process::isRunning(*handle_))
  30. {
  31. shouldRun_ = false;
  32. break;
  33. }
  34. inStream_.read(data, 128);
  35. read = inStream_.gcount();
  36. data[read] = 0;
  37. if (read)
  38. {
  39. mutex_.Acquire();
  40. output_ += (const char*) data;
  41. mutex_.Release();
  42. }
  43. if (inStream_.eof())
  44. {
  45. returnCode_ = handle_->wait();
  46. if (returnCode_)
  47. {
  48. while (true)
  49. {
  50. errorStream_.read(data, 128);
  51. read = errorStream_.gcount();
  52. data[read] = 0;
  53. if (read)
  54. {
  55. mutex_.Acquire();
  56. errorOutput_ += (const char*) data;
  57. mutex_.Release();
  58. }
  59. else
  60. {
  61. break;
  62. }
  63. }
  64. }
  65. shouldRun_ = false;
  66. break;
  67. }
  68. }
  69. }
  70. void Subprocess::ProcessOutput(SubprocessSystem* system)
  71. {
  72. String output, errorOutput;
  73. GetOutput(output, errorOutput);
  74. if (output.Length())
  75. {
  76. VariantMap eventData;
  77. eventData[SubprocessOutput::P_TEXT] = output;
  78. SendEvent(E_SUBPROCESSOUTPUT, eventData);
  79. }
  80. if (errorOutput.Length())
  81. {
  82. VariantMap eventData;
  83. eventData[SubprocessOutput::P_TEXT] = errorOutput;
  84. SendEvent(E_SUBPROCESSOUTPUT, eventData);
  85. }
  86. }
  87. bool Subprocess::Update(SubprocessSystem* system)
  88. {
  89. ProcessOutput(system);
  90. if (!shouldRun_) {
  91. ProcessOutput(system);
  92. VariantMap eventData;
  93. eventData[SubprocessComplete::P_RETCODE] = returnCode_;
  94. SendEvent(E_SUBPROCESSCOMPLETE, eventData);
  95. return false;
  96. }
  97. return true;
  98. }
  99. bool Subprocess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
  100. {
  101. Poco::Process::Env env;
  102. return Launch(command, args, initialDirectory, env);
  103. }
  104. bool Subprocess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory, const Poco::Process::Env& env)
  105. {
  106. Poco::Process::Args pargs;
  107. for (unsigned i = 0; i < args.Size(); i++)
  108. pargs.push_back(args[i].CString());
  109. std::string pcommand = command.CString();
  110. std::string pinitialDirectory = initialDirectory.CString();
  111. // this can take an ENV as well, may come in useful
  112. handle_ = new Poco::ProcessHandle(Poco::Process::launch(pcommand, pargs, pinitialDirectory, &pipeIn_, &pipeOut_, &pipeError_, env));
  113. if (!Poco::Process::isRunning(*handle_))
  114. return false;
  115. return Run();
  116. }
  117. }