| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- ///////////////////////////////////////////////////////////////////////////////
- // Name: wx/private/streamtempinput.h
- // Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW
- // implementations of wxExecute; this file is only used by the
- // library and never by the user code
- // Author: Vadim Zeitlin
- // Modified by: Rob Bresalier
- // Created: 2013-05-04
- // Copyright: (c) 2002 Vadim Zeitlin <vadim@wxwindows.org>
- // Licence: wxWindows licence
- ///////////////////////////////////////////////////////////////////////////////
- #ifndef _WX_PRIVATE_STREAMTEMPINPUT_H
- #define _WX_PRIVATE_STREAMTEMPINPUT_H
- #include "wx/private/pipestream.h"
- // ----------------------------------------------------------------------------
- // wxStreamTempInputBuffer
- // ----------------------------------------------------------------------------
- /*
- wxStreamTempInputBuffer is a hack which we need to solve the problem of
- executing a child process synchronously with IO redirecting: when we do
- this, the child writes to a pipe we open to it but when the pipe buffer
- (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to
- read data from it because the child blocks in its write() until then and if
- it blocks we are never going to return from wxExecute() so we dead lock.
- So here is the fix: we now read the output as soon as it appears into a temp
- buffer (wxStreamTempInputBuffer object) and later just stuff it back into
- the stream when the process terminates. See supporting code in wxExecute()
- itself as well.
- Note that this is horribly inefficient for large amounts of output (count
- the number of times we copy the data around) and so a better API is badly
- needed! However it's not easy to devise a way to do this keeping backwards
- compatibility with the existing wxExecute(wxEXEC_SYNC)...
- */
- class wxStreamTempInputBuffer
- {
- public:
- wxStreamTempInputBuffer()
- {
- m_stream = NULL;
- m_buffer = NULL;
- m_size = 0;
- }
- // call to associate a stream with this buffer, otherwise nothing happens
- // at all
- void Init(wxPipeInputStream *stream)
- {
- wxASSERT_MSG( !m_stream, wxS("Can only initialize once") );
- m_stream = stream;
- }
- // check for input on our stream and cache it in our buffer if any
- //
- // return true if anything was done
- bool Update()
- {
- if ( !m_stream || !m_stream->CanRead() )
- return false;
- // realloc in blocks of 4Kb: this is the default (and minimal) buffer
- // size of the Unix pipes so it should be the optimal step
- //
- // NB: don't use "static int" in this inline function, some compilers
- // (e.g. IBM xlC) don't like it
- enum { incSize = 4096 };
- void *buf = realloc(m_buffer, m_size + incSize);
- if ( !buf )
- return false;
- m_buffer = buf;
- m_stream->Read((char *)m_buffer + m_size, incSize);
- m_size += m_stream->LastRead();
- return true;
- }
- // check if can continue reading from the stream, this is used to disable
- // the callback once we can't read anything more
- bool Eof() const
- {
- // If we have no stream, always return true as we can't read any more.
- return !m_stream || m_stream->Eof();
- }
- // read everything remaining until the EOF, this should only be called once
- // the child process terminates and we know that no more data is coming
- bool ReadAll()
- {
- while ( !Eof() )
- {
- if ( !Update() )
- return false;
- }
- return true;
- }
- // dtor puts the data buffered during this object lifetime into the
- // associated stream
- ~wxStreamTempInputBuffer()
- {
- if ( m_buffer )
- {
- m_stream->Ungetch(m_buffer, m_size);
- free(m_buffer);
- }
- }
- const void *GetBuffer() const { return m_buffer; }
- size_t GetSize() const { return m_size; }
- private:
- // the stream we're buffering, if NULL we don't do anything at all
- wxPipeInputStream *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;
- wxDECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer);
- };
- #endif // _WX_PRIVATE_STREAMTEMPINPUT_H
|