]> git.saurik.com Git - wxWidgets.git/commitdiff
1. wxProcess changes to make capturing subprocess output easier (and more
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 2 Mar 2000 19:06:13 +0000 (19:06 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 2 Mar 2000 19:06:13 +0000 (19:06 +0000)
   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

16 files changed:
docs/latex/wx/busycurs.tex
docs/latex/wx/function.tex
docs/latex/wx/inputstr.tex
docs/latex/wx/stream.tex
docs/latex/wx/strmbase.tex
docs/latex/wx/wnddisbl.tex [new file with mode: 0644]
include/wx/process.h
include/wx/stream.h
include/wx/utils.h
samples/exec/exec.cpp
src/common/process.cpp
src/common/stream.cpp
src/common/txtstrm.cpp
src/common/utilscmn.cpp
src/msw/utilsexc.cpp
src/unix/utilsunx.cpp

index 10363652756018468be218fa1202c247e5b46bcd..179caa8435cf6ecfbcec01c41283cc7716cfa4d7 100644 (file)
@@ -26,7 +26,9 @@ None
 
 \wxheading{See also}
 
-\helpref{wxBeginBusyCursor}{wxbeginbusycursor}, \helpref{wxEndBusyCursor}{wxendbusycursor}
+\helpref{wxBeginBusyCursor}{wxbeginbusycursor},\rtfsp
+\helpref{wxEndBusyCursor}{wxendbusycursor},\rtfsp
+\helpref{wxWindowDisabler}{wxwindowdisabler}
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
index bfd6094c88ab705404d363a82622be658b5e0259..13e2bbb85390c2f01b9db09755c735fb4410a10b 100644 (file)
@@ -1117,7 +1117,7 @@ registered with the dynamic class system using DECLARE... and IMPLEMENT... macro
 Called when wxWindows exits, to clean up the DDE system. This no longer needs to be
 called by the application.
 
-See also helpref{wxDDEInitialize}{wxddeinitialize}.
+See also \helpref{wxDDEInitialize}{wxddeinitialize}.
 
 \wxheading{Include files}
 
@@ -1259,6 +1259,8 @@ wxWindows errors. See also \helpref{wxFatalError}{wxfatalerror}.
 
 \func{long}{wxExecute}{\param{char **}{argv}, \param{bool }{sync = FALSE}, \param{wxProcess *}{callback = NULL}}
 
+\func{long}{wxExecute}{\param{const wxString\& }{command}, \param{wxArrayString\& }{output}}
+
 Executes another program in Unix or Windows.
 
 The first form takes a command string, such as {\tt "emacs file.txt"}.
@@ -1266,6 +1268,9 @@ The first form takes a command string, such as {\tt "emacs file.txt"}.
 The second form takes an array of values: a command, any number of
 arguments, terminated by NULL.
 
+The semantics of the third version is different from the first two and is
+described in more details below.
+
 If {\it sync} is FALSE (the default), flow of control immediately returns.
 If TRUE, the current application waits until the other program has terminated.
 
@@ -1285,6 +1290,10 @@ parameter can not be non NULL for synchronous execution),
 \helpref{wxProcess::OnTerminate}{wxprocessonterminate} will be called when
 the process finishes.
 
+Finally, you may use the third overloaded version of this function to execute
+a process (always synchronously) and capture its output in the array 
+{\it output}.
+
 See also \helpref{wxShell}{wxshell}, \helpref{wxProcess}{wxprocess}, 
 \helpref{Exec sample}{sampleexec}.
 
index 1df6d394dc92533b4a23621ea18d60fa72ef75ff..236b1657c7557288de5690e86fde9d5e89bf2aaa 100644 (file)
@@ -34,6 +34,12 @@ Destructor.
 
 Returns the first character in the input queue and removes it.
 
+\membersection{wxInputStream::Eof}\label{wxinputstreameof}
+
+\constfunc{wxInputStream}{Eof}{\void}
+
+Returns TRUE if the end of stream has been reached.
+
 \membersection{wxInputStream::LastRead}\label{wxinputstreamlastread}
 
 \constfunc{size\_t}{LastRead}{\void}
index e79c80ad69134e4178fc11c8e05d880801046076..f33416983626bb0536c5a96b9cdb7c47fe932d72 100644 (file)
@@ -90,7 +90,7 @@ accordingly until all requested data is read.
 
 \wxheading{Return value}
 
-It returns the size of the data read. If thereturned size is different of the specified 
+It returns the size of the data read. If the returned size is different of the specified 
 {\it size}, an error has occured and should be tested using 
 \helpref{LastError}{wxstreambaselasterror}.
 
index 1bcd9ec56b900c96dc45954a97e596c77260d057..40ce15f24fd7370389a143ce418d70caa2371a3e 100644 (file)
@@ -39,6 +39,16 @@ Creates a dummy stream object. It doesn't do anything.
 
 Destructor.
 
+\membersection{wxStreamBase::IsOk}\label{wxstreambaseisok}
+
+\constfunc{wxStreamError}{IsOk}{\void}
+
+Returns TRUE if no error occured on the stream.
+
+\wxheading{See also}
+
+\helpref{LastError}{wxstreambaselasterror}
+
 \membersection{wxStreamBase::LastError}\label{wxstreambaselasterror}
 
 \constfunc{wxStreamError}{LastError}{\void}
@@ -84,7 +94,7 @@ See \helpref{OnSysRead}{wxstreambaseonsysread}.
 \constfunc{size\_t}{GetSize}{\void}
 
 This function returns the size of the stream. For example, for a file it is the size of
-the file).
+the file.
 
 \wxheading{Warning}
 
