AESubprocess.cpp 3.2 KB

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