2 /// \file exechelper.cc
3 /// Helper class to wrap wxProcess and wxExecute operations
7 Copyright (C) 2010-2013, Chris Frey <cdfrey@foursquare.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "exechelper.h"
24 #include <wx/tokenzr.h>
29 #include <sys/types.h>
36 TermCatcher::~TermCatcher()
42 ExecHelper::ExecHelper(TermCatcher
*catcher
)
49 // link ourselves to the catcher... the catcher will unlink if necessary
51 m_catcher
->m_eh
= this;
54 ExecHelper::~ExecHelper()
56 if( m_app_callback
) {
57 m_app_callback
->Detach();
64 void ExecHelper::RunError(wxWindow
*parent
, const wxString
&msg
)
69 wxMessageBox(msg
, _W("Application Run Error"),
70 wxOK
| wxICON_ERROR
, parent
);
73 int ExecHelper::Execute(bool use_wx
,
74 const wxString
&command
,
78 return wxExecute(command
, wxEXEC_ASYNC
, m_app_callback
);
82 // use our own forking mechanism, due to bugs in wxWidgets :-(
85 class WaitThread
: public wxThread
88 AppCallback
*m_callback
;
91 WaitThread(int pid
, AppCallback
*cb
)
100 int pid
= waitpid(m_pid
, &status
, 0);
102 // our child finished
103 m_callback
->OnTerminate(pid
, status
);
110 // about to fork, log the start time
111 m_started
= time(NULL
);
119 else if( pid
== 0 ) {
122 // parse the command line into an array
125 wxStringTokenizer
t(command
, _T(" "));
126 while( t
.HasMoreTokens() && argc
< 99 ) {
127 wxString token
= t
.GetNextToken();
128 std::string
ctoken(token
.utf8_str());
129 argv
[argc
] = new char[ctoken
.size() + 1];
130 strcpy(argv
[argc
], ctoken
.c_str());
135 execvp(argv
[0], argv
);
137 cerr
<< "execvp() failed: " << strerror(errno
) << endl
;
138 for( int i
= 0; argv
[i
]; i
++ ) {
139 cerr
<< argv
[i
] << " ";
146 // we are the parent... start the wait thread
147 WaitThread
*wt
= new WaitThread(pid
, cb
);
154 bool ExecHelper::Run(wxWindow
*parent
,
155 const std::string
&appname
,
156 const wxString
&command
)
158 if( IsAppRunning() ) {
160 // TRANSLATORS: %s is the name of an application
161 wxString::Format(_W("%s is already running."),
166 m_app_callback
= new AppCallback(this);
167 m_app_pid
= Execute(false, command
, m_app_callback
);
168 if( m_app_pid
<= 0 ) {
169 delete m_app_callback
;
173 RunError(parent
, wxString::Format(
174 _W("Failed to run %s. Please make sure it is "
175 "installed and in your PATH."),
183 bool ExecHelper::IsAppRunning()
185 return m_app_callback
&& m_app_pid
> 0;
188 void ExecHelper::WaitForChild()
190 while( IsAppRunning() )
194 int ExecHelper::GetChildExitCode() const
196 int status
= GetRawAppStatus();
197 return WEXITSTATUS(status
);
200 void ExecHelper::KillApp(bool hardkill
)
202 if( IsAppRunning() ) {
203 // m_app_callback->Kill(m_app_pid, hardkill ? wxSIGKILL : wxSIGTERM);
204 kill(m_app_pid
, hardkill
? SIGKILL
: SIGTERM
);
205 // let the callback handle the cleanup