diff --git a/docs/latex/wx/wnddisbl.tex b/docs/latex/wx/wnddisbl.tex
new file mode 100644 (file)
index 0000000..0148385
--- /dev/null
@@ -0,0 +1,31 @@
+\section{\class{wxWindowDisabler}}\label{wxwindowdisabler}
+
+This class disables all windows of the application (may be with the exception
+of one of them) in its constructor and enables them back in its destructor.
+This comes in handy when you want to indicate to the user that the application
+is currently busy and cannot respond to user input.
+
+\wxheading{Derived from}
+
+None
+
+\wxheading{Include files}
+
+<wx/utils.h>
+
+\wxheading{See also}
+
+\helpref{wxBusyCursor}{wxbusycursor}
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+\membersection{wxWindowDisabler::wxWindowDisabler}
+
+\func{}{wxWindowDisabler}{\param{wxWindow *}{winToSkip = NULL}}
+
+Disables all top level windows of the applications with the exception of 
+{\it winToSkip} if it is not {\tt NULL}.
+
+\membersection{wxWindowDisabler::\destruct{wxWindowDisabler}}
+
+Reenables back the windows disabled by the constructor.
index 19ae35c1f65b9b88dbf5c4fce978d6c338b55e58..f88b6a85c7b4816e6310727f5bc6f753e6ab4c9b 100644 (file)
@@ -52,30 +52,42 @@ class WXDLLEXPORT wxProcess : public wxEvtHandler
 DECLARE_DYNAMIC_CLASS(wxProcess)
 
 public:
-    wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, bool needPipe = FALSE, int id = -1);
-    ~wxProcess();
+    wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, int id = -1)
+        { Init(parent, id, FALSE); }
+    wxProcess(wxEvtHandler *parent, bool redirect)
+        { Init(parent, -1, redirect); }
 
+    virtual ~wxProcess();
+
+    // may be overridden to be notified about process termination
     virtual void OnTerminate(int pid, int status);
 
+    // call this before passing the object to wxExecute() to redirect the
+    // launched process stdin/stdout, then use GetInputStream() and
+    // GetOutputStream() to get access to them
+    void Redirect() { m_redirect = TRUE; }
+    bool IsRedirected() const { return m_redirect; }
+
     // detach from the parent - should be called by the parent if it's deleted
     // before the process it started terminates
     void Detach();
 
     // Pipe handling
-    wxInputStream *GetInputStream() const;
-    wxOutputStream *GetOutputStream() const;
+    wxInputStream *GetInputStream() const { return m_inputStream; }
+    wxOutputStream *GetOutputStream() const { return m_outputStream; }
 
-    // These functions should not be called by the usual user. They are only
-    // intended to be used by wxExecute.
-    // Install pipes
-    void SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream);
-    bool NeedPipe() const;
+    // implementation only (for wxExecute)
+    void SetPipeStreams(wxInputStream *inStream, wxOutputStream *outStream);
 
 protected:
+    void Init(wxEvtHandler *parent, int id, bool redirect);
+
     int m_id;
-    bool m_needPipe;
-    wxInputStream *m_in_stream;
-    wxOutputStream *m_out_stream;
+
+    wxInputStream  *m_inputStream;
+    wxOutputStream *m_outputStream;
+
+    bool m_redirect;
 };
 
 typedef void (wxObject::*wxProcessEventFunction)(wxProcessEvent&);
