]> git.saurik.com Git - wxWidgets.git/commitdiff
Add support for specifying child process cwd and env to wxExecute().
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 24 Oct 2010 22:40:11 +0000 (22:40 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 24 Oct 2010 22:40:11 +0000 (22:40 +0000)
Add an optional wxExecuteEnv parameter to wxExecute() which allows to specify
the initial working directory and custom environment for the child process.

Closes #12163.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65896 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/utils.h
interface/wx/utils.h
samples/exec/exec.cpp
src/cocoa/utilsexc.mm
src/common/utilscmn.cpp
src/msdos/utilsdos.cpp
src/msw/utilsexc.cpp
src/os2/utilsexc.cpp
src/palmos/utilsexc.cpp
src/unix/utilsunx.cpp

index e189246df531d5f222a3b978b5ade16f84656236..b34dfa11bc6ef07e87116fb15de5810f2daa53c4 100644 (file)
@@ -405,6 +405,7 @@ Major new features in this release
 
 All:
 
+- Added cwd and env arguments to wxExecute() (Emilien Kia).
 - Added "rest" argument to wxString::Before{First,Last}().
 - Added wxThread::OnKill() and OnDelete() callbacks.
 
index 32bed656c30d6c3e25f1d22ca964b21ce05b4f88..78f29a0063319473ae5947670859d80a3f58f4da 100644 (file)
@@ -19,6 +19,7 @@
 #include "wx/object.h"
 #include "wx/list.h"
 #include "wx/filefn.h"
+#include "wx/hashmap.h"
 
 #if wxUSE_GUI
     #include "wx/gdicmn.h"
@@ -313,6 +314,17 @@ enum
     wxEXEC_BLOCK = wxEXEC_SYNC | wxEXEC_NOEVENTS
 };
 
+// Map storing environment variables.
+typedef wxStringToStringHashMap wxEnvVariableHashMap;
+
+// Used to pass additional parameters for child process to wxExecute(). Could
+// be extended with other fields later.
+struct wxExecuteEnv
+{
+    wxString cwd;               // If empty, CWD is not changed.
+    wxEnvVariableHashMap env;   // If empty, environment is unchanged.
+};
+
 // Execute another program.
 //
 // If flags contain wxEXEC_SYNC, return -1 on failure and the exit code of the
@@ -320,27 +332,32 @@ enum
 // failure and the PID of the launched process if ok.
 WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
                                 int flags = wxEXEC_ASYNC,
-                                wxProcess *process = NULL);
+                                wxProcess *process = NULL,
+                                const wxExecuteEnv *env = NULL);
 WXDLLIMPEXP_BASE long wxExecute(char **argv,
                                 int flags = wxEXEC_ASYNC,
-                                wxProcess *process = NULL);
+                                wxProcess *process = NULL,
+                                const wxExecuteEnv *env = NULL);
 #if wxUSE_UNICODE
 WXDLLIMPEXP_BASE long wxExecute(wchar_t **argv,
                                 int flags = wxEXEC_ASYNC,
-                                wxProcess *process = NULL);
+                                wxProcess *process = NULL,
+                                const wxExecuteEnv *env = NULL);
 #endif // wxUSE_UNICODE
 
 // execute the command capturing its output into an array line by line, this is
 // always synchronous
 WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
                                 wxArrayString& output,
-                                int flags = 0);
+                                int flags = 0,
+                                const wxExecuteEnv *env = NULL);
 
 // also capture stderr (also synchronous)
 WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
                                 wxArrayString& output,
                                 wxArrayString& error,
-                                int flags = 0);
+                                int flags = 0,
+                                const wxExecuteEnv *env = NULL);
 
 #if defined(__WXMSW__) && wxUSE_IPC
 // ask a DDE server to execute the DDE request with given parameters
@@ -479,6 +496,10 @@ inline bool wxSetEnv(const wxString& var, int value)
 }
 #endif // WXWIN_COMPATIBILITY_2_8
 
+// Retrieve the complete environment by filling specified map.
+// Returns true on success or false if an error occurred.
+WXDLLIMPEXP_BASE bool wxGetEnvMap(wxEnvVariableHashMap *map);
+
 // ----------------------------------------------------------------------------
 // Network and username functions.
 // ----------------------------------------------------------------------------
