streamtempinput.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: wx/private/streamtempinput.h
  3. // Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW
  4. // implementations of wxExecute; this file is only used by the
  5. // library and never by the user code
  6. // Author: Vadim Zeitlin
  7. // Modified by: Rob Bresalier
  8. // Created: 2013-05-04
  9. // Copyright: (c) 2002 Vadim Zeitlin <vadim@wxwindows.org>
  10. // Licence: wxWindows licence
  11. ///////////////////////////////////////////////////////////////////////////////
  12. #ifndef _WX_PRIVATE_STREAMTEMPINPUT_H
  13. #define _WX_PRIVATE_STREAMTEMPINPUT_H
  14. #include "wx/private/pipestream.h"
  15. // ----------------------------------------------------------------------------
  16. // wxStreamTempInputBuffer
  17. // ----------------------------------------------------------------------------
  18. /*
  19. wxStreamTempInputBuffer is a hack which we need to solve the problem of
  20. executing a child process synchronously with IO redirecting: when we do
  21. this, the child writes to a pipe we open to it but when the pipe buffer
  22. (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to
  23. read data from it because the child blocks in its write() until then and if
  24. it blocks we are never going to return from wxExecute() so we dead lock.
  25. So here is the fix: we now read the output as soon as it appears into a temp
  26. buffer (wxStreamTempInputBuffer object) and later just stuff it back into
  27. the stream when the process terminates. See supporting code in wxExecute()
  28. itself as well.
  29. Note that this is horribly inefficient for large amounts of output (count
  30. the number of times we copy the data around) and so a better API is badly
  31. needed! However it's not easy to devise a way to do this keeping backwards
  32. compatibility with the existing wxExecute(wxEXEC_SYNC)...
  33. */
  34. class wxStreamTempInputBuffer
  35. {
  36. public:
  37. wxStreamTempInputBuffer()
  38. {
  39. m_stream = NULL;
  40. m_buffer = NULL;
  41. m_size = 0;
  42. }
  43. // call to associate a stream with this buffer, otherwise nothing happens
  44. // at all
  45. void Init(wxPipeInputStream *stream)
  46. {
  47. wxASSERT_MSG( !m_stream, wxS("Can only initialize once") );
  48. m_stream = stream;
  49. }
  50. // check for input on our stream and cache it in our buffer if any
  51. //
  52. // return true if anything was done
  53. bool Update()
  54. {
  55. if ( !m_stream || !m_stream->CanRead() )
  56. return false;
  57. // realloc in blocks of 4Kb: this is the default (and minimal) buffer
  58. // size of the Unix pipes so it should be the optimal step
  59. //
  60. // NB: don't use "static int" in this inline function, some compilers
  61. // (e.g. IBM xlC) don't like it
  62. enum { incSize = 4096 };
  63. void *buf = realloc(m_buffer, m_size + incSize);
  64. if ( !buf )
  65. return false;
  66. m_buffer = buf;
  67. m_stream->Read((char *)m_buffer + m_size, incSize);
  68. m_size += m_stream->LastRead();
  69. return true;
  70. }
  71. // check if can continue reading from the stream, this is used to disable
  72. // the callback once we can't read anything more
  73. bool Eof() const
  74. {
  75. // If we have no stream, always return true as we can't read any more.
  76. return !m_stream || m_stream->Eof();
  77. }
  78. // read everything remaining until the EOF, this should only be called once
  79. // the child process terminates and we know that no more data is coming
  80. bool ReadAll()
  81. {
  82. while ( !Eof() )
  83. {
  84. if ( !Update() )
  85. return false;
  86. }
  87. return true;
  88. }
  89. // dtor puts the data buffered during this object lifetime into the
  90. // associated stream
  91. ~wxStreamTempInputBuffer()
  92. {
  93. if ( m_buffer )
  94. {
  95. m_stream->Ungetch(m_buffer, m_size);
  96. free(m_buffer);
  97. }
  98. }
  99. const void *GetBuffer() const { return m_buffer; }
  100. size_t GetSize() const { return m_size; }
  101. private:
  102. // the stream we're buffering, if NULL we don't do anything at all
  103. wxPipeInputStream *m_stream;
  104. // the buffer of size m_size (NULL if m_size == 0)
  105. void *m_buffer;
  106. // the size of the buffer
  107. size_t m_size;
  108. wxDECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer);
  109. };
  110. #endif // _WX_PRIVATE_STREAMTEMPINPUT_H