From: Vadim Zeitlin Date: Tue, 20 Aug 2002 22:32:40 +0000 (+0000) Subject: fixes for wxExecute() with IO redirection: wxStreamTempInputBuffer is now used under... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/79066131734040a7d01b87566fc1262e7fbe51ad 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 --- diff --git a/docs/changes.txt b/docs/changes.txt index bd59434497..b4528c53ba 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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: diff --git a/src/common/execcmn.cpp b/src/common/execcmn.cpp new file mode 100644 index 0000000000..f89e061b2c --- /dev/null +++ b/src/common/execcmn.cpp @@ -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 +// 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_ + diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 21b74439c3..69ee8c8c46 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -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,9 +159,174 @@ 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" + +// ---------------------------------------------------------------------------- +// wxPipe represents a Win32 anonymous pipe +// ---------------------------------------------------------------------------- + +class wxPipe +{ +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; + } + + return TRUE; + } + + // 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 + { + wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_handles), + _T("invalid pipe index") ); + + return m_handles[which]; + } + + // detach a descriptor, meaning that the pipe dtor won't close it, and + // return it + HANDLE Detach(Direction which) + { + wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_handles), + _T("invalid pipe index") ); + + HANDLE handle = m_handles[which]; + m_handles[which] = INVALID_HANDLE_VALUE; + + return handle; + } + + // close the pipe descriptors + void Close() + { + for ( size_t n = 0; n < WXSIZEOF(m_handles); n++ ) + { + if ( m_handles[n] != INVALID_HANDLE_VALUE ) + { + ::CloseHandle(m_handles[n]); + m_handles[n] = INVALID_HANDLE_VALUE; + } + } + } + + // dtor closes the pipe descriptors + ~wxPipe() { Close(); } + +private: + HANDLE m_handles[2]; +}; + +#endif // wxUSE_STREAMS + +// ============================================================================ +// implementation +// ============================================================================ + +#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; + + 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) ) + { + wxLogLastError(wxT("GetExitCodeProcess")); + } + + wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE, + wxT("process should have terminated") ); + + // send a message indicating process termination to the window + ::SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data); + + return 0; +} + +// window procedure of a hidden window which is created just to receive +// the notification message when a process exits +LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + if ( message == wxWM_PROC_TERMINATED ) + { + DestroyWindow(hWnd); // we don't need it any more + + wxExecuteData *data = (wxExecuteData *)lParam; + if ( data->handler ) + { + data->handler->OnTerminate((int)data->dwProcessId, + (int)data->dwExitCode); + } + + if ( data->state ) + { + // we're executing synchronously, tell the waiting thread + // that the process finished + data->state = 0; + } + else + { + // asynchronous execution - we should do the clean up + delete data; + } + + return 0; + } + else + { + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +// ============================================================================ +// implementation of IO redirection support classes +// ============================================================================ + +#if wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// wxPipeInputStreams +// ---------------------------------------------------------------------------- wxPipeInputStream::wxPipeInputStream(HANDLE hInput) { @@ -166,11 +335,15 @@ wxPipeInputStream::wxPipeInputStream(HANDLE hInput) wxPipeInputStream::~wxPipeInputStream() { - ::CloseHandle(m_hInput); + if ( m_hInput != INVALID_HANDLE_VALUE ) + ::CloseHandle(m_hInput); } -bool wxPipeInputStream::Eof() const +bool wxPipeInputStream::IsAvailable() const { + if ( !IsOpened() ) + return FALSE; + DWORD nAvailable; // function name is misleading, it works with anon pipes as well @@ -193,21 +366,28 @@ bool wxPipeInputStream::Eof() const // don't try to continue reading from a pipe if an error occured or if // it had been closed - return TRUE; - } - else - { - return nAvailable == 0; + ::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 - m_lasterror = wxSTREAM_NOERROR; - if ( Eof() ) + if ( !IsAvailable() ) + { + m_lasterror = wxSTREAM_EOF; + return 0; + } + + m_lasterror = wxSTREAM_NOERROR; DWORD bytesRead; if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) ) @@ -221,9 +401,9 @@ size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len) return bytesRead; } -// ================== +// ---------------------------------------------------------------------------- // wxPipeOutputStream -// ================== +// ---------------------------------------------------------------------------- wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput) { @@ -251,72 +431,14 @@ size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len) return bytesRead; } -#endif // __WIN32__ +#endif // wxUSE_STREAMS + +#endif // Win32 // ============================================================================ -// implementation +// wxExecute functions family // ============================================================================ -#ifdef __WIN32__ - -static DWORD __stdcall wxExecuteThread(void *arg) -{ - wxExecuteData *data = (wxExecuteData*)arg; - - WaitForSingleObject(data->hProcess, INFINITE); - - // get the exit code - if ( !GetExitCodeProcess(data->hProcess, &data->dwExitCode) ) - { - wxLogLastError(wxT("GetExitCodeProcess")); - } - - wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE, - wxT("process should have terminated") ); - - // send a message indicating process termination to the window - SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data); - - return 0; -} - -// window procedure of a hidden window which is created just to receive -// the notification message when a process exits -LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - if ( message == wxWM_PROC_TERMINATED ) - { - DestroyWindow(hWnd); // we don't need it any more - - wxExecuteData *data = (wxExecuteData *)lParam; - if ( data->handler ) - { - data->handler->OnTerminate((int)data->dwProcessId, - (int)data->dwExitCode); - } - - if ( data->state ) - { - // we're executing synchronously, tell the waiting thread - // that the process finished - data->state = 0; - } - else - { - // asynchronous execution - we should do the clean up - delete data; - } - - return 0; - } - else - { - return DefWindowProc(hWnd, message, wParam, lParam); - } -} -#endif // Win32 - #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(outStream, inStream, errStream); - handler->SetPipeStreams(inStream, outStream, errStream); + bufOut.Init(outStream); + bufErr.Init(errStream); } #endif // wxUSE_STREAMS @@ -734,12 +848,21 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler) wxWindowDisabler wd; #endif // wxUSE_GUI - while ( data->state ) - { - // don't take 100% of the CPU - ::Sleep(500); - wxYield(); - } + // wait until the child process terminates + while ( data->state ) + { +#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(); + } #if wxUSE_GUI } diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 70d467e744..6fe5a0b5f7 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -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,8 +489,9 @@ private: // ---------------------------------------------------------------------------- // wxExecute: the real worker function // ---------------------------------------------------------------------------- + #ifdef __VMS -#pragma message disable codeunreachable + #pragma message disable codeunreachable #endif long wxExecute(wxChar **argv, @@ -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,8 +758,9 @@ long wxExecute(wxChar **argv, return ERROR_RETURN_CODE; } + #ifdef __VMS -#pragma message enable codeunreachable + #pragma message enable codeunreachable #endif #undef ERROR_RETURN_CODE @@ -868,13 +773,13 @@ long wxExecute(wxChar **argv, const wxChar* wxGetHomeDir( wxString *home ) { *home = wxGetUserHome( wxString() ); - wxString tmp; + wxString tmp; if ( home->IsEmpty() ) *home = wxT("/"); #ifdef __VMS - tmp = *home; - if ( tmp.Last() != wxT(']')) - if ( tmp.Last() != wxT('/')) *home << wxT('/'); + tmp = *home; + if ( tmp.Last() != wxT(']')) + if ( tmp.Last() != wxT('/')) *home << wxT('/'); #endif return home->c_str(); }