index c09df344ba40bd5ed7e36a05824cb1ed5a77f99c..d62ddf1e925ab3678a9c6733e7b383ccc85f5ff2 100644 (file)
@@ -157,6 +157,18 @@ void wxInfoMessageBox(wxWindow parent = NULL);
 /** @addtogroup group_funcmacro_env */
 //@{
 
+/**
+    A map type containing environment variables names and values.
+
+    This type is used with wxGetEnvMap() function and wxExecuteEnv structure
+    optionally passed to wxExecute().
+
+    @since 2.9.2
+
+    @header{wx/utils.h}
+*/
+typedef wxStringToStringHashMap wxEnvVariableHashMap;
+
 /**
     This is a macro defined as @c getenv() or its wide char version in Unicode
     mode.
@@ -218,6 +230,22 @@ bool wxSetEnv(const wxString& var, const wxString& value);
 */
 bool wxUnsetEnv(const wxString& var);
 
+/**
+    Fill a map with the complete content of current environment.
+
+    The map will contain the environment variable names as keys and their
+    values as values.
+
+    @param map
+        The environment map to fill, must be non-@NULL.
+    @return
+        @true if environment was successfully retrieved or @false otherwise.
+
+    @header{wx/utils.h}
+
+    @since 2.9.2
+*/
+bool wxGetEnvMap(wxEnvVariableHashMap *map);
 //@}
 
 
@@ -735,6 +763,36 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
 /** @addtogroup group_funcmacro_procctrl */
 //@{
 
+/**
+    @struct wxExecuteEnv
+
+    This structure can optionally be passed to wxExecute() to specify
+    additional options to use for the child process.
+
+    @since 2.9.2
+
+    @header{wx/utils.h}
+*/
+struct wxExecuteEnv
+{
+    /**
+        The initial working directory for the new process.
+
+        If this field is empty, the current working directory of this process
+        is used.
+    */
+    wxString cwd;
+
+    /**
+        The environment variable map.
+
+        If the map is empty, the environment variables of the current process
+        are also used for the child one, otherwise only the variables defined
+        in this map are used.
+    */
+    wxEnvVariableHashMap env;
+};
+
 /**
     Executes another program in Unix or Windows.
 
@@ -800,6 +858,10 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
         their combination, in wxEXEC_SYNC case.
     @param callback
         An optional pointer to wxProcess.
+    @param env
+        An optional pointer to additional parameters for the child process,
+        such as its initial working directory and environment variables. This
+        parameter is available in wxWidgets 2.9.2 and later only.
 
     @see wxShell(), wxProcess, @ref page_samples_exec,
          wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -811,8 +873,8 @@ wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
     @endWxPerlOnly
 */
 long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
-                wxProcess* callback = NULL);
-
+                wxProcess* callback = NULL,
+                const wxExecuteEnv* env = NULL);
 //@}
 
 /** @addtogroup group_funcmacro_procctrl */
@@ -835,6 +897,10 @@ long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
         their combination, in wxEXEC_SYNC case.
     @param callback
         An optional pointer to wxProcess.
+    @param env
+        An optional pointer to additional parameters for the child process,
+        such as its initial working directory and environment variables. This
+        parameter is available in wxWidgets 2.9.2 and later only.
 
     @see wxShell(), wxProcess, @ref page_samples_exec,
          wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -846,9 +912,11 @@ long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
     @endWxPerlOnly
 */
 long wxExecute(char** argv, int flags = wxEXEC_ASYNC,
-                wxProcess* callback = NULL);
+                wxProcess* callback = NULL,
+                const wxExecuteEnv *env = NULL);
 long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
-                wxProcess* callback = NULL);
+                wxProcess* callback = NULL,
+                const wxExecuteEnv *env = NULL);
 //@}
 
 /** @addtogroup group_funcmacro_procctrl */
@@ -871,6 +939,10 @@ long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
         May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or
         wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to
         their combination. wxEXEC_SYNC is always implicitly added to the flags.