index 7004ab2359457dca43d9b4934815b1ddd26a1b66..2e57b4ce7b3e3c651b89b87ba90965ad3ff7a821 100644 (file)
@@ -38,12 +38,8 @@ WXDLLEXPORT wxOutputStream& wxEndL(wxOutputStream& o_stream);
 // wxStream: base classes
 // ---------------------------------------------------------------------------
 
-#define wxStream_NOERROR    wxSTREAM_NOERROR
-#define wxStream_EOF        wxSTREAM_EOF
-#define wxStream_WRITE_ERR  wxSTREAM_WRITE_ERROR
-#define wxStream_READ_ERR   wxSTREAM_READ_ERROR
-
-typedef enum {
+typedef enum
+{
   wxSTREAM_NO_ERROR = 0,
   wxSTREAM_NO_ERR = wxSTREAM_NO_ERROR,
   wxSTREAM_NOERROR = wxSTREAM_NO_ERROR,
@@ -58,14 +54,24 @@ typedef enum {
 
 } wxStreamError;
 
+// compatibility
+#define wxStream_NOERROR    wxSTREAM_NOERROR
+#define wxStream_EOF        wxSTREAM_EOF
+#define wxStream_WRITE_ERR  wxSTREAM_WRITE_ERROR
+#define wxStream_READ_ERR   wxSTREAM_READ_ERROR
+
 class WXDLLEXPORT wxStreamBase
 {
 public:
     wxStreamBase();
     virtual ~wxStreamBase();
 
-    bool operator!() const { return (LastError() != wxSTREAM_NOERROR); }
+    // error testing
     wxStreamError LastError() const { return m_lasterror; }
+    wxStreamError GetLastError() const { return m_lasterror; }
+    bool IsOk() const { return LastError() == wxSTREAM_NOERROR; }
+    bool operator!() const { return LastError() != wxSTREAM_NOERROR; }
+
     virtual size_t GetSize() const { return ~((size_t)0); }
     size_t StreamSize() const { return GetSize(); }
 
@@ -87,6 +93,9 @@ public:
     wxInputStream();
     virtual ~wxInputStream();
 
+    // is the stream at EOF?
+    virtual bool Eof() const;
+
     // IO functions
     virtual char Peek();
     char GetC();
index 7893bd1700e603324514eba2c3da9288b03f1925..8be9b245f3d3b42adb7552e40871726123808283 100644 (file)
@@ -39,6 +39,7 @@
 class WXDLLEXPORT wxProcess;
 class WXDLLEXPORT wxFrame;
 class WXDLLEXPORT wxWindow;
+class WXDLLEXPORT wxWindowList;
 
 // FIXME should use wxStricmp() instead
 #if defined(__GNUWIN32__)
@@ -146,6 +147,9 @@ WXDLLEXPORT long wxExecute(wxChar **argv, bool sync = FALSE,
 WXDLLEXPORT long wxExecute(const wxString& command, bool sync = FALSE,
                            wxProcess *process = (wxProcess *) NULL);
 
+// execute the command capturing its output into an array line by line
+WXDLLEXPORT long wxExecute(const wxString& command, wxArrayString& output);
+
 enum wxSignal
 {
     wxSIGNONE = 0,  // verify if the process exists under Unix
@@ -272,6 +276,18 @@ WXDLLEXPORT bool wxCheckForInterrupt(wxWindow *wnd);
 // Consume all events until no more left
 WXDLLEXPORT void wxFlushEvents();
 
+// a class which disables all windows (except, may be, thegiven one) in its
+// ctor and enables them back in its dtor
+class WXDLLEXPORT wxWindowDisabler
+{
+public:
+    wxWindowDisabler(wxWindow *winToSkip = (wxWindow *)NULL);
+    ~wxWindowDisabler();
+
+private:
+    wxWindowList *m_winDisabled;
+};
+
 // ----------------------------------------------------------------------------
 // Cursors
 // ----------------------------------------------------------------------------
index 9017978836542f6633876690406b5bb6246a8e20..0bc3b509aee8a95e9a3bbd68d9b8c8e980892669 100644 (file)
@@ -66,6 +66,10 @@ public:
     virtual bool OnInit();
 };
 
+// Define an array of process pointers used by MyFrame
+class MyPipedProcess;
+WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray);
+
 // Define a new frame type: this is going to be our main frame
 class MyFrame : public wxFrame
 {
@@ -86,7 +90,12 @@ public:
 
     void OnAbout(wxCommandEvent& event);
 
+    // polling output of async processes
+    void OnIdle(wxIdleEvent& event);
+
     // for MyPipedProcess
+    void OnProcessTerminated(MyPipedProcess *process)
+        { m_running.Remove(process); }
     wxListBox *GetLogListBox() const { return m_lbox; }
 
 private:
@@ -94,6 +103,8 @@ private:
 
     wxListBox *m_lbox;
 
+    MyProcessesArray m_running;
+
     // any class wishing to process wxWindows events must use this macro
     DECLARE_EVENT_TABLE()
 };
@@ -125,10 +136,12 @@ public:
     MyPipedProcess(MyFrame *parent, const wxString& cmd)
         : MyProcess(parent, cmd)
         {
-            m_needPipe = TRUE;
+            Redirect();
         }
 
     virtual void OnTerminate(int pid, int status);
+
+    bool HasInput();
 };
 
 // ----------------------------------------------------------------------------
@@ -169,6 +182,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
 
     EVT_MENU(Exec_About, MyFrame::OnAbout)
+
+    EVT_IDLE(MyFrame::OnIdle)
 END_EVENT_TABLE()
 
 // Create a new application object: this macro will allow wxWindows to create
@@ -347,17 +362,58 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
     if ( !cmd )
         return;
 
-    wxProcess *process = new MyPipedProcess(this, cmd);
-    if ( !wxExecute(cmd, FALSE /* async */, process) )
+    bool sync;
+    switch ( wxMessageBox(_T("Execute it synchronously?"),
+                          _T("Exec question"),
+                          wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
     {
-        wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+        case wxYES:
+            sync = TRUE;
+            break;
 
-        delete process;
+        case wxNO:
+            sync = FALSE;
+            break;
+
+        default:
+            return;
     }
-    else
+
+    if ( sync )
     {
-        m_cmdLast = cmd;
+        wxArrayString output;
+        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]);
+            }
+        }
+    }
+    else // async exec
+    {
+        MyPipedProcess *process = new MyPipedProcess(this, cmd);
+        if ( !wxExecute(cmd, FALSE /* async */, process) )
+        {
+            wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+
+            delete process;
+        }
+        else
+        {
+            m_running.Add(process);
+        }
     }
