diff --git a/docs/latex/wx/process.tex b/docs/latex/wx/process.tex index 95cf13eb19..9438d0433e 100644 --- a/docs/latex/wx/process.tex +++ b/docs/latex/wx/process.tex @@ -62,6 +62,15 @@ macro in the event table of the parent to handle it) with the given {\it id}. Destroys the wxProcess object. +\membersection{wxProcess::CloseOutput}\label{wxprocesscloseoutput} + +\func{void}{CloseOutput}{\void} + +Closes the output stream (the one connected to the stdin of the child +process). This function can be used to indicate to the child process that +there is no more data to be read - usually, a filter program will only +terminate when the input stream is closed. + \membersection{wxProcess::Detach}\label{wxprocessdetach} \func{void}{Detach}{\void} diff --git a/include/wx/process.h b/include/wx/process.h index e2c76856b0..ea2fc303d8 100644 --- a/include/wx/process.h +++ b/include/wx/process.h @@ -81,6 +81,9 @@ public: wxInputStream *GetErrorStream() const { return m_errorStream; } wxOutputStream *GetOutputStream() const { return m_outputStream; } + // close the output stream indicating that nothing more will be written + void CloseOutput() { delete m_outputStream; m_outputStream = NULL; } + // implementation only (for wxExecute) void SetPipeStreams(wxInputStream *inStream, wxOutputStream *outStream, diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index aa717d4c4b..e8483a828a 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -86,6 +86,8 @@ public: void OnAsyncExec(wxCommandEvent& event); void OnShell(wxCommandEvent& event); void OnExecWithRedirect(wxCommandEvent& event); + void OnExecWithPipe(wxCommandEvent& event); + void OnDDEExec(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -144,7 +146,23 @@ public: virtual void OnTerminate(int pid, int status); - bool HasInput(); + virtual bool HasInput(); +}; + +// A version of MyPipedProcess which also sends input to the stdin of the +// child process +class MyPipedProcess2 : public MyPipedProcess +{ +public: + MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input) + : MyPipedProcess(parent, cmd), m_input(input) + { + } + + virtual bool HasInput(); + +private: + wxString m_input; }; // ---------------------------------------------------------------------------- @@ -162,6 +180,7 @@ enum Exec_Shell, Exec_DDEExec, Exec_Redirect, + Exec_Pipe, Exec_About = 300 }; @@ -182,6 +201,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec) EVT_MENU(Exec_Shell, MyFrame::OnShell) EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect) + EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe) + EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec) EVT_MENU(Exec_About, MyFrame::OnAbout) @@ -249,8 +270,11 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) _T("Launch a program and return immediately")); execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"), _T("Launch a shell and execute a command in it")); + execMenu->AppendSeparator(); execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"), _T("Launch a program and capture its output")); + execMenu->Append(Exec_Pipe, _T("&Pipe through command...\tCtrl-P"), + _T("Pipe a string through a filter")); #ifdef __WINDOWS__ execMenu->AppendSeparator(); @@ -386,7 +410,7 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) if ( sync ) { wxArrayString output, errors; - int code = wxExecute(cmd, output); + int code = wxExecute(cmd, output, errors); wxLogStatus(_T("command '%s' terminated with exit code %d."), cmd.c_str(), code); @@ -414,6 +438,42 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) m_cmdLast = cmd; } +void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event)) +{ + if ( !m_cmdLast ) + m_cmdLast = _T("tr [a-z] [A-Z]"); + + wxString cmd = wxGetTextFromUser(_T("Enter the command: "), + DIALOG_TITLE, + m_cmdLast); + + if ( !cmd ) + return; + + wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "), + DIALOG_TITLE); + if ( !input ) + return; + + // always execute the filter asynchronously + MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input); + int pid = wxExecute(cmd, FALSE /* async */, process); + if ( pid ) + { + wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str()); + + m_running.Add(process); + } + else + { + wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); + + delete process; + } + + m_cmdLast = cmd; +} + void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) { #ifdef __WINDOWS__ @@ -556,3 +616,24 @@ void MyPipedProcess::OnTerminate(int pid, int status) MyProcess::OnTerminate(pid, status); } + +// ---------------------------------------------------------------------------- +// MyPipedProcess2 +// ---------------------------------------------------------------------------- + +bool MyPipedProcess2::HasInput() +{ + if ( !!m_input ) + { + wxTextOutputStream os(*GetOutputStream()); + os.WriteString(m_input); + + CloseOutput(); + m_input.clear(); + + // call us once again - may be we'll have output + return TRUE; + } + + return MyPipedProcess::HasInput(); +} diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index b27a76a82e..0b30edea65 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -397,7 +397,11 @@ long wxExecute(wxChar **argv, bool sync, wxProcess *process) { - wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") ); + // for the sync execution, we return -1 to indicate failure, but for async + // cse we return 0 which is never a valid PID + long errorRetCode = sync ? -1 : 0; + + wxCHECK_MSG( *argv, errorRetCode, wxT("can't exec empty command") ); #if wxUSE_UNICODE int mb_argc = 0; @@ -432,7 +436,7 @@ long wxExecute(wxChar **argv, ARGS_CLEANUP; - return 0; + return errorRetCode; } #endif // wxUSE_GUI @@ -460,7 +464,7 @@ long wxExecute(wxChar **argv, ARGS_CLEANUP; - return 0; + return errorRetCode; } } @@ -488,7 +492,7 @@ long wxExecute(wxChar **argv, ARGS_CLEANUP; - return 0; + return errorRetCode; } else if ( pid == 0 ) // we're in child { @@ -612,12 +616,10 @@ long wxExecute(wxChar **argv, return exitcode; #endif // wxUSE_GUI } - - return 0; - - #undef ARGS_CLEANUP } +#undef ARGS_CLEANUP + // ---------------------------------------------------------------------------- // file and directory functions // ----------------------------------------------------------------------------