+    @param env
+        An optional pointer to additional parameters for the child process,
+        such as its initial working directory and environment variables. This
+        parameter is available in wxWidgets 2.9.2 and later only.
 
     @see wxShell(), wxProcess, @ref page_samples_exec,
          wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -883,7 +955,8 @@ long wxExecute(wchar_t** argv, int flags = wxEXEC_ASYNC,
     where @c output in an array reference.
     @endWxPerlOnly
 */
-long wxExecute(const wxString& command, wxArrayString& output, int flags = 0);
+long wxExecute(const wxString& command, wxArrayString& output, int flags = 0,
+                const wxExecuteEnv *env = NULL);
 
 /**
     This is an overloaded version of wxExecute(const wxString&,int,wxProcess*),
@@ -904,6 +977,10 @@ long wxExecute(const wxString& command, wxArrayString& output, int flags = 0);
         May include wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or
         wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to
         their combination. wxEXEC_SYNC is always implicitly added to the flags.
+    @param env
+        An optional pointer to additional parameters for the child process,
+        such as its initial working directory and environment variables. This
+        parameter is available in wxWidgets 2.9.2 and later only.
 
     @see wxShell(), wxProcess, @ref page_samples_exec,
          wxLaunchDefaultApplication(), wxLaunchDefaultBrowser()
@@ -917,7 +994,8 @@ long wxExecute(const wxString& command, wxArrayString& output, int flags = 0);
     @endWxPerlOnly
 */
 long wxExecute(const wxString& command, wxArrayString& output,
-                wxArrayString& errors, int flags = 0);
+                wxArrayString& errors, int flags = 0,
+                const wxExecuteEnv *env = NULL);
 
 /**
     Returns the number uniquely identifying the current process in the system.
index fcbe8b302937394bfa05e72cbfacc6eb7d5d49f0..4f72a17958f6e0dc354aa691ce9ddb1b598801b0 100644 (file)
@@ -43,6 +43,8 @@
     #include "wx/choicdlg.h"
 
     #include "wx/button.h"
+    #include "wx/checkbox.h"
+    #include "wx/stattext.h"
     #include "wx/textctrl.h"
     #include "wx/listbox.h"
 
@@ -666,6 +668,147 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
     }
 }
 
+// ----------------------------------------------------------------------------
+// execution options dialog
+// ----------------------------------------------------------------------------
+
+enum ExecQueryDialogID
+{
+    TEXT_EXECUTABLE,
+    TEXT_CWD,
+    TEXT_ENVIRONMENT
+};
+
+class ExecQueryDialog : public wxDialog
+{
+public:
+    ExecQueryDialog(const wxString& cmd);
+
+    wxString GetExecutable() const
+    {
+        return m_executable->GetValue();
+    }
+
+    wxString GetWorkDir() const
+    {
+        return m_useCWD->GetValue() ? m_cwdtext->GetValue() : wxString();
+    }
+
+    void GetEnvironment(wxEnvVariableHashMap& env);
+
+private:
+    void OnUpdateWorkingDirectoryUI(wxUpdateUIEvent& event)
+    {
+        event.Enable(m_useCWD->GetValue());
+    }
+
+    void OnUpdateEnvironmentUI(wxUpdateUIEvent& event)
+    {
+        event.Enable(m_useEnv->GetValue());
+    }
+
+    wxTextCtrl* m_executable;
+    wxTextCtrl* m_cwdtext;
+    wxTextCtrl* m_envtext;
+    wxCheckBox* m_useCWD;
+    wxCheckBox* m_useEnv;
+
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(ExecQueryDialog, wxDialog)
+    EVT_UPDATE_UI(TEXT_CWD, ExecQueryDialog::OnUpdateWorkingDirectoryUI)
+    EVT_UPDATE_UI(TEXT_ENVIRONMENT, ExecQueryDialog::OnUpdateEnvironmentUI)
+END_EVENT_TABLE()
+
+ExecQueryDialog::ExecQueryDialog(const wxString& cmd)
+    : wxDialog(NULL, wxID_ANY, DIALOG_TITLE,
+               wxDefaultPosition, wxDefaultSize,
+               wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+{
+    wxSizer* globalSizer = new wxBoxSizer(wxVERTICAL);
+
+    m_executable = new wxTextCtrl(this, TEXT_EXECUTABLE, wxString());
+    m_cwdtext = new wxTextCtrl(this, TEXT_CWD, wxString());
+    m_envtext = new wxTextCtrl(this, TEXT_ENVIRONMENT, wxString(),
+                               wxDefaultPosition, wxSize(300, 200),
+                               wxTE_MULTILINE|wxHSCROLL);
+
+    const wxSizerFlags flagsExpand = wxSizerFlags().Expand().Border();
+    globalSizer->Add(new wxStaticText(this, wxID_ANY, "Enter the command: "),
+                     flagsExpand);
+    globalSizer->Add(m_executable, flagsExpand);
+
+    m_useCWD = new wxCheckBox(this, wxID_ANY, "Working directory: ");
+    globalSizer->Add(m_useCWD, flagsExpand);
+    globalSizer->Add(m_cwdtext, flagsExpand);
+
+    m_useEnv = new wxCheckBox(this, wxID_ANY, "Environment: ");
+    globalSizer->Add(m_useEnv, flagsExpand);
+    globalSizer->Add(m_envtext, wxSizerFlags(flagsExpand).Proportion(1));
+
+    globalSizer->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL), flagsExpand);
+    SetSizerAndFit(globalSizer);
+
+
+    m_executable->SetValue(cmd);
+    m_cwdtext->SetValue(wxGetCwd());
+    wxEnvVariableHashMap env;
+    if ( wxGetEnvMap(&env) )
+    {
+        for ( wxEnvVariableHashMap::iterator it = env.begin();
+              it != env.end();
+              ++it )
+        {
+            m_envtext->AppendText(it->first + '=' + it->second + '\n');
+        }
+    }
+    m_useCWD->SetValue(false);
+    m_useEnv->SetValue(false);
+}
+
+void ExecQueryDialog::GetEnvironment(wxEnvVariableHashMap& env)
+{
+    env.clear();
+    if ( m_useEnv->GetValue() )
+    {
+        wxString name,
+                 value;
+
+        const int nb = m_envtext->GetNumberOfLines();
+        for ( int l = 0; l < nb; l++ )
+        {
+            const wxString line = m_envtext->GetLineText(l).Trim();
+
+            if ( !line.empty() )
+            {
+                name = line.BeforeFirst('=', &value);
+                if ( name.empty() )
+                {
+                    wxLogWarning("Skipping invalid environment line \"%s\".", line);
+                    continue;
+                }
+
+                env[name] = value;
+            }
+        }
+    }
+}
+
+static bool QueryExec(wxString& cmd, wxExecuteEnv& env)
+{
+    ExecQueryDialog dialog(cmd);
+
+    if ( dialog.ShowModal() != wxID_OK )
+        return false;
+
+    cmd = dialog.GetExecutable();
+    env.cwd = dialog.GetWorkDir();
+    dialog.GetEnvironment(env.env);
+
+    return true;
+}
+
 // ----------------------------------------------------------------------------
 // event handlers: exec menu
 // ----------------------------------------------------------------------------
@@ -694,16 +837,14 @@ void MyFrame::DoAsyncExec(const wxString& cmd)
 
 void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
 {
-    wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
-                                     DIALOG_TITLE,
-                                     m_cmdLast);
-
-    if ( !cmd )
+    wxString cmd;
+    wxExecuteEnv env;
+    if ( !QueryExec(cmd, env) )
         return;
 
     wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
 
-    int code = wxExecute(cmd, wxEXEC_SYNC);
+    int code = wxExecute(cmd, wxEXEC_SYNC, NULL, &env);
 
     wxLogStatus(wxT("Process '%s' terminated with exit code %d."),
         cmd.c_str(), code);
index 398834798f1d14b0c50887e81cc4db858e181b64..7df71bf3213d29827a551352e37fd5fd2efb5170 100644 (file)
@@ -142,7 +142,8 @@ WX_IMPLEMENT_GET_OBJC_CLASS(wxTaskHandler,NSObject)
 
 long wxExecute(const wxString& command,
                int sync,
-               wxProcess *handle)
+               wxProcess *handle,
+               const wxExecuteEnv *env)
 {
     NSTask* theTask = [[NSTask alloc] init];
 
index 2667f5885bac5523a4f2588e9f915c2d75793749..5176c5236ff598898ad50a466e92115d7523ef96 100644 (file)
@@ -543,6 +543,43 @@ wxString wxGetCurrentDir()
 
 #endif // 0
 
+// ----------------------------------------------------------------------------
+// Environment
+// ----------------------------------------------------------------------------
+
+bool wxGetEnvMap(wxEnvVariableHashMap *map)
+{
+    wxCHECK_MSG( map, false, wxS("output pointer can't be NULL") );
+
+#if defined(__VISUALC__)
+    wxChar **env = _tenviron;
+#else // non-MSVC
+    // Not sure if other compilers have _tenviron so use the (more standard)
+    // ANSI version only for them.
+    char ** env = environ;
+#endif
+
+    if ( env )
+    {
+        wxString name,
+                 value;
+        while ( *env )
+        {
+            const wxString var(*env);
+
+            name = var.BeforeFirst(wxS('='), &value);
+
+            (*map)[name] = value;
+
+            env++;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
 // ----------------------------------------------------------------------------
 // wxExecute
 // ----------------------------------------------------------------------------
@@ -590,13 +627,14 @@ static bool ReadAll(wxInputStream *is, wxArrayString& output)
 static long wxDoExecuteWithCapture(const wxString& command,
                                    wxArrayString& output,
                                    wxArrayString* error,
-                                   int flags)
+                                   int flags,
+                                   const wxExecuteEnv *env)
 {
     // create a wxProcess which will capture the output
     wxProcess *process = new wxProcess;
     process->Redirect();
 
-    long rc = wxExecute(command, wxEXEC_SYNC | flags, process);
+    long rc = wxExecute(command, wxEXEC_SYNC | flags, process, env);
 
 #if wxUSE_STREAMS
     if ( rc != -1 )
@@ -621,17 +659,19 @@ static long wxDoExecuteWithCapture(const wxString& command,
     return rc;
 }
 
-long wxExecute(const wxString& command, wxArrayString& output, int flags)
+long wxExecute(const wxString& command, wxArrayString& output, int flags,
+               const wxExecuteEnv *env)
 {
-    return wxDoExecuteWithCapture(command, output, NULL, flags);
+    return wxDoExecuteWithCapture(command, output, NULL, flags, env);
 }
 
 long wxExecute(const wxString& command,
                wxArrayString& output,
                wxArrayString& error,
-               int flags)
+               int flags,
+               const wxExecuteEnv *env)
 {
-    return wxDoExecuteWithCapture(command, output, &error, flags);
+    return wxDoExecuteWithCapture(command, output, &error, flags, env);
 }
 
 // ----------------------------------------------------------------------------
index 3d1095cf59da84eae22129212f47e2657651e3c6..1b47458ab4a0f93084b5f19413fa5bc97ed9a555 100644 (file)
@@ -314,7 +314,8 @@ bool wxShell(const wxString& command /*=wxEmptyString*/)
     return result == 0;
 }
 
