+// ----------------------------------------------------------------------------
+// wxStreamTempBuffer
+// ----------------------------------------------------------------------------
+
+/*
+ Extract of a mail to wx-users to give the context of the problem we are
+ trying to solve here:
+
+ MC> If I run the command:
+ MC> find . -name "*.h" -exec grep linux {} \;
+ MC> in the exec sample synchronously from the 'Capture command output'
+ MC> menu, wxExecute never returns. I have to xkill it. Has anyone
+ MC> else encountered this?
+
+ Yes, I can reproduce it too.
+
+ I even think I understand why it happens: before launching the external
+ command we set up a pipe with a valid file descriptor on the reading side
+ when the output is redirected. So the subprocess happily writes to it ...
+ until the pipe buffer (which is usually quite big on Unix, I think the
+ default is 4Mb) is full. Then the writing process stops and waits until we
+ read some data from the pipe to be able to continue writing to it but we
+ never do it because we wait until it terminates to start reading and so we
+ have a classical deadlock.
+
+ Here is the fix: we now read the output as soon as it appears into a temp
+ buffer (wxStreamTempBuffer object) and later just stuff it back into the
+ stream when the process terminates. See supporting code in wxExecute()
+ itself as well.
+*/
+
+class wxStreamTempBuffer
+{
+public:
+ wxStreamTempBuffer();
+
+ // call to associate a stream with this buffer, otherwise nothing happens
+ // at all
+ void Init(wxInputStream *stream);
+
+ // check for input on our stream and cache it in our buffer if any
+ void Update();
+
+ ~wxStreamTempBuffer();
+
+private:
+ // the stream we're buffering, if NULL we don't do anything at all
+ wxInputStream *m_stream;
+
+ // the buffer of size m_size (NULL if m_size == 0)
+ void *m_buffer;
+
+ // the size of the buffer
+ size_t m_size;
+};
+
+wxStreamTempBuffer::wxStreamTempBuffer()
+{
+ m_stream = NULL;
+ m_buffer = NULL;
+ m_size = 0;
+}
+
+void wxStreamTempBuffer::Init(wxInputStream *stream)
+{
+ m_stream = stream;
+}
+
+void wxStreamTempBuffer::Update()
+{
+ if ( m_stream && !m_stream->Eof() )
+ {
+ // realloc in blocks of 1Kb - surely not the best strategy but which
+ // one is?
+ static const size_t incSize = 1024;
+
+ void *buf = realloc(m_buffer, m_size + incSize);
+ if ( !buf )
+ {
+ // don't read any more, we don't have enough memory to do it
+ m_stream = NULL;
+ }
+ else // got memory for the buffer
+ {
+ m_buffer = buf;
+ m_stream->Read((char *)m_buffer + m_size, incSize);
+ m_size += incSize;
+ }
+ }
+}
+
+wxStreamTempBuffer::~wxStreamTempBuffer()
+{
+ if ( m_buffer )
+ {
+ m_stream->Ungetch(m_buffer, m_size);
+ free(m_buffer);
+ }
+}
+
+#endif // wxUSE_STREAMS
+