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