lib: added implicit ctor converter from DatabaseDatabase to DBListType
[barry/progweb.git] / desktop / src / exechelper.cc
blobb1d18f60845f930a36dcb120f90ce34e8e7618e8
1 ///
2 /// \file exechelper.cc
3 /// Helper class to wrap wxProcess and wxExecute operations
4 ///
6 /*
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>
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>
33 using namespace std;
35 TermCatcher::~TermCatcher()
37 if( m_eh )
38 m_eh->m_catcher = 0;
41 ExecHelper::ExecHelper(TermCatcher *catcher)
42 : m_catcher(catcher)
43 , m_app_callback(0)
44 , m_app_pid(-1)
45 , m_app_status(-1)
46 , m_started(0)
48 // link ourselves to the catcher... the catcher will unlink if necessary
49 if( m_catcher )
50 m_catcher->m_eh = this;
53 ExecHelper::~ExecHelper()
55 if( m_app_callback ) {
56 m_app_callback->Detach();
57 m_app_callback = 0;
59 if( m_catcher )
60 m_catcher->m_eh = 0;
63 void ExecHelper::RunError(wxWindow *parent, const wxString &msg)
65 if( !parent )
66 return;
68 wxMessageBox(msg, _T("Application Run Error"),
69 wxOK | wxICON_ERROR, parent);
72 int ExecHelper::Execute(bool use_wx,
73 const wxString &command,
74 AppCallback *cb)
76 if( use_wx ) {
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
86 int m_pid;
87 AppCallback *m_callback;
89 public:
90 WaitThread(int pid, AppCallback *cb)
91 : m_pid(pid)
92 , m_callback(cb)
96 virtual void* Entry()
98 int status;
99 int pid = waitpid(m_pid, &status, 0);
100 if( pid == m_pid ) {
101 // our child finished
102 m_callback->OnTerminate(pid, status);
105 return 0;
109 // about to fork, log the start time
110 m_started = time(NULL);
112 // create child
113 int pid = fork();
114 if( pid == -1 ) {
115 // no child created
116 return -1;
118 else if( pid == 0 ) {
119 // we are the child
121 // parse the command line into an array
122 char *argv[100];
123 int argc = 0;
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());
130 argc++;
132 argv[argc] = 0;
134 execvp(argv[0], argv);
136 cerr << "execvp() failed: " << strerror(errno) << endl;
137 for( int i = 0; argv[i]; i++ ) {
138 cerr << argv[i] << " ";
140 cerr << endl;
142 exit(255);
144 else {
145 // we are the parent... start the wait thread
146 WaitThread *wt = new WaitThread(pid, cb);
147 wt->Create();
148 wt->Run();
149 return pid;
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."));
160 return false;
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;
167 m_app_callback = 0;
168 m_app_pid = -1;
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."));
173 return false;
176 return true;
179 bool ExecHelper::IsAppRunning()
181 return m_app_callback && m_app_pid > 0;
184 void ExecHelper::WaitForChild()
186 while( IsAppRunning() )
187 usleep(50000);
190 int ExecHelper::GetChildExitCode() const
192 int status = GetRawAppStatus();
193 return WEXITSTATUS(status);
196 void ExecHelper::KillApp(bool hardkill)
198 if( IsAppRunning() ) {
199 // m_app_callback->Kill(m_app_pid, hardkill ? wxSIGKILL : wxSIGTERM);
200 kill(m_app_pid, hardkill ? SIGKILL : SIGTERM);
201 // let the callback handle the cleanup