+#if wxUSE_STREAMS
+
+// A wxFFileInputStream that deletes the file in it's destructor
+//
+class wxTempFileInStream : public wxFFileInputStream
+{
+public:
+ wxTempFileInStream(const wxString& name)
+ : wxFFileInputStream(name, _T("rt"))
+ { }
+
+ ~wxTempFileInStream()
+ {
+ m_file->Close();
+ wxRemoveFile(m_file->GetName());
+ }
+};
+
+// A file descriptor that can be redirected to a file
+//
+class wxRedirectableFd
+{
+public:
+ wxRedirectableFd(int fd) : m_fd(fd), m_dup(-1) { }
+ ~wxRedirectableFd();
+
+ // Redirect the descriptor to a file, similar to ANSI C's freopen, but
+ // for low level descriptors. The desctructor un-redirects. If O_CREAT
+ // is in the flags then the destructor will delete the file unless it is
+ // given away with Release().
+ bool Reopen(const wxString& name, int flags);
+
+ // un-redirect the redirected file descriptor, closing the file, and give
+ // away the filename without deleting it
+ wxString Release();
+
+private:
+ // un-redirect the descriptor, closing the file
+ void Restore();
+
+ int m_fd;
+ int m_dup;
+ wxString m_name;
+};
+
+wxRedirectableFd::~wxRedirectableFd()
+{
+ Restore();
+ if (!m_name.empty())
+ wxRemoveFile(m_name);
+}
+
+bool wxRedirectableFd::Reopen(const wxString& name, int flags)
+{
+ wxASSERT(m_dup == -1);
+ bool result = false;
+
+ // save a duplicate so that the descriptor can be closed now and
+ // restored later
+ m_dup = dup(m_fd);
+
+ if (m_dup != -1)
+ {
+ int tmp = open(name.mb_str(), flags);
+
+ if (tmp != -1)
+ {
+ close(m_fd);
+
+ if (flags & O_CREAT)
+ m_name = name;
+
+ result = dup2(tmp, m_fd) == m_fd;
+ close(tmp);
+ }
+ }
+
+ if (!result)
+ wxLogSysError(_("error opening '%s'"), name.c_str());
+
+ return result;
+}
+
+void wxRedirectableFd::Restore()
+{
+ if (m_dup != -1)
+ {
+ close(m_fd);
+ dup2(m_dup, m_fd);
+ close(m_dup);
+ m_dup = -1;
+ }
+}
+
+wxString wxRedirectableFd::Release()
+{
+ Restore();
+ wxString name = m_name;
+ m_name.clear();
+ return name;
+}
+
+#endif // wxUSE_STREAMS
+
+// wxExecute implementation
+//
+long wxExecute(wxChar **argv, int flags, wxProcess *process)
+{
+#if wxUSE_STREAMS
+ const int STDIN = 0;
+ const int STDOUT = 1;
+ const int STDERR = 2;
+
+ wxRedirectableFd in(STDIN), out(STDOUT), err(STDERR);
+ bool redirect = process && process->IsRedirected() && (flags & wxEXEC_SYNC);
+
+ if (redirect)
+ {
+ // close stdin/out/err and reopen them as files
+ if (!in.Reopen(_T("NUL"), O_RDONLY | O_TEXT))
+ return -1;
+
+ if (!out.Reopen(wxFileName::CreateTempFileName(_T("out")),
+ O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
+ return -1;
+
+ if (!err.Reopen(wxFileName::CreateTempFileName(_T("err")),
+ O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
+ return -1;
+ }
+#endif // wxUSE_STREAMS
+
+ // FIXME: suspend/resume gui
+ int mode = flags & wxEXEC_SYNC ? P_WAIT : P_NOWAIT;
+ int result = spawnvp(mode, argv[0], argv);
+
+ if (result == -1)
+ wxLogSysError(_("can't execute '%s'"), argv[0]);
+
+#if wxUSE_STREAMS
+ if (redirect)
+ process->SetPipeStreams(new wxTempFileInStream(out.Release()),
+ new wxFFileOutputStream(_T("NUL"), _T("wt")),
+ new wxTempFileInStream(err.Release()));
+#endif // wxUSE_STREAMS
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+// Traits for console apps
+//----------------------------------------------------------------------------
+