+
+    m_cmdLast = cmd;
 }
 
 void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
@@ -402,6 +458,19 @@ void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
 #endif // __WINDOWS__
 }
 
+// input polling
+void MyFrame::OnIdle(wxIdleEvent& event)
+{
+    size_t count = m_running.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        if ( m_running[n]->HasInput() )
+        {
+            event.RequestMore();
+        }
+    }
+}
+
 // ----------------------------------------------------------------------------
 // MyProcess
 // ----------------------------------------------------------------------------
@@ -415,17 +484,38 @@ void MyProcess::OnTerminate(int pid, int status)
     delete this;
 }
 
-void MyPipedProcess::OnTerminate(int pid, int status)
+// ----------------------------------------------------------------------------
+// MyPipedProcess
+// ----------------------------------------------------------------------------
+
+bool MyPipedProcess::HasInput()
 {
-    // show the program output
-    wxListBox *lbox = m_parent->GetLogListBox();
-    lbox->Append(wxString::Format(_T("--- Output of '%s' ---"), m_cmd.c_str()));
+    wxInputStream& is = *GetInputStream();
+    if ( !is.Eof() )
+    {
+        wxTextInputStream tis(is);
+
+        // this assumes that the output is always line buffered
+        wxString msg;
+        msg << m_cmd << _T(": ") << tis.ReadLine();
 
-    wxTextInputStream tis(*m_in_stream);
-    while ( !m_in_stream->LastError() )
+        m_parent->GetLogListBox()->Append(msg);
+
+        return TRUE;
+    }
+    else
     {
-        lbox->Append(tis.ReadLine());
+        return FALSE;
     }
+}
+
+void MyPipedProcess::OnTerminate(int pid, int status)
+{
+    // show the rest of the output
+    while ( HasInput() )
+        ;
+
+    m_parent->OnProcessTerminated(this);
 
     MyProcess::OnTerminate(pid, status);
 }
index e573fe8e0d995ba5682845f407c927d3a27cda94..dd80b31466da578a781607ecdaec59147908ffc2 100644 (file)
 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;
