1/////////////////////////////////////////////////////////////////////////////// 2// Name: common/wxexec.cpp 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: 8// Created: 20.08.02 9// RCS-ID: $Id: execcmn.cpp 35289 2005-08-23 23:12:48Z VZ $ 10// Copyright: (c) 2002 Vadim Zeitlin <vadim@wxwindows.org> 11// Licence: wxWindows licence 12/////////////////////////////////////////////////////////////////////////////// 13 14#ifndef _WX_WXEXEC_CPP_ 15#define _WX_WXEXEC_CPP_ 16 17// this file should never be compiled directly, just included by other code 18#ifndef _WX_USED_BY_WXEXECUTE_ 19 #error "You should never directly build this file!" 20#endif 21 22// ---------------------------------------------------------------------------- 23// wxStreamTempInputBuffer 24// ---------------------------------------------------------------------------- 25 26/* 27 wxStreamTempInputBuffer is a hack which we need to solve the problem of 28 executing a child process synchronously with IO redirecting: when we do 29 this, the child writes to a pipe we open to it but when the pipe buffer 30 (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to 31 read data from it because the child blocks in its write() until then and if 32 it blocks we are never going to return from wxExecute() so we dead lock. 33 34 So here is the fix: we now read the output as soon as it appears into a temp 35 buffer (wxStreamTempInputBuffer object) and later just stuff it back into 36 the stream when the process terminates. See supporting code in wxExecute() 37 itself as well. 38 39 Note that this is horribly inefficient for large amounts of output (count 40 the number of times we copy the data around) and so a better API is badly 41 needed! However it's not easy to devise a way to do this keeping backwards 42 compatibility with the existing wxExecute(wxEXEC_SYNC)... 43*/ 44 45class wxStreamTempInputBuffer 46{ 47public: 48 wxStreamTempInputBuffer(); 49 50 // call to associate a stream with this buffer, otherwise nothing happens 51 // at all 52 void Init(wxPipeInputStream *stream); 53 54 // check for input on our stream and cache it in our buffer if any 55 void Update(); 56 57 ~wxStreamTempInputBuffer(); 58 59private: 60 // the stream we're buffering, if NULL we don't do anything at all 61 wxPipeInputStream *m_stream; 62 63 // the buffer of size m_size (NULL if m_size == 0) 64 void *m_buffer; 65 66 // the size of the buffer 67 size_t m_size; 68 69 DECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer) 70}; 71 72inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() 73{ 74 m_stream = NULL; 75 m_buffer = NULL; 76 m_size = 0; 77} 78 79inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) 80{ 81 m_stream = stream; 82} 83 84inline 85void wxStreamTempInputBuffer::Update() 86{ 87 if ( m_stream && m_stream->CanRead() ) 88 { 89 // realloc in blocks of 4Kb: this is the default (and minimal) buffer 90 // size of the Unix pipes so it should be the optimal step 91 // 92 // NB: don't use "static int" in this inline function, some compilers 93 // (e.g. IBM xlC) don't like it 94 enum { incSize = 4096 }; 95 96 void *buf = realloc(m_buffer, m_size + incSize); 97 if ( !buf ) 98 { 99 // don't read any more, we don't have enough memory to do it 100 m_stream = NULL; 101 } 102 else // got memory for the buffer 103 { 104 m_buffer = buf; 105 m_stream->Read((char *)m_buffer + m_size, incSize); 106 m_size += m_stream->LastRead(); 107 } 108 } 109} 110 111inline 112wxStreamTempInputBuffer::~wxStreamTempInputBuffer() 113{ 114 if ( m_buffer ) 115 { 116 m_stream->Ungetch(m_buffer, m_size); 117 free(m_buffer); 118 } 119} 120 121#endif // _WX_WXEXEC_CPP_ 122 123