-long wxExecute(const wxString& command, int flags, wxProcess *process)
+long wxExecute(const wxString& command, int flags, wxProcess *process,
+        const wxExecuteEnv *env)
 {
     // FIXME: shouldn't depend on wxCmdLineParser
     wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command));
@@ -439,7 +440,8 @@ wxString wxRedirectableFd::Release()
 
 // wxExecute implementation
 //
-long wxExecute(wxChar **argv, int flags, wxProcess *process)
+long wxExecute(wxChar **argv, int flags, wxProcess *process,
+        const wxString* cwd, const wxEnvVariableHashMap* env)
 {
 #if wxUSE_STREAMS
     const int STDIN = 0;
index 8e86fb663c42050eb49e5a3e4b9c7758fd178c6a..6fc63c0ee1f7b22dca338f66e11afc58cf7a8601 100644 (file)
@@ -610,7 +610,8 @@ wxExecuteDDE(const wxString& ddeServer,
 
 #endif // wxUSE_IPC
 
-long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
+long wxExecute(const wxString& cmd, int flags, wxProcess *handler,
+               const wxExecuteEnv *env)
 {
     wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
 
@@ -800,6 +801,55 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
     wxString arguments = command.AfterFirst(wxT(' '));
 #endif
 
+    wxWxCharBuffer envBuffer;
+    bool useCwd = false;
+    if ( env )
+    {
+        useCwd = !env->cwd.empty();
+
+        // Translate environment variable map into NUL-terminated list of
+        // NUL-terminated strings.
+        if ( !env->env.empty() )
+        {
+#if wxUSE_UNICODE
+            // Environment variables can contain non-ASCII characters. We could
+            // check for it and not use this flag if everything is really ASCII
+            // only but there doesn't seem to be any reason to do it so just
+            // assume Unicode by default.
+            dwFlags |= CREATE_UNICODE_ENVIRONMENT;
+#endif // wxUSE_UNICODE
+
+            wxEnvVariableHashMap::const_iterator it;
+
+            size_t envSz = 1; // ending '\0'
+            for ( it = env->env.begin(); it != env->env.end(); ++it )
+            {
+                // Add size of env variable name and value, and '=' char and
+                // ending '\0'
+                envSz += it->first.length() + it->second.length() + 2;
+            }
+
+            envBuffer.extend(envSz);
+
+            wxChar *p = envBuffer.data();
+            for ( it = env->env.begin(); it != env->env.end(); ++it )
+            {
+                const wxString line = it->first + wxS("=") + it->second;
+
+                // Include the trailing NUL which will always terminate the
+                // buffer returned by t_str().
+                const size_t len = line.length() + 1;
+
+                wxTmemcpy(p, line.t_str(), len);
+
+                p += len;
+            }
+
+            // And another NUL to terminate the list of NUL-terminated strings.
+            *p = 0;
+        }
+    }
+
     bool ok = ::CreateProcess
                 (
                     // WinCE requires appname to be non null
@@ -818,8 +868,10 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
                  NULL,               //   the process and its main thread
                  redirect,           // inherit handles if we use pipes
                  dwFlags,            // process creation flags
-                 NULL,               // environment (use the same)
-                 NULL,               // current directory (use the same)
+                 envBuffer.data(),   // environment (may be NULL which is fine)
+                 useCwd              // initial working directory
+                    ? const_cast<wxChar *>(env->cwd.wx_str())
+                    : NULL,          //     (or use the same)
                  &si,                // startup info (unused here)
                  &pi                 // process info
                 ) != 0;
@@ -1039,7 +1091,8 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
 }
 
 template <typename CharType>
-long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
+long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler,
+                   const wxExecuteEnv *env)
 {
     wxString command;
     command.reserve(1024);
@@ -1078,19 +1131,21 @@ long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
         command += ' ';
     }
 
-    return wxExecute(command, flags, handler);
+    return wxExecute(command, flags, handler, env);
 }
 
