Bumped copyright dates for 2013
[barry.git] / desktop / src / exechelper.cc
blobf531aaf0c765b68f48d5f3f98b21119e751276a4
1 ///
2 /// \file exechelper.cc
3 /// Helper class to wrap wxProcess and wxExecute operations
4 ///
6 /*
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>
26 #include <iostream>
27 #include <string.h>
28 #include <sys/wait.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include "wxi18n.h"
34 using namespace std;
36 TermCatcher::~TermCatcher()
38 if( m_eh )
39 m_eh->m_catcher = 0;
42 ExecHelper::ExecHelper(TermCatcher *catcher)
43 : m_catcher(catcher)
44 , m_app_callback(0)
45 , m_app_pid(-1)
46 , m_app_status(-1)
47 , m_started(0)
49 // link ourselves to the catcher... the catcher will unlink if necessary
50 if( m_catcher )
51 m_catcher->m_eh = this;
54 ExecHelper::~ExecHelper()
56 if( m_app_callback ) {
57 m_app_callback->Detach();
58 m_app_callback = 0;
60 if( m_catcher )
61 m_catcher->m_eh = 0;
64 void ExecHelper::RunError(wxWindow *parent, const wxString &msg)
66 if( !parent )
67 return;
69 wxMessageBox(msg, _W("Application Run Error"),
70 wxOK | wxICON_ERROR, parent);
73 int ExecHelper::Execute(bool use_wx,
74 const wxString &command,
75 AppCallback *cb)
77 if( use_wx ) {
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
87 int m_pid;
88 AppCallback *m_callback;
90 public:
91 WaitThread(int pid, AppCallback *cb)
92 : m_pid(pid)
93 , m_callback(cb)
97 virtual void* Entry()
99 int status;
100 int pid = waitpid(m_pid, &status, 0);
101 if( pid == m_pid ) {
102 // our child finished
103 m_callback->OnTerminate(pid, status);
106 return 0;
110 // about to fork, log the start time
111 m_started = time(NULL);
113 // create child
114 int pid = fork();
115 if( pid == -1 ) {
116 // no child created
117 return -1;
119 else if( pid == 0 ) {
120 // we are the child
122 // parse the command line into an array
123 char *argv[100];
124 int argc = 0;
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());
131 argc++;
133 argv[argc] = 0;
135 execvp(argv[0], argv);
137 cerr << "execvp() failed: " << strerror(errno) << endl;
138 for( int i = 0; argv[i]; i++ ) {
139 cerr << argv[i] << " ";
141 cerr << endl;
143 exit(255);
145 else {
146 // we are the parent... start the wait thread
147 WaitThread *wt = new WaitThread(pid, cb);
148 wt->Create();
149 wt->Run();
150 return pid;
154 bool ExecHelper::Run(wxWindow *parent,
155 const std::string &appname,
156 const wxString &command)
158 if( IsAppRunning() ) {
159 RunError(parent,
160 // TRANSLATORS: %s is the name of an application
161 wxString::Format(_W("%s is already running."),
162 appname.c_str()));
163 return false;
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;
170 m_app_callback = 0;
171 m_app_pid = -1;
173 RunError(parent, wxString::Format(
174 _W("Failed to run %s. Please make sure it is "
175 "installed and in your PATH."),
176 appname.c_str()));
177 return false;
180 return true;
183 bool ExecHelper::IsAppRunning()
185 return m_app_callback && m_app_pid > 0;
188 void ExecHelper::WaitForChild()
190 while( IsAppRunning() )
191 usleep(50000);
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