2 /// \file exechelper.cc
3 /// Helper class to wrap wxProcess and wxExecute operations
7 Copyright (C) 2010-2012, 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>
35 TermCatcher::~TermCatcher()
41 ExecHelper::ExecHelper(TermCatcher
*catcher
)
48 // link ourselves to the catcher... the catcher will unlink if necessary
50 m_catcher
->m_eh
= this;
53 ExecHelper::~ExecHelper()
55 if( m_app_callback
) {
56 m_app_callback
->Detach();
63 void ExecHelper::RunError(wxWindow
*parent
, const wxString
&msg
)
68 wxMessageBox(msg
, _T("Application Run Error"),
69 wxOK
| wxICON_ERROR
, parent
);
72 int ExecHelper::Execute(bool use_wx
,
73 const wxString
&command
,
77 return wxExecute(command
, wxEXEC_ASYNC
, m_app_callback
);
81 // use our own forking mechanism, due to bugs in wxWidgets :-(
84 class WaitThread
: public wxThread
87 AppCallback
*m_callback
;
90 WaitThread(int pid
, AppCallback
*cb
)
99 int pid
= waitpid(m_pid
, &status
, 0);
101 // our child finished
102 m_callback
->OnTerminate(pid
, status
);
109 // about to fork, log the start time
110 m_started
= time(NULL
);
118 else if( pid
== 0 ) {
121 // parse the command line into an array
124 wxStringTokenizer
t(command
, _T(" "));
125 while( t
.HasMoreTokens() && argc
< 99 ) {
126 wxString token
= t
.GetNextToken();
127 std::string
ctoken(token
.utf8_str());
128 argv
[argc
] = new char[ctoken
.size() + 1];
129 strcpy(argv
[argc
], ctoken
.c_str());
134 execvp(argv
[0], argv
);
136 cerr
<< "execvp() failed: " << strerror(errno
) << endl
;
137 for( int i
= 0; argv
[i
]; i
++ ) {
138 cerr
<< argv
[i
] << " ";
145 // we are the parent... start the wait thread
146 WaitThread
*wt
= new WaitThread(pid
, cb
);
153 bool ExecHelper::Run(wxWindow
*parent
,
154 const std::string
&appname
,
155 const wxString
&command
)
157 if( IsAppRunning() ) {
158 RunError(parent
, wxString(appname
.c_str(), wxConvUTF8
) +
159 _T(" is already running."));
163 m_app_callback
= new AppCallback(this);
164 m_app_pid
= Execute(false, command
, m_app_callback
);
165 if( m_app_pid
<= 0 ) {
166 delete m_app_callback
;
170 RunError(parent
, _T("Failed to run ") +
171 wxString(appname
.c_str(), wxConvUTF8
) +
172 _T(". Please make sure it is installed and in your PATH."));
179 bool ExecHelper::IsAppRunning()
181 return m_app_callback
&& m_app_pid
> 0;
184 void ExecHelper::WaitForChild()
186 while( IsAppRunning() )
190 void ExecHelper::KillApp(bool hardkill
)
192 if( IsAppRunning() ) {
193 // m_app_callback->Kill(m_app_pid, hardkill ? wxSIGKILL : wxSIGTERM);
194 kill(m_app_pid
, hardkill
? SIGKILL
: SIGTERM
);
195 // let the callback handle the cleanup