fixes for wxExecute() with IO redirection: wxStreamTempInputBuffer is now used under MSW as well

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16638 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-08-20 22:32:40 +00:00
parent db59a97cda
commit 7906613173
4 changed files with 421 additions and 261 deletions

View File

@@ -227,6 +227,7 @@ All (GUI):
wxMSW:
- small appearance fixes for native look under Windows XP
- fixed multiple bugs in wxExecute() with IO redirection
- refresh the buttons properly when the window is resized (Hans Van Leemputten)
- huge (40*) speed up in wxMask::Create()
- changing wxWindows styles also changes the underlying Windows window style
@@ -256,12 +257,9 @@ wxMSW:
- multiple events avoided in wxComboBox
- tooltip asserts avoided for read-only wxComboBox
- fixed a race condition during a thread exit and a join
- fixed a condition where a thread can hang during
message/event processing
- fixed a condition where a thread can hang during message/event processing
- increased space between wxRadioBox label and first radio button
- don't fail to register remaining window classes if one fails to register
- set window proc for non-control windows to avoid problems
with multiple wxWindows apps running simultaneously
wxGTK:

134
src/common/execcmn.cpp Normal file
View File

@@ -0,0 +1,134 @@
///////////////////////////////////////////////////////////////////////////////
// Name: common/wxexec.cpp
// 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:
// Created: 20.08.02
// RCS-ID: $Id$
// Copyright: (c) 2002 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_WXEXEC_CPP_
#define _WX_WXEXEC_CPP_
// this file should never be compiled directly, just included by other code
#ifndef _WX_USED_BY_WXEXECUTE_
#error "Please don't exclude this file from build!"
#endif
// ----------------------------------------------------------------------------
// 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();
// call to associate a stream with this buffer, otherwise nothing happens
// at all
void Init(wxPipeInputStream *stream);
// check for input on our stream and cache it in our buffer if any
void Update();
~wxStreamTempInputBuffer();
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;
};
inline wxStreamTempInputBuffer::wxStreamTempInputBuffer()
{
m_stream = NULL;
m_buffer = NULL;
m_size = 0;
}
inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream)
{
m_stream = stream;
}
void wxStreamTempInputBuffer::Update()
{
if ( m_stream && m_stream->IsAvailable() )
{
// realloc in blocks of 4Kb: this is the default (and minimal) buffer
// size of the Unix pipes so it should be the optimal step
static const size_t incSize = 4096;
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 += m_stream->LastRead();
}
}
}
wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
{
if ( m_buffer )
{
m_stream->Ungetch(m_buffer, m_size);
free(m_buffer);
}
}
// ----------------------------------------------------------------------------
// platform-dependent parts of wxProcess implementation included
// ----------------------------------------------------------------------------
bool wxProcess::IsInputOpened() const
{
return m_inputStream && ((wxPipeInputStream *)m_inputStream)->IsOpened();
}
bool wxProcess::IsInputAvailable() const
{
return m_inputStream && ((wxPipeInputStream *)m_inputStream)->IsAvailable();
}
bool wxProcess::IsErrorAvailable() const
{
return m_errorStream && ((wxPipeInputStream *)m_errorStream)->IsAvailable();
}
#endif // _WX_WXEXEC_CPP_

View File