-}
index ef92a1807a3b977facd144fa84b1a546d37644e4..310f1ee7e09eb77b4353f57a6611348a9baa51e5 100644 (file)
@@ -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;
index cd0300b42df8532acd16b8fba338a9cd309ee2f1..ae71ae5d219da1a2b2176878960d80a921e7be0c 100644 (file)
@@ -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;
 }
 
index fbcad04649eec361577d3ff0657006db3a78f199..3f62793a9eb1930cd8b1b42371f8619e1ff288ed 100644 (file)
@@ -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);
     }
 }
 
-// Yield to other apps/messages and disable user input to all windows except
-// the given one
-bool wxSafeYield(wxWindow *win)
+wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
 {
     // remember all windows we're going to (temporarily) disable
-    wxWindowList winDisabled;
+    m_winDisabled = new wxWindowList;
 
     wxWindowList::Node *node;
     for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
     {
         wxWindow *winTop = node->GetData();
-        wxFindDisabledWindows(winDisabled, winTop);
+        if ( winTop->IsEnabled() )
+        {
+            wxFindDisabledWindows(*m_winDisabled, winTop);
 
-        winTop->Disable();
+            m_winDisabled->Append(winTop);
+            winTop->Disable();
+        }
     }
 
-    if ( win )
+    if ( winToSkip && m_winDisabled->Find(winToSkip) )
     {
         // always enable ourselves
-        win->Enable();
+        m_winDisabled->DeleteObject(winToSkip);
+        winToSkip->Enable();
     }
+}
 