-long wxExecute(char **argv, int flags, wxProcess *handler)
+long wxExecute(char **argv, int flags, wxProcess *handler,
+               const wxExecuteEnv *env)
 {
-    return wxExecuteImpl(argv, flags, handler);
+    return wxExecuteImpl(argv, flags, handler, env);
 }
 
 #if wxUSE_UNICODE
 
-long wxExecute(wchar_t **argv, int flags, wxProcess *handler)
+long wxExecute(wchar_t **argv, int flags, wxProcess *handler,
+               const wxExecuteEnv *env)
 {
-    return wxExecuteImpl(argv, flags, handler);
+    return wxExecuteImpl(argv, flags, handler, env);
 }
 
 #endif // wxUSE_UNICODE
index c50a311691f10f3c4bc540e3b5bda7ff5fc4dc97..199781f7cfbdb052d1b40f6becef40b15df8dd57 100644 (file)
@@ -128,7 +128,8 @@ MRESULT APIENTRY wxExecuteWindowCbk( HWND   hWnd,
 
 long wxExecute( const wxString& rCommand,
                 int flags,
-                wxProcess* pHandler)
+                wxProcess* pHandler,
+                const wxExecuteEnv *env)
 {
     if (rCommand.empty())
     {
@@ -219,6 +220,7 @@ long wxExecute(
   char**                            ppArgv
 , int                               flags
 , wxProcess*                        pHandler
+, const wxExecuteEnv *env
 )
 {
     wxString                        sCommand;
@@ -234,6 +236,7 @@ long wxExecute(
     return wxExecute( sCommand
                      ,flags
                      ,pHandler
+                     , env
                     );
 }
 
index eaa04a4e6b18ac9f054a3cafc40f47bc0ae55530..2d224edacbe79cea162d81b0373a90959d3fbe08 100644 (file)
@@ -87,12 +87,14 @@ static bool wxExecuteDDE(const wxString& ddeServer,
 
 #endif // wxUSE_IPC
 
-long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
+long wxExecute(const wxString& cmd, int flags, wxProcess *handler,
+    const wxExecuteEnv *env)
 {
     return 0;
 }
 
-long wxExecute(wxChar **argv, int flags, wxProcess *handler)
+long wxExecute(wxChar **argv, int flags, wxProcess *handler,
+    const wxExecuteEnv *env)
 {
     return 0;
 }
index 6126c0a2e55c9a8623e0da1307e48719be5848cc..fa2eb472873f9e724f9ec3e3eccc1461f1b08166 100644 (file)
@@ -442,27 +442,30 @@ private:
 bool wxMacLaunch(char **argv);
 #endif
 
-long wxExecute(const wxString& command, int flags, wxProcess *process)
+long wxExecute(const wxString& command, int flags, wxProcess *process,
+        const wxExecuteEnv *env)
 {
     ArgsArray argv(wxCmdLineParser::ConvertStringToArgs(command,
                                                         wxCMD_LINE_SPLIT_UNIX));
 
-    return wxExecute(argv, flags, process);
+    return wxExecute(argv, flags, process, env);
 }
 
 #if wxUSE_UNICODE
 
-long wxExecute(wchar_t **wargv, int flags, wxProcess *process)
+long wxExecute(wchar_t **wargv, int flags, wxProcess *process,
+        const wxExecuteEnv *env)
 {
     ArgsArray argv(wargv);
 
-    return wxExecute(argv, flags, process);
+    return wxExecute(argv, flags, process, env);
 }
 
 #endif // wxUSE_UNICODE
 
 // wxExecute: the real worker function
-long wxExecute(char **argv, int flags, wxProcess *process)
+long wxExecute(char **argv, int flags, wxProcess *process,
+        const wxExecuteEnv *env)
 {
     // for the sync execution, we return -1 to indicate failure, but for async
     // case we return 0 which is never a valid PID
@@ -577,6 +580,40 @@ long wxExecute(char **argv, int flags, wxProcess *process)
             pipeErr.Close();
         }
 
+        // Process additional options if we have any
+        if ( env )
+        {
+            // Change working directory if it is specified
+            if ( !env->cwd.empty() )
+                wxSetWorkingDirectory(env->cwd);
+
+            // Change environment if needed.
+            //
+            // NB: We can't use execve() currently because we allow using
+            //     non full paths to wxExecute(), i.e. we want to search for
+            //     the program in PATH. However it just might be simpler/better
+            //     to do the search manually and use execve() envp parameter to
+            //     set up the environment of the child process explicitly
+            //     instead of doing what we do below.
+            if ( !env->env.empty() )
+            {
+                wxEnvVariableHashMap oldenv;
+                wxGetEnvMap(&oldenv);
+
+                // Remove unwanted variables
+                wxEnvVariableHashMap::const_iterator it;
+                for ( it = oldenv.begin(); it != oldenv.end(); ++it )
+                {
+                    if ( env->env.find(it->first) == env->env.end() )
+                        wxUnsetEnv(it->first);
+                }
+
+                // And add the new ones (possibly replacing the old values)
+                for ( it = env->env.begin(); it != env->env.end(); ++it )
+                    wxSetEnv(it->first, it->second);
+            }
+        }
+
         execvp(*argv, argv);
 
         fprintf(stderr, "execvp(");