@@ -1,11 +1,11 @@
/////////////////////////////////////////////////////////////////////////////
// Name: msw/utilsexec.cpp
// Purpose: Various utilities
// Purpose: wxExecute implementation for MSW
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Julian Smart and Markus Holzem
// Copyright: (c) 1998-2002 wxWindows dev team
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
@@ -131,9 +131,13 @@ class wxPipeInputStream: public wxInputStream
{
public:
wxPipeInputStream(HANDLE hInput);
~wxPipeInputStream();
virtual ~wxPipeInputStream();
virtual bool Eof() const;
// returns TRUE if the pipe is still opened
bool IsOpened() const { return m_hInput != INVALID_HANDLE_VALUE; }
// returns TRUE if there is any data to be read from the pipe
bool IsAvailable() const;
protected:
size_t OnSysRead(void *buffer, size_t len);
@@ -146,7 +150,7 @@ class wxPipeOutputStream: public wxOutputStream
{
public:
wxPipeOutputStream(HANDLE hOutput);
~wxPipeOutputStream();
virtual ~wxPipeOutputStream();
protected:
size_t OnSysWrite(const void *buffer, size_t len);
@@ -155,103 +159,93 @@ protected:
HANDLE m_hOutput;
};
// ==================
// wxPipeInputStream
// ==================
// define this to let wxexec.cpp know that we know what we're doing
#define _WX_USED_BY_WXEXECUTE_
#include "../common/execcmn.cpp"
wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
// ----------------------------------------------------------------------------
// wxPipe represents a Win32 anonymous pipe
// ----------------------------------------------------------------------------
class wxPipe
{
m_hInput = hInput;
public:
// the symbolic names for the pipe ends
enum Direction
{
Read,
Write
};
// default ctor doesn't do anything
wxPipe() { m_handles[Read] = m_handles[Write] = INVALID_HANDLE_VALUE; }
// create the pipe, return TRUE if ok, FALSE on error
bool Create()
{
// default secutiry attributes
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(security);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = TRUE; // to pass it to the child
if ( !::CreatePipe(&m_handles[0], &m_handles[1], &security, 0) )
{
wxLogSysError(_("Failed to create an anonymous pipe"));
return FALSE;
}
wxPipeInputStream::~wxPipeInputStream()
{
::CloseHandle(m_hInput);
}
bool wxPipeInputStream::Eof() const
{
DWORD nAvailable;
// function name is misleading, it works with anon pipes as well
DWORD rc = ::PeekNamedPipe
(
m_hInput, // handle
NULL, 0, // ptr to buffer and its size
NULL, // [out] bytes read
&nAvailable, // [out] bytes available
NULL // [out] bytes left
);
if ( !rc )
{
if ( ::GetLastError() != ERROR_BROKEN_PIPE )
{
// unexpected error
wxLogLastError(_T("PeekNamedPipe"));
}
// don't try to continue reading from a pipe if an error occured or if
// it had been closed
return TRUE;
}
else
// return TRUE if we were created successfully
bool IsOk() const { return m_handles[Read] != INVALID_HANDLE_VALUE; }
// return the descriptor for one of the pipe ends
HANDLE operator[](Direction which) const
{
return nAvailable == 0;
}
wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_handles),
_T("invalid pipe index") );
return m_handles[which];
}
size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
// detach a descriptor, meaning that the pipe dtor won't close it, and
// return it
HANDLE Detach(Direction which)
{
// reading from a pipe may block if there is no more data, always check for
// EOF first
m_lasterror = wxSTREAM_NOERROR;
if ( Eof() )
return 0;
wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_handles),
_T("invalid pipe index") );
DWORD bytesRead;
if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
HANDLE handle = m_handles[which];
m_handles[which] = INVALID_HANDLE_VALUE;
return handle;
}
// close the pipe descriptors
void Close()
{
if ( ::GetLastError() == ERROR_BROKEN_PIPE )
m_lasterror = wxSTREAM_EOF;
else
m_lasterror = wxSTREAM_READ_ERROR;
}
return bytesRead;
}
// ==================
// wxPipeOutputStream
// ==================
wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
for ( size_t n = 0; n < WXSIZEOF(m_handles); n++ )
{
m_hOutput = hOutput;
}
wxPipeOutputStream::~wxPipeOutputStream()
if ( m_handles[n] != INVALID_HANDLE_VALUE )
{
::CloseHandle(m_hOutput);
::CloseHandle(m_handles[n]);
m_handles[n] = INVALID_HANDLE_VALUE;
}
}
}
size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
{
DWORD bytesRead;
// dtor closes the pipe descriptors
~wxPipe() { Close(); }
m_lasterror = wxSTREAM_NOERROR;
if ( !::WriteFile(m_hOutput, buffer, len, &bytesRead, NULL) )
{
if ( ::GetLastError() == ERROR_BROKEN_PIPE )
m_lasterror = wxSTREAM_EOF;
else
m_lasterror = wxSTREAM_READ_ERROR;
}
private:
HANDLE m_handles[2];
};
return bytesRead;
}
#endif // __WIN32__
#endif // wxUSE_STREAMS
// ============================================================================
// implementation
@@ -259,14 +253,22 @@ size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
#ifdef __WIN32__
// ----------------------------------------------------------------------------
// process termination detecting support
// ----------------------------------------------------------------------------
// thread function for the thread monitoring the process termination
static DWORD __stdcall wxExecuteThread(void *arg)
{
wxExecuteData *data = (wxExecuteData*)arg;
WaitForSingleObject(data->hProcess, INFINITE);
if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 )
{
wxLogDebug(_T("Waiting for the process termination failed!"));
}
// get the exit code
if ( !GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
if ( !::GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
{
wxLogLastError(wxT("GetExitCodeProcess"));
}
@@ -275,7 +277,7 @@ static DWORD __stdcall wxExecuteThread(void *arg)
wxT("process should have terminated") );
// send a message indicating process termination to the window
SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
::SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
return 0;
}
@@ -315,8 +317,128 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
// ============================================================================
// implementation of IO redirection support classes
// ============================================================================
#if wxUSE_STREAMS
// ----------------------------------------------------------------------------
// wxPipeInputStreams
// ----------------------------------------------------------------------------
wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
{
m_hInput = hInput;
}
wxPipeInputStream::~wxPipeInputStream()
{
if ( m_hInput != INVALID_HANDLE_VALUE )
::CloseHandle(m_hInput);
}
bool wxPipeInputStream::IsAvailable() const
{
if ( !IsOpened() )
return FALSE;
DWORD nAvailable;
// function name is misleading, it works with anon pipes as well
DWORD rc = ::PeekNamedPipe
(
m_hInput, // handle
NULL, 0, // ptr to buffer and its size
NULL, // [out] bytes read
&nAvailable, // [out] bytes available
NULL // [out] bytes left
);
if ( !rc )
{
if ( ::GetLastError() != ERROR_BROKEN_PIPE )
{
// unexpected error
wxLogLastError(_T("PeekNamedPipe"));
}
// don't try to continue reading from a pipe if an error occured or if
// it had been closed
::CloseHandle(m_hInput);
wxConstCast(this, wxPipeInputStream)->m_hInput = INVALID_HANDLE_VALUE;
return FALSE;
}
return nAvailable != 0;
}
size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
{
// reading from a pipe may block if there is no more data, always check for
// EOF first
if ( !IsAvailable() )
{
m_lasterror = wxSTREAM_EOF;
return 0;
}
m_lasterror = wxSTREAM_NOERROR;
DWORD bytesRead;
if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
{
if ( ::GetLastError() == ERROR_BROKEN_PIPE )
m_lasterror = wxSTREAM_EOF;
else
m_lasterror = wxSTREAM_READ_ERROR;
}
return bytesRead;
}
// ----------------------------------------------------------------------------
// wxPipeOutputStream
// ----------------------------------------------------------------------------
wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
{
m_hOutput = hOutput;
}
wxPipeOutputStream::~wxPipeOutputStream()
{
::CloseHandle(m_hOutput);
}
size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
{
DWORD bytesRead;
m_lasterror = wxSTREAM_NOERROR;
if ( !::WriteFile(m_hOutput, buffer, len, &bytesRead, NULL) )
{
if ( ::GetLastError() == ERROR_BROKEN_PIPE )
m_lasterror = wxSTREAM_EOF;
else
m_lasterror = wxSTREAM_READ_ERROR;
}
return bytesRead;
}
#endif // wxUSE_STREAMS
#endif // Win32
// ============================================================================
// wxExecute functions family
// ============================================================================
#if wxUSE_IPC
// connect to the given server via DDE and ask it to execute the command
@@ -462,46 +584,26 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
// the IO redirection is only supported with wxUSE_STREAMS
BOOL redirect = FALSE;
#if wxUSE_STREAMS
// the first elements are reading ends, the second are the writing ones
HANDLE hpipeStdin[2],
hpipeStdout[2],
hpipeStderr[2];
wxPipe pipeIn, pipeOut, pipeErr;
// we'll save here the copy of pipeIn[Write]
HANDLE hpipeStdinWrite = INVALID_HANDLE_VALUE;
// open the pipes to which child process IO will be redirected if needed
if ( handler && handler->IsRedirected() )
{
// default secutiry attributes
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(security);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = TRUE;
// create stdin pipe
if ( !::CreatePipe(&hpipeStdin[0], &hpipeStdin[1], &security, 0) )
// create pipes for redirecting stdin, stdout and stderr
if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
{
wxLogSysError(_("Can't create the inter-process read pipe"));
wxLogSysError(_("Failed to redirect the child process IO"));
// indicate failure: we need to return different error code
// depending on the sync flag
return flags & wxEXEC_SYNC ? -1 : 0;
}
// and a stdout one
if ( !::CreatePipe(&hpipeStdout[0], &hpipeStdout[1], &security, 0) )
{
::CloseHandle(hpipeStdin[0]);
::CloseHandle(hpipeStdin[1]);
wxLogSysError(_("Can't create the inter-process write pipe"));
return flags & wxEXEC_SYNC ? -1 : 0;
}
(void)::CreatePipe(&hpipeStderr[0], &hpipeStderr[1], &security, 0);
redirect = TRUE;
}
#endif // wxUSE_STREAMS
@@ -516,9 +618,9 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
{
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hpipeStdin[0];
si.hStdOutput = hpipeStdout[1];
si.hStdError = hpipeStderr[1];
si.hStdInput = pipeIn[wxPipe::Read];
si.hStdOutput = pipeOut[wxPipe::Write];
si.hStdError = pipeErr[wxPipe::Write];
// when the std IO is redirected, we don't show the (console) process
// window by default, but this can be overridden by the caller by
@@ -530,15 +632,16 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
}
// we must duplicate the handle to the write side of stdin pipe to make
// it non inheritable: indeed, we must close hpipeStdin[1] before
// launching the child process as otherwise this handle will be
// it non inheritable: indeed, we must close the writing end of pipeIn
// before launching the child process as otherwise this handle will be
// inherited by the child which will never close it and so the pipe
// will never be closed and the child will be left stuck in ReadFile()
HANDLE pipeInWrite = pipeIn.Detach(wxPipe::Write);
if ( !::DuplicateHandle
(
GetCurrentProcess(),
hpipeStdin[1],
GetCurrentProcess(),
::GetCurrentProcess(),
pipeInWrite,
::GetCurrentProcess(),
&hpipeStdinWrite,
0, // desired access: unused here
FALSE, // not inherited
@@ -548,7 +651,7 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
wxLogLastError(_T("DuplicateHandle"));
}
::CloseHandle(hpipeStdin[1]);
::CloseHandle(pipeInWrite);
}
#endif // wxUSE_STREAMS
@@ -574,9 +677,9 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
// we can close the pipe ends used by child anyhow
if ( redirect )
{
::CloseHandle(hpipeStdin[0]);
::CloseHandle(hpipeStdout[1]);
::CloseHandle(hpipeStderr[1]);
::CloseHandle(pipeIn.Detach(wxPipe::Read));
::CloseHandle(pipeOut.Detach(wxPipe::Write));
::CloseHandle(pipeErr.Detach(wxPipe::Write));
}
#endif // wxUSE_STREAMS
@@ -586,8 +689,8 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
// close the other handles too
if ( redirect )
{
::CloseHandle(hpipeStdout[0]);
::CloseHandle(hpipeStderr[0]);
::CloseHandle(pipeOut.Detach(wxPipe::Read));
::CloseHandle(pipeErr.Detach(wxPipe::Read));
}
#endif // wxUSE_STREAMS
@@ -597,14 +700,25 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
}
#if wxUSE_STREAMS
// the input buffer bufOut is connected to stdout, this is why it is
// called bufOut and not bufIn
wxStreamTempInputBuffer bufOut,
bufErr;
if ( redirect )
{
// We can now initialize the wxStreams
wxInputStream *inStream = new wxPipeInputStream(hpipeStdout[0]),
*errStream = new wxPipeInputStream(hpipeStderr[0]);
wxOutputStream *outStream = new wxPipeOutputStream(hpipeStdinWrite);
wxPipeInputStream *
outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
wxPipeInputStream *
errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
wxPipeOutputStream *
inStream = new wxPipeOutputStream(hpipeStdinWrite);
handler->SetPipeStreams(inStream, outStream, errStream);
handler->SetPipeStreams(outStream, inStream, errStream);
bufOut.Init(outStream);
bufErr.Init(errStream);
}
#endif // wxUSE_STREAMS
@@ -734,10 +848,19 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
wxWindowDisabler wd;
#endif // wxUSE_GUI
// wait until the child process terminates
while ( data->state )
{
// don't take 100% of the CPU
::Sleep(500);
#if wxUSE_STREAMS
bufOut.Update();
bufErr.Update();
#endif // wxUSE_STREAMS
// don't eat 100% of the CPU -- ugly but anything else requires
// real async IO which we don't have for the moment
::Sleep(50);
// repaint the GUI
wxYield();
}

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: utilsunx.cpp
// Name: unix/utilsunx.cpp
// Purpose: generic Unix implementation of many wx functions
// Author: Vadim Zeitlin
// Id: $Id$
@@ -354,19 +354,22 @@ void wxHandleProcessTermination(wxEndProcessData *proc_data)
#if wxUSE_STREAMS
// ----------------------------------------------------------------------------
// wxProcessFileInputStream: stream for reading from a pipe
// wxPipeInputStream: stream for reading from a pipe
// ----------------------------------------------------------------------------
class wxProcessFileInputStream : public wxFileInputStream
class wxPipeInputStream : public wxFileInputStream
{
public:
wxProcessFileInputStream(int fd) : wxFileInputStream(fd) { }
wxPipeInputStream(int fd) : wxFileInputStream(fd) { }
// return TRUE if the pipe is still opened
bool IsOpened() const { return TRUE; } // TODO
// return TRUE if we have anything to read, don't block
bool IsAvailable() const;
};
bool wxProcessFileInputStream::IsAvailable() const
bool wxPipeInputStream::IsAvailable() const
{
if ( m_lasterror == wxSTREAM_EOF )
return TRUE;
@@ -400,109 +403,9 @@ bool wxProcessFileInputStream::IsAvailable() const
}
}
// ----------------------------------------------------------------------------
// wxStreamTempInputBuffer
// ----------------------------------------------------------------------------
/*
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 4Kb) 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 (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!
*/
class wxStreamTempInputBuffer
{
public:
wxStreamTempInputBuffer();
// call to associate a stream with this buffer, otherwise nothing happens
// at all
void Init(wxProcessFileInputStream *stream);
// check for input on our stream and cache it in our buffer if any
void Update();
~wxStreamTempInputBuffer();
private:
// the stream we're buffering, if NULL we don't do anything at all
wxProcessFileInputStream *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;
};
wxStreamTempInputBuffer::wxStreamTempInputBuffer()
{
m_stream = NULL;
m_buffer = NULL;
m_size = 0;
}
void wxStreamTempInputBuffer::Init(wxProcessFileInputStream *stream)
{
m_stream = stream;
}
void wxStreamTempInputBuffer::Update()
{
if ( m_stream && m_stream->IsAvailable() )
{
// realloc in blocks of 4Kb: this is the default (and minimal) buffer
// size of the Unix pipes so it should be the optimal step
static const size_t incSize = 4096;
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 += m_stream->LastRead();
}
}
}
wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
{
if ( m_buffer )
{
m_stream->Ungetch(m_buffer, m_size);
free(m_buffer);
}
}
// define this to let wxexec.cpp know that we know what we're doing
#define _WX_USED_BY_WXEXECUTE_
#include "../common/execcmn.cpp"
#endif // wxUSE_STREAMS
@@ -586,6 +489,7 @@ private:
// ----------------------------------------------------------------------------
// wxExecute: the real worker function
// ----------------------------------------------------------------------------
#ifdef __VMS
#pragma message disable codeunreachable
#endif
@@ -764,11 +668,11 @@ long wxExecute(wxChar **argv,
wxOutputStream *inStream =
new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
wxProcessFileInputStream *outStream =
new wxProcessFileInputStream(pipeOut.Detach(wxPipe::Read));
wxPipeInputStream *outStream =
new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
wxProcessFileInputStream *errStream =
new wxProcessFileInputStream(pipeErr.Detach(wxPipe::Read));
wxPipeInputStream *errStream =
new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
process->SetPipeStreams(outStream, inStream, errStream);
@@ -854,6 +758,7 @@ long wxExecute(wxChar **argv,
return ERROR_RETURN_CODE;
}
#ifdef __VMS
#pragma message enable codeunreachable
#endif