1 |
william |
31 |
/////////////////////////////////////////////////////////////////////////////// |
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 |
|
|
|
45 |
|
|
class wxStreamTempInputBuffer |
46 |
|
|
{ |
47 |
|
|
public: |
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 |
|
|
|
59 |
|
|
private: |
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 |
|
|
|
72 |
|
|
inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() |
73 |
|
|
{ |
74 |
|
|
m_stream = NULL; |
75 |
|
|
m_buffer = NULL; |
76 |
|
|
m_size = 0; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) |
80 |
|
|
{ |
81 |
|
|
m_stream = stream; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
inline |
85 |
|
|
void 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 |
|
|
|
111 |
|
|
inline |
112 |
|
|
wxStreamTempInputBuffer::~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 |
|
|
|