diff --git a/include/wx/process.h b/include/wx/process.h index 55dc613e5d..e2c76856b0 100644 --- a/include/wx/process.h +++ b/include/wx/process.h @@ -78,11 +78,14 @@ public: #if wxUSE_STREAMS // Pipe handling wxInputStream *GetInputStream() const { return m_inputStream; } + wxInputStream *GetErrorStream() const { return m_errorStream; } wxOutputStream *GetOutputStream() const { return m_outputStream; } // implementation only (for wxExecute) - void SetPipeStreams(wxInputStream *inStream, wxOutputStream *outStream); -#endif + void SetPipeStreams(wxInputStream *inStream, + wxOutputStream *outStream, + wxInputStream *errStream); +#endif // wxUSE_STREAMS protected: void Init(wxEvtHandler *parent, int id, bool redirect); @@ -90,9 +93,10 @@ protected: int m_id; #if wxUSE_STREAMS - wxInputStream *m_inputStream; + wxInputStream *m_inputStream, + *m_errorStream; wxOutputStream *m_outputStream; -#endif +#endif // wxUSE_STREAMS bool m_redirect; }; diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index 8f39d8121e..aa717d4c4b 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -98,6 +98,10 @@ public: wxListBox *GetLogListBox() const { return m_lbox; } private: + void ShowOutput(const wxString& cmd, + const wxArrayString& output, + const wxString& title); + wxString m_cmdLast; wxListBox *m_lbox; @@ -381,23 +385,15 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) if ( sync ) { - wxArrayString output; + wxArrayString output, errors; int code = wxExecute(cmd, output); wxLogStatus(_T("command '%s' terminated with exit code %d."), cmd.c_str(), code); if ( code != -1 ) { - m_lbox->Append(wxString::Format(_T("--- Output of '%s' ---"), - cmd.c_str())); - - size_t count = output.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - m_lbox->Append(output[n]); - } - - m_lbox->Append(_T("--- End of output ---")); + ShowOutput(cmd, output, _T("Output")); + ShowOutput(cmd, errors, _T("Errors")); } } else // async exec @@ -478,6 +474,26 @@ void MyFrame::OnProcessTerminated(MyPipedProcess *process) m_running.Remove(process); } + +void MyFrame::ShowOutput(const wxString& cmd, + const wxArrayString& output, + const wxString& title) +{ + size_t count = output.GetCount(); + if ( !count ) + return; + + m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"), + title.c_str(), cmd.c_str())); + + for ( size_t n = 0; n < count; n++ ) + { + m_lbox->Append(output[n]); + } + + m_lbox->Append(_T("--- End of output ---")); +} + // ---------------------------------------------------------------------------- // MyProcess // ---------------------------------------------------------------------------- @@ -497,6 +513,8 @@ void MyProcess::OnTerminate(int pid, int status) bool MyPipedProcess::HasInput() { + bool hasInput = FALSE; + wxInputStream& is = *GetInputStream(); if ( !is.Eof() ) { @@ -504,16 +522,28 @@ bool MyPipedProcess::HasInput() // this assumes that the output is always line buffered wxString msg; - msg << m_cmd << _T(": ") << tis.ReadLine(); + msg << m_cmd << _T(" (stdout): ") << tis.ReadLine(); m_parent->GetLogListBox()->Append(msg); - return TRUE; + hasInput = TRUE; } - else + + wxInputStream& es = *GetErrorStream(); + if ( !es.Eof() ) { - return FALSE; + wxTextInputStream tis(es); + + // this assumes that the output is always line buffered + wxString msg; + msg << m_cmd << _T(" (stderr): ") << tis.ReadLine(); + + m_parent->GetLogListBox()->Append(msg); + + hasInput = TRUE; } + + return hasInput; } void MyPipedProcess::OnTerminate(int pid, int status) diff --git a/src/common/process.cpp b/src/common/process.cpp index 3166d2b19c..5a3f23843a 100644 --- a/src/common/process.cpp +++ b/src/common/process.cpp @@ -39,16 +39,18 @@ void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect) #if wxUSE_STREAMS m_inputStream = NULL; + m_errorStream = NULL; m_outputStream = NULL; -#endif +#endif // wxUSE_STREAMS } wxProcess::~wxProcess() { #if wxUSE_STREAMS delete m_inputStream; + delete m_errorStream; delete m_outputStream; -#endif +#endif // wxUSE_STREAMS } void wxProcess::OnTerminate(int pid, int status) @@ -67,9 +69,14 @@ void wxProcess::Detach() } #if wxUSE_STREAMS -void wxProcess::SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream) + +void wxProcess::SetPipeStreams(wxInputStream *inputSstream, + wxOutputStream *outputStream, + wxInputStream *errorStream) { - m_inputStream = in_stream; - m_outputStream = out_stream; + m_inputStream = inputSstream; + m_errorStream = errorStream; + m_outputStream = outputStream; } -#endif + +#endif // wxUSE_STREAMS diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 87bcd66ce2..09049b1e55 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -498,7 +498,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) wxInputStream *inStream = new wxPipeInputStream(hpipeStdout[0]); wxOutputStream *outStream = new wxPipeOutputStream(hpipeStdin[1]); - handler->SetPipeStreams(inStream, outStream); + handler->SetPipeStreams(inStream, outStream, NULL); } #endif // wxUSE_STREAMS diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index adfbcd04c2..b27a76a82e 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -436,14 +436,18 @@ long wxExecute(wxChar **argv, } #endif // wxUSE_GUI - int pipeIn[2]; - int pipeOut[2]; + // pipes for inter process communication + int pipeIn[2], // stdin + pipeOut[2], // stdout + pipeErr[2]; // stderr + pipeIn[0] = pipeIn[1] = - pipeOut[0] = pipeOut[1] = -1; + pipeOut[0] = pipeOut[1] = + pipeErr[0] = pipeErr[1] = -1; if ( process && process->IsRedirected() ) { - if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 ) + if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 || pipe(pipeErr) == -1 ) { #if wxUSE_GUI // free previously allocated resources @@ -476,6 +480,8 @@ long wxExecute(wxChar **argv, close(pipeIn[1]); close(pipeOut[0]); close(pipeOut[1]); + close(pipeErr[0]); + close(pipeErr[1]); #endif // wxUSE_GUI wxLogSysError( _("Fork failed") ); @@ -498,7 +504,7 @@ long wxExecute(wxChar **argv, { for ( int fd = 0; fd < FD_SETSIZE; fd++ ) { - if ( fd == pipeIn[0] || fd == pipeOut[1] + if ( fd == pipeIn[0] || fd == pipeOut[1] || fd == pipeErr[1] #if wxUSE_GUI || fd == end_proc_detect[1] #endif // wxUSE_GUI @@ -514,19 +520,19 @@ long wxExecute(wxChar **argv, } } - // redirect stdio and stdout - // (TODO: what about stderr?) + // redirect stdio, stdout and stderr if ( pipeIn[0] != -1 ) { if ( dup2(pipeIn[0], STDIN_FILENO) == -1 || - dup2(pipeOut[1], STDOUT_FILENO) == -1 ) + dup2(pipeOut[1], STDOUT_FILENO) == -1 || + dup2(pipeErr[1], STDERR_FILENO) == -1 ) { - wxLogSysError(_("Failed to redirect child process " - "input/output")); + wxLogSysError(_("Failed to redirect child process input/output")); } close(pipeIn[0]); close(pipeOut[1]); + close(pipeErr[1]); } execvp (*mb_argv, mb_argv); @@ -544,10 +550,13 @@ long wxExecute(wxChar **argv, // These two streams are relative to this process. wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]); wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]); + wxInputStream *errStream = new wxProcessFileInputStream(pipeErr[0]); + close(pipeIn[0]); // close reading side close(pipeOut[1]); // close writing side + close(pipeErr[1]); // close writing side - process->SetPipeStreams(inStream, outStream); + process->SetPipeStreams(inStream, outStream, errStream); } #if wxUSE_GUI