1. wxProcess changes to make capturing subprocess output easier (and more
reliable), now works in both sync and async modes 2. wxSafeYieldBug() corrected, wxWindowDisabler which is now used in it added and documented 3. exec sample updated to illustrate capturing the subprocess output 4. wxStreamBase::IsOk() added 5. wxInputStream::Eof() added and non-blocking Eof() implementation in wxPipeInputStream used by wxExecute git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6400 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -29,23 +29,21 @@
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler)
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
|
||||
|
||||
wxProcess::wxProcess(wxEvtHandler *parent, bool needPipe, int id)
|
||||
void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
|
||||
{
|
||||
if (parent)
|
||||
if ( parent )
|
||||
SetNextHandler(parent);
|
||||
|
||||
m_id = id;
|
||||
m_needPipe = needPipe;
|
||||
m_in_stream = NULL;
|
||||
m_out_stream = NULL;
|
||||
m_redirect = redirect;
|
||||
m_inputStream = NULL;
|
||||
m_outputStream = NULL;
|
||||
}
|
||||
|
||||
wxProcess::~wxProcess()
|
||||
{
|
||||
if (m_in_stream)
|
||||
delete m_in_stream;
|
||||
if (m_out_stream)
|
||||
delete m_out_stream;
|
||||
delete m_inputStream;
|
||||
delete m_outputStream;
|
||||
}
|
||||
|
||||
void wxProcess::OnTerminate(int pid, int status)
|
||||
@@ -65,21 +63,7 @@ void wxProcess::Detach()
|
||||
|
||||
void wxProcess::SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream)
|
||||
{
|
||||
m_in_stream = in_stream;
|
||||
m_out_stream = out_stream;
|
||||
m_inputStream = in_stream;
|
||||
m_outputStream = out_stream;
|
||||
}
|
||||
|
||||
wxInputStream *wxProcess::GetInputStream() const
|
||||
{
|
||||
return m_in_stream;
|
||||
}
|
||||
|
||||
wxOutputStream *wxProcess::GetOutputStream() const
|
||||
{
|
||||
return m_out_stream;
|
||||
}
|
||||
|
||||
bool wxProcess::NeedPipe() const
|
||||
{
|
||||
return m_needPipe;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ char wxStreamBuffer::GetChar()
|
||||
}
|
||||
|
||||
GetFromBuffer(&c, 1);
|
||||
|
||||
|
||||
m_stream->m_lastcount = 1;
|
||||
return c;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ size_t wxStreamBuffer::Read(void *buffer, size_t size)
|
||||
size_t buf_left, orig_size = size;
|
||||
|
||||
while (size > 0) {
|
||||
buf_left = GetDataLeft();
|
||||
buf_left = GetDataLeft();
|
||||
|
||||
// First case: the requested buffer is larger than the stream buffer,
|
||||
// we split it.
|
||||
@@ -428,10 +428,10 @@ off_t wxStreamBuffer::Tell() const
|
||||
return wxInvalidOffset;
|
||||
|
||||
pos += GetIntPosition();
|
||||
|
||||
|
||||
if (m_mode == read && m_flushable)
|
||||
pos -= GetLastAccess();
|
||||
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ size_t wxStreamBuffer::GetDataLeft()
|
||||
/* Why is this done? RR. */
|
||||
if (m_buffer_end == m_buffer_pos && m_flushable)
|
||||
FillBuffer();
|
||||
|
||||
|
||||
return m_buffer_end-m_buffer_pos;
|
||||
}
|
||||
|
||||
@@ -494,6 +494,22 @@ wxInputStream::~wxInputStream()
|
||||
free(m_wback);
|
||||
}
|
||||
|
||||
bool wxInputStream::Eof() const
|
||||
{
|
||||
wxInputStream *self = (wxInputStream *)this; // const_cast
|
||||
|
||||
char c;
|
||||
self->Read(&c, 1);
|
||||
if ( GetLastError() == wxSTREAM_EOF )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
self->Ungetch(c);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char *wxInputStream::AllocSpaceWBack(size_t needed_size)
|
||||
{
|
||||
/* get number of bytes left from previous wback buffer */
|
||||
@@ -533,14 +549,14 @@ size_t wxInputStream::GetWBack(char *buf, size_t bsize)
|
||||
memcpy(buf, (m_wback+m_wbackcur), s_toget);
|
||||
|
||||
m_wbackcur += s_toget;
|
||||
if (m_wbackcur == m_wbacksize)
|
||||
if (m_wbackcur == m_wbacksize)
|
||||
{
|
||||
free(m_wback);
|
||||
m_wback = (char *)NULL;
|
||||
m_wbacksize = 0;
|
||||
m_wbackcur = 0;
|
||||
}
|
||||
|
||||
|
||||
return s_toget;
|
||||
}
|
||||
|
||||
@@ -549,7 +565,7 @@ size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
|
||||
char *ptrback = AllocSpaceWBack(bufsize);
|
||||
if (!ptrback)
|
||||
return 0;
|
||||
|
||||
|
||||
memcpy(ptrback, buf, bufsize);
|
||||
return bufsize;
|
||||
}
|
||||
@@ -576,7 +592,7 @@ wxInputStream& wxInputStream::Read(void *buffer, size_t size)
|
||||
char *buf = (char *)buffer;
|
||||
|
||||
size_t retsize = GetWBack(buf, size);
|
||||
if (retsize == size)
|
||||
if (retsize == size)
|
||||
{
|
||||
m_lastcount = size;
|
||||
m_lasterror = wxStream_NOERROR;
|
||||
@@ -593,21 +609,21 @@ char wxInputStream::Peek()
|
||||
{
|
||||
char c;
|
||||
Read(&c, 1);
|
||||
if (m_lasterror == wxStream_NOERROR)
|
||||
if (m_lasterror == wxStream_NOERROR)
|
||||
{
|
||||
Ungetch(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
|
||||
{
|
||||
char buf[BUF_TEMP_SIZE];
|
||||
char buf[BUF_TEMP_SIZE];
|
||||
size_t bytes_read = BUF_TEMP_SIZE;
|
||||
|
||||
while (bytes_read == BUF_TEMP_SIZE)
|
||||
while (bytes_read == BUF_TEMP_SIZE)
|
||||
{
|
||||
bytes_read = Read(buf, bytes_read).LastRead();
|
||||
bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
|
||||
@@ -619,7 +635,7 @@ off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
|
||||
{
|
||||
/* Should be check and improve, just to remove a slight bug !
|
||||
I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
|
||||
if (m_lasterror==wxSTREAM_EOF)
|
||||
if (m_lasterror==wxSTREAM_EOF)
|
||||
m_lasterror=wxSTREAM_NOERROR;
|
||||
|
||||
/* A call to SeekI() will automatically invalidate any previous call
|
||||
@@ -632,7 +648,7 @@ off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
|
||||
when seeking in wxFromCurrent mode, else it would invalidate
|
||||
anyway...
|
||||
*/
|
||||
if (m_wback)
|
||||
if (m_wback)
|
||||
{
|
||||
free(m_wback);
|
||||
m_wback = (char*) NULL;
|
||||
@@ -750,9 +766,9 @@ off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
|
||||
m_currentPos = m_lastcount + pos;
|
||||
else
|
||||
m_currentPos += pos;
|
||||
|
||||
|
||||
if (m_currentPos > m_lastcount) m_lastcount = m_currentPos;
|
||||
|
||||
|
||||
return m_currentPos;
|
||||
}
|
||||
|
||||
@@ -760,7 +776,7 @@ off_t wxCountingOutputStream::OnSysTell() const
|
||||
{
|
||||
return m_currentPos;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFilterInputStream
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -828,7 +844,7 @@ wxInputStream& wxBufferedInputStream::Read(void *buffer, size_t size)
|
||||
|
||||
retsize = GetWBack(buf, size);
|
||||
m_lastcount = retsize;
|
||||
if (retsize == size)
|
||||
if (retsize == size)
|
||||
{
|
||||
m_lasterror = wxStream_NOERROR;
|
||||
return *this;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Created: 28/06/98
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) Guilhem Lavaux
|
||||
// Licence: wxWindows license
|
||||
// Licence: wxWindows license
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __GNUG__
|
||||
@@ -52,13 +52,13 @@ wxChar wxTextInputStream::NextNonSeparators()
|
||||
wxChar c = (wxChar) 0;
|
||||
for (;;)
|
||||
{
|
||||
if (!m_input) return (wxChar) 0;
|
||||
if (!m_input) return (wxChar) 0;
|
||||
c = m_input.GetC();
|
||||
|
||||
if (c != wxT('\n') &&
|
||||
c != wxT('\r') &&
|
||||
!m_separators.Contains(c))
|
||||
return c;
|
||||
|
||||
if (c != wxT('\n') &&
|
||||
c != wxT('\r') &&
|
||||
!m_separators.Contains(c))
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,12 +66,12 @@ wxChar wxTextInputStream::NextNonSeparators()
|
||||
inline bool wxTextInputStream::EatEOL(const wxChar &c)
|
||||
{
|
||||
if (c == wxT('\n')) return TRUE; // eat on UNIX
|
||||
|
||||
|
||||
if (c == wxT('\r')) // eat on both Mac and DOS
|
||||
{
|
||||
if (!m_input) return TRUE;
|
||||
wxChar c2 = m_input.GetC();
|
||||
|
||||
|
||||
if (c2 != wxT('\n')) m_input.Ungetch( c2 ); // Don't eat on Mac
|
||||
return TRUE;
|
||||
}
|
||||
@@ -88,11 +88,13 @@ void wxTextInputStream::SkipIfEndOfLine( wxChar c )
|
||||
wxUint32 wxTextInputStream::Read32()
|
||||
{
|
||||
/* I only implemented a simple integer parser */
|
||||
// VZ: what about using strtol()?? (TODO)
|
||||
|
||||
int sign;
|
||||
wxInt32 i;
|
||||
|
||||
if (!m_input) return 0;
|
||||
int c = NextNonSeparators();
|
||||
int c = NextNonSeparators();
|
||||
if (c==(wxChar)0) return 0;
|
||||
|
||||
i = 0;
|
||||
@@ -142,6 +144,7 @@ wxUint8 wxTextInputStream::Read8()
|
||||
double wxTextInputStream::ReadDouble()
|
||||
{
|
||||
/* I only implemented a simple float parser */
|
||||
// VZ: what about using strtod()?? (TODO)
|
||||
double f;
|
||||
int sign;
|
||||
|
||||
@@ -184,32 +187,32 @@ double wxTextInputStream::ReadDouble()
|
||||
c = m_input.GetC();
|
||||
|
||||
while (isdigit(c))
|
||||
{
|
||||
{
|
||||
f += (c-wxT('0'))*f_multiplicator;
|
||||
f_multiplicator /= 10;
|
||||
c = m_input.GetC();
|
||||
}
|
||||
|
||||
if (c == wxT('e'))
|
||||
{
|
||||
{
|
||||
double f_multiplicator = 0.0;
|
||||
int i, e;
|
||||
|
||||
c = m_input.GetC();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
{
|
||||
case wxT('-'): f_multiplicator = 0.1; break;
|
||||
case wxT('+'): f_multiplicator = 10.0; break;
|
||||
}
|
||||
case wxT('+'): f_multiplicator = 10.0; break;
|
||||
}
|
||||
|
||||
e = Read8(); // why only max 256 ?
|
||||
|
||||
for (i=0;i<e;i++)
|
||||
f *= f_multiplicator;
|
||||
}
|
||||
else
|
||||
SkipIfEndOfLine( c );
|
||||
else
|
||||
SkipIfEndOfLine( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -223,7 +226,7 @@ double wxTextInputStream::ReadDouble()
|
||||
|
||||
wxString wxTextInputStream::ReadString()
|
||||
{
|
||||
return ReadLine();
|
||||
return ReadLine();
|
||||
}
|
||||
|
||||
wxString wxTextInputStream::ReadLine()
|
||||
@@ -231,13 +234,15 @@ wxString wxTextInputStream::ReadLine()
|
||||
wxChar c;
|
||||
wxString line;
|
||||
|
||||
for (;;)
|
||||
while ( !m_input.Eof() )
|
||||
{
|
||||
if (!m_input) break;
|
||||
c = m_input.GetC();
|
||||
|
||||
if (EatEOL(c)) break;
|
||||
|
||||
if ( !m_input )
|
||||
break;
|
||||
|
||||
if (EatEOL(c))
|
||||
break;
|
||||
|
||||
line += c;
|
||||
}
|
||||
|
||||
@@ -246,22 +251,28 @@ wxString wxTextInputStream::ReadLine()
|
||||
|
||||
wxString wxTextInputStream::ReadWord()
|
||||
{
|
||||
if (!m_input) return "";
|
||||
|
||||
wxString word;
|
||||
wxChar c=NextNonSeparators();
|
||||
if (c==(wxChar)0) return "";
|
||||
|
||||
for (;;)
|
||||
if ( !m_input )
|
||||
return word;
|
||||
|
||||
wxChar c = NextNonSeparators();
|
||||
if ( !c )
|
||||
return word;
|
||||
|
||||
while ( !m_input.Eof() )
|
||||
{
|
||||
if (m_separators.Contains(c)) break;
|
||||
|
||||
if (EatEOL(c)) break;
|
||||
|
||||
if (m_separators.Contains(c))
|
||||
break;
|
||||
|
||||
if (EatEOL(c))
|
||||
break;
|
||||
|
||||
word += c;
|
||||
|
||||
if (!m_input) break;
|
||||
c = m_input.GetC();
|
||||
if (!m_input)
|
||||
break;
|
||||
}
|
||||
|
||||
return word;
|
||||
@@ -269,8 +280,8 @@ wxString wxTextInputStream::ReadWord()
|
||||
|
||||
wxTextInputStream& wxTextInputStream::operator>>(wxString& word)
|
||||
{
|
||||
word = ReadWord();
|
||||
return *this;
|
||||
word = ReadWord();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxTextInputStream& wxTextInputStream::operator>>(wxChar& c)
|
||||
@@ -397,19 +408,19 @@ void wxTextOutputStream::WriteString(const wxString& string)
|
||||
wxChar c = string[i];
|
||||
if (c == wxT('\n'))
|
||||
{
|
||||
if (m_mode == wxEOL_DOS)
|
||||
{
|
||||
if (m_mode == wxEOL_DOS)
|
||||
{
|
||||
c = wxT('\r');
|
||||
m_output.Write( (const void*)(&c), sizeof(wxChar) );
|
||||
c = wxT('\n');
|
||||
m_output.Write( (const void*)(&c), sizeof(wxChar) );
|
||||
} else
|
||||
if (m_mode == wxEOL_MAC)
|
||||
{
|
||||
} else
|
||||
if (m_mode == wxEOL_MAC)
|
||||
{
|
||||
c = wxT('\r');
|
||||
m_output.Write( (const void*)(&c), sizeof(wxChar) );
|
||||
} else
|
||||
{
|
||||
} else
|
||||
{
|
||||
c = wxT('\n');
|
||||
m_output.Write( (const void*)(&c), sizeof(wxChar) );
|
||||
}
|
||||
@@ -444,7 +455,7 @@ wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c)
|
||||
wxString str;
|
||||
str.Printf(wxT("%d"), (signed int)c);
|
||||
WriteString(str);
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -453,7 +464,7 @@ wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c)
|
||||
wxString str;
|
||||
str.Printf(wxT("%ld"), (signed long)c);
|
||||
WriteString(str);
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -462,7 +473,7 @@ wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c)
|
||||
wxString str;
|
||||
str.Printf(wxT("%u"), (unsigned int)c);
|
||||
WriteString(str);
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
#endif // wxUSE_GUI
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/process.h"
|
||||
#include "wx/txtstrm.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -965,46 +968,61 @@ static void wxFindDisabledWindows(wxWindowList& winDisabled, wxWindow *win)
|
||||
for ( node = win->GetChildren().GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
wxWindow *child = node->GetData();
|
||||
wxFindDisabledWindows(winDisabled, child);
|
||||
|
||||
if ( child->IsEnabled() )
|
||||
{
|
||||
winDisabled.Append(child);
|
||||
child->Disable();
|
||||
}
|
||||
|
||||
wxFindDisabledWindows(winDisabled, child);
|
||||
}
|
||||
}
|
||||
|
||||
wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
|
||||
{
|
||||
// remember all windows we're going to (temporarily) disable
|
||||
m_winDisabled = new wxWindowList;
|
||||
|
||||
wxWindowList::Node *node;
|
||||
for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
wxWindow *winTop = node->GetData();
|
||||
if ( winTop->IsEnabled() )
|
||||
{
|
||||
wxFindDisabledWindows(*m_winDisabled, winTop);
|
||||
|
||||
m_winDisabled->Append(winTop);
|
||||
winTop->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
if ( winToSkip && m_winDisabled->Find(winToSkip) )
|
||||
{
|
||||
// always enable ourselves
|
||||
m_winDisabled->DeleteObject(winToSkip);
|
||||
winToSkip->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
wxWindowDisabler::~wxWindowDisabler()
|
||||
{
|
||||
wxWindowList::Node *node;
|
||||
for ( node = m_winDisabled->GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
node->GetData()->Enable();
|
||||
}
|
||||
|
||||
delete m_winDisabled;
|
||||
}
|
||||
|
||||
// Yield to other apps/messages and disable user input to all windows except
|
||||
// the given one
|
||||
bool wxSafeYield(wxWindow *win)
|
||||
{
|
||||
// remember all windows we're going to (temporarily) disable
|
||||
wxWindowList winDisabled;
|
||||
|
||||
wxWindowList::Node *node;
|
||||
for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
wxWindow *winTop = node->GetData();
|
||||
wxFindDisabledWindows(winDisabled, winTop);
|
||||
|
||||
winTop->Disable();
|
||||
}
|
||||
|
||||
if ( win )
|
||||
{
|
||||
// always enable ourselves
|
||||
win->Enable();
|
||||
}
|
||||
wxWindowDisabler wd;
|
||||
|
||||
bool rc = wxYield();
|
||||
|
||||
// don't call wxEnableTopLevelWindows(TRUE) because this will reenable even
|
||||
// the window which had been disabled before, do it manually instead
|
||||
for ( node = winDisabled.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
node->GetData()->Enable();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1154,3 +1172,31 @@ wxString wxGetCurrentDir()
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxExecute
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
long wxExecute(const wxString& command, wxArrayString& output)
|
||||
{
|
||||
// create a wxProcess which will capture the output
|
||||
wxProcess *process = new wxProcess;
|
||||
process->Redirect();
|
||||
|
||||
long rc = wxExecute(command, TRUE /* sync */, process);
|
||||
if ( rc != -1 )
|
||||
{
|
||||
wxInputStream& is = *process->GetInputStream();
|
||||
wxTextInputStream tis(is);
|
||||
while ( !is.Eof() )
|
||||
{
|
||||
wxString line = tis.ReadLine();
|
||||
if ( is.LastError() )
|
||||
break;
|
||||
|
||||
output.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user