-    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() )
+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)
+{
+    wxWindowDisabler wd;
+
+    bool rc = wxYield();
+
     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;
+}
index 411eaeaf44c33cfcc8d4ee1229b8b1561502fffb..4a5489086c3efd9648841a8c1b18b92016d0305f 100644 (file)
@@ -158,7 +158,7 @@ protected:
 wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
 {
     m_hInput = hInput;
-}   
+}
 
 wxPipeInputStream::~wxPipeInputStream()
 {
@@ -186,7 +186,7 @@ size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
 wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
 {
     m_hOutput = hOutput;
-}   
+}
 
 wxPipeOutputStream::~wxPipeOutputStream()
 {
@@ -401,32 +401,36 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 
     return result;
 #else // 1
-                     
+
     HANDLE h_readPipe[2];
     HANDLE h_writePipe[2];
     HANDLE h_oldreadPipe;
     HANDLE h_oldwritePipe;
     BOOL inheritHandles;
 
-    // ------------------------------------
-    // Pipe handling
-    // We are in the case of opening a pipe
+    // open the pipes to which child process IO will be redirected if needed
     inheritHandles = FALSE;
-    if (handler && handler->NeedPipe()) {
+    if ( handler && handler->IsRedirected() )
+    {
         SECURITY_ATTRIBUTES security;
 
         security.nLength              = sizeof(security);
         security.lpSecurityDescriptor = NULL;
         security.bInheritHandle       = TRUE;
 
-        if (! ::CreatePipe(&h_readPipe[0], &h_readPipe[1], &security, 0) ) {
-            wxLogSysError(_T("Can't create the inter-process read pipe"));
+        if (! ::CreatePipe(&h_readPipe[0], &h_readPipe[1], &security, 0) )
+        {
+            wxLogSysError(_("Can't create the inter-process read pipe"));
 
             return 0;
         }
 
-        if (! ::CreatePipe(&h_writePipe[0], &h_writePipe[1], &security, 0) ) {
-            wxLogSysError(_T("Can't create the inter-process read pipe"));
+        if (! ::CreatePipe(&h_writePipe[0], &h_writePipe[1], &security, 0) )
+        {
+            ::CloseHandle(h_readPipe[0]);
+            ::CloseHandle(h_readPipe[1]);
+
+            wxLogSysError(_("Can't create the inter-process write pipe"));
 
             return 0;
         }
@@ -464,12 +468,14 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
                          &pi         // process info
                         ) == 0 )
     {
-        if (inheritHandles) {
+        if ( inheritHandles )
+        {
             ::CloseHandle(h_writePipe[0]);
             ::CloseHandle(h_writePipe[1]);
             ::CloseHandle(h_readPipe[0]);
             ::CloseHandle(h_readPipe[1]);
         }
+
         wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
 
         return 0;
@@ -589,16 +595,17 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 
     // waiting until command executed (disable everything while doing it)
 #if wxUSE_GUI
-    wxBeginBusyCursor();
-    wxEnableTopLevelWindows(FALSE);
+    {
+        wxBusyCursor bc;
+
+        wxWindowDisabler wd;
 #endif // wxUSE_GUI
 
     while ( data->state )
         wxYield();
 
 #if wxUSE_GUI
-    wxEnableTopLevelWindows(TRUE);
-    wxEndBusyCursor();
+    }
 #endif // wxUSE_GUI
 
     DWORD dwExitCode = data->dwExitCode;
index fe4abae50e27af316e99f050b2c25c83515d964a..d8925aba2bd6be084936205a46233e56551251e7 100644 (file)
@@ -208,8 +208,8 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process )
 bool wxShell(const wxString& command)
 {
     wxString cmd;
-    if ( !!command )
-        cmd.Printf(wxT("xterm -e %s"), command.c_str());
+    if ( !command )
+        cmd = _T("xterm");
     else
         cmd = command;
 
@@ -270,92 +270,109 @@ void wxHandleProcessTermination(wxEndProcessData *proc_data)
 
 #endif // wxUSE_GUI
 
-#if wxUSE_GUI
-    #define WXUNUSED_UNLESS_GUI(p)  p
-#else
-    #define WXUNUSED_UNLESS_GUI(p)
-#endif
+// ----------------------------------------------------------------------------
+// wxStream classes to support IO redirection in wxExecute
+// ----------------------------------------------------------------------------
 
-// New wxStream classes to clean up the data when the process terminates
+class wxProcessFileInputStream : public wxInputStream
+{
+public:
+    wxProcessFileInputStream(int fd) { m_fd = fd; }
+    ~wxProcessFileInputStream() { close(m_fd); }
 
-#if wxUSE_GUI
-class wxProcessFileInputStream: public wxInputStream {
- public:
-    wxProcessFileInputStream(int fd);
-    ~wxProcessFileInputStream();
+    virtual bool Eof() const;
 
- protected: 
+protected:
     size_t OnSysRead(void *buffer, size_t bufsize);
 
- protected:
+protected:
     int m_fd;
 };
 
-class wxProcessFileOutputStream: public wxOutputStream {
- public:
-    wxProcessFileOutputStream(int fd);
-    ~wxProcessFileOutputStream();
+class wxProcessFileOutputStream : public wxOutputStream
+{
+public:
+    wxProcessFileOutputStream(int fd) { m_fd = fd; }
+    ~wxProcessFileOutputStream() { close(m_fd); }
 
- protected:
+protected:
     size_t OnSysWrite(const void *buffer, size_t bufsize);
 
- protected:
+protected:
     int m_fd;
 };
 
-wxProcessFileInputStream::wxProcessFileInputStream(int fd)
+bool wxProcessFileInputStream::Eof() const
 {
-    m_fd = fd;
-}
+    if ( m_lasterror == wxSTREAM_EOF )
+        return TRUE;
 
-wxProcessFileInputStream::~wxProcessFileInputStream()
-{
-    close(m_fd);
-}
+    // check if there is any input available
+    struct timeval tv;
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
 
-size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
-{
-    int ret;
-
-    ret = read(m_fd, buffer, bufsize);
-    m_lasterror = wxSTREAM_NOERROR;
-    if (ret == 0)
-      m_lasterror = wxSTREAM_EOF;
-    if (ret == -1) {
-      m_lasterror = wxSTREAM_READ_ERROR;
-      ret = 0;
+    fd_set readfds;
+    FD_ZERO(&readfds);
+    FD_SET(m_fd, &readfds);
+    switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
+    {
+        case -1:
+            wxLogSysError(_("Impossible to get child process input"));
+            // fall through
+
+        case 0:
+            return TRUE;
+
+        default:
+            wxFAIL_MSG(_T("unexpected select() return value"));
+            // still fall through
+
+        case 1:
+            // input available: check if there is any
+            return wxInputStream::Eof();
     }
-    return ret;
 }
 
-wxProcessFileOutputStream::wxProcessFileOutputStream(int fd)
+size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
 {
-    m_fd = fd;
-}
+    int ret = read(m_fd, buffer, bufsize);
+    if ( ret == 0 )
+    {
+        m_lasterror = wxSTREAM_EOF;
+    }
+    else if ( ret == -1 )
+    {
+        m_lasterror = wxSTREAM_READ_ERROR;
+        ret = 0;
+    }
+    else
+    {
+        m_lasterror = wxSTREAM_NOERROR;
+    }
 
-wxProcessFileOutputStream::~wxProcessFileOutputStream()
-{
-    close(m_fd);
+    return ret;
 }
 
 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
 {
-    int ret;
-
-    ret = write(m_fd, buffer, bufsize);
-    m_lasterror = wxSTREAM_NOERROR;
-    if (ret == -1) {
-      m_lasterror = wxSTREAM_WRITE_ERROR;
-      ret = 0;
+    int ret = write(m_fd, buffer, bufsize);
+    if ( ret == -1 )
+    {
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+        ret = 0;
+    }
+    else
+    {
+        m_lasterror = wxSTREAM_NOERROR;
     }
+
     return ret;
 }
 
-#endif
-      
 long wxExecute(wxChar **argv,
                bool sync,
-               wxProcess * WXUNUSED_UNLESS_GUI(process))
+               wxProcess *process)
 {
     wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
 
@@ -365,9 +382,9 @@ long wxExecute(wxChar **argv,
 
     while (argv[mb_argc])
     {
-      wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
-      mb_argv[mb_argc] = strdup(mb_arg);
-      mb_argc++;
+        wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
+        mb_argv[mb_argc] = strdup(mb_arg);
+        mb_argc++;
     }
     mb_argv[mb_argc] = (char *) NULL;
 
@@ -385,9 +402,10 @@ long wxExecute(wxChar **argv,
 #if wxUSE_GUI
     // create pipes
     int end_proc_detect[2];
-    if (pipe(end_proc_detect) == -1)
+    if ( pipe(end_proc_detect) == -1 )
     {
         wxLogSysError( _("Pipe creation failed") );
+        wxLogError( _("Failed to execute '%s'\n"), *argv );
 
         ARGS_CLEANUP;
 
@@ -395,25 +413,29 @@ long wxExecute(wxChar **argv,
     }
 #endif // wxUSE_GUI
 
-#if wxUSE_GUI
-    int in_pipe[2] = { -1, -1 };
-    int out_pipe[2] = { -1, -1 };
-    // Only asynchronous mode is interresting
-    if (!sync && process && process->NeedPipe())
+    int pipeIn[2];
+    int pipeOut[2];
+    pipeIn[0] = pipeIn[1] =
+    pipeOut[0] = pipeOut[1] = -1;
+
+    if ( process && process->IsRedirected() )
     {
-        if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1)
+        if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 )
         {
-            /* Free fds */
+#if wxUSE_GUI
+            // free previously allocated resources
             close(end_proc_detect[0]);
             close(end_proc_detect[1]);
-            wxLogSysError( _("Pipe creation failed (Console pipes)") );
+#endif // wxUSE_GUI
+
+            wxLogSysError( _("Pipe creation failed") );
+            wxLogError( _("Failed to execute '%s'\n"), *argv );
 
             ARGS_CLEANUP;
 
             return 0;
         }
     }
-#endif // wxUSE_GUI
 
     // fork the process
 #ifdef HAVE_VFORK
@@ -421,93 +443,108 @@ long wxExecute(wxChar **argv,
 #else
     pid_t pid = fork();
 #endif
-    if (pid == -1)
+
+    if ( pid == -1 )     // error?
     {
 #if wxUSE_GUI
         close(end_proc_detect[0]);
         close(end_proc_detect[1]);
-        close(in_pipe[0]);
-        close(in_pipe[1]);
-        close(out_pipe[0]);
-        close(out_pipe[1]);
-#endif
+        close(pipeIn[0]);
+        close(pipeIn[1]);
+        close(pipeOut[0]);
+        close(pipeOut[1]);
+#endif // wxUSE_GUI
+
         wxLogSysError( _("Fork failed") );
 
         ARGS_CLEANUP;
 
         return 0;
     }
-    else if (pid == 0)
+    else if ( pid == 0 )  // we're in child
     {
 #if wxUSE_GUI
-        // we're in child
         close(end_proc_detect[0]); // close reading side
 #endif // wxUSE_GUI
 
-        // These three lines close the open file descriptors to to avoid any
+        // These lines close the open file descriptors to to avoid any
         // input/output which might block the process or irritate the user. If
-        // one wants proper IO for the subprocess, the right thing to do is
-        // to start an xterm executing it.
-        if (sync == 0)
+        // one wants proper IO for the subprocess, the right thing to do is to
+        // start an xterm executing it.
+        if ( !sync )
         {
-            // leave stderr opened, it won't do any hurm
             for ( int fd = 0; fd < FD_SETSIZE; fd++ )
             {
+                if ( fd == pipeIn[0] || fd == pipeOut[1]
 #if wxUSE_GUI
-                if ( fd == end_proc_detect[1] || fd == in_pipe[0] || fd == out_pipe[1] )
-                    continue;
+                     || fd == end_proc_detect[1]
 #endif // wxUSE_GUI
+                   )
+                {
+                    // don't close this one, we still need it
+                    continue;
+                }
 
+                // leave stderr opened too, it won't do any hurm
                 if ( fd != STDERR_FILENO )
                     close(fd);
             }
         }
 
-        // Fake a console by duplicating pipes
-#if wxUSE_GUI
-        if (in_pipe[0] != -1) {
-            dup2(in_pipe[0], STDIN_FILENO);
-            dup2(out_pipe[1], STDOUT_FILENO);
-            close(in_pipe[0]);
-            close(out_pipe[1]);
-        }
-#endif // wxUSE_GUI
-
-#if 0
-        close(STDERR_FILENO);
+        // redirect stdio and stdout
+        // (TODO: what about stderr?)
+        if ( pipeIn[0] != -1 )
+        {
+            if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
+                 dup2(pipeOut[1], STDOUT_FILENO) == -1 )
+            {
+                wxLogSysError(_("Failed to redirect child process "
+                                "input/output"));
+            }
 
-        // some programs complain about stderr not being open, so redirect
-        // them:
-        open("/dev/null", O_RDONLY);  // stdin
-        open("/dev/null", O_WRONLY);  // stdout
-        open("/dev/null", O_WRONLY);  // stderr
-#endif
+            close(pipeIn[0]);
+            close(pipeOut[1]);
+        }
 
         execvp (*mb_argv, mb_argv);
 
         // there is no return after successful exec()
-        wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
-
         _exit(-1);
     }
-    else
+    else // we're in parent
     {
+        ARGS_CLEANUP;
+
+        // pipe initialization: construction of the wxStreams
+        if ( process && process->IsRedirected() )
+        {
+            // These two streams are relative to this process.
+            wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
+            wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
+            close(pipeIn[0]); // close reading side
+            close(pipeOut[1]); // close writing side
+
+            process->SetPipeStreams(inStream, outStream);
+        }
+
 #if wxUSE_GUI
         wxEndProcessData *data = new wxEndProcessData;
 
-        ARGS_CLEANUP;
-
         if ( sync )
         {
-            wxASSERT_MSG( !process, wxT("wxProcess param ignored for sync exec") );
+            // we may have process for capturing the program output, but it's
+            // not used in wxEndProcessData in the case of sync execution
             data->process = NULL;
 
             // sync execution: indicate it by negating the pid
-            data->pid      = -pid;
-            data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
-            // we're in parent
+            data->pid = -pid;
+            data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
+
             close(end_proc_detect[1]); // close writing side
 
+            wxBusyCursor bc;
+            wxWindowDisabler wd;
+
             // it will be set to 0 from GTK_EndProcessDetector
             while (data->pid != 0)
                 wxYield();
@@ -518,29 +555,15 @@ long wxExecute(wxChar **argv,
 
             return exitcode;
         }
-        else
+        else // async execution
         {
-            // pipe initialization: construction of the wxStreams
-            if (process && process->NeedPipe()) {
-                // These two streams are relative to this process.
-                wxOutputStream *my_output_stream;
-                wxInputStream *my_input_stream;
-
-                my_output_stream = new wxProcessFileOutputStream(in_pipe[1]);
-                my_input_stream = new wxProcessFileInputStream(out_pipe[0]);
-                close(in_pipe[0]); // close reading side
-                close(out_pipe[1]); // close writing side
-
-                process->SetPipeStreams(my_input_stream, my_output_stream);
-            }
-
             // async execution, nothing special to do - caller will be
             // notified about the process termination if process != NULL, data
             // will be deleted in GTK_EndProcessDetector
             data->process  = process;
             data->pid      = pid;
             data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
-            // we're in parent
+
             close(end_proc_detect[1]); // close writing side
 
             return pid;
@@ -557,7 +580,8 @@ long wxExecute(wxChar **argv,
         return exitcode;
 #endif // wxUSE_GUI
     }
-   return 0;
+
+    return 0;
 
     #undef ARGS_CLEANUP
 }