1 //**************************************************************************************************
2 // PrcBase.cpp *
3 // ------------- *
4 // Started : 2004-01-29 *
5 // Last Update : 2015-01-06 *
6 // Copyright : (C) 2004 by MSWaters *
7 //**************************************************************************************************
8
9 //**************************************************************************************************
10 // *
11 // This program is free software; you can redistribute it and/or modify it under the *
12 // terms of the GNU General Public License as published by the Free Software Foundation; *
13 // either version 3 of the License, or (at your option) any later version. *
14 // *
15 //**************************************************************************************************
16
17 #include "PrcBase.hpp"
18
19 //**************************************************************************************************
20 // Constructor.
21
PrcBase(int iFlags)22 PrcBase::PrcBase( int iFlags ) : wxProcess( iFlags )
23 {
24 m_iPid = -1; // Clear the process ID number
25 m_iExitCode = 0; // Clear the process exit code
26 m_ofnLog = DEF_LOG_FILE; // Set the default log file path and name
27 m_osErrMsg = wxT(""); // Clear the error message
28 }
29
30 //**************************************************************************************************
31 // Destructor.
32
~PrcBase()33 PrcBase::~PrcBase( )
34 {
35 // Delete the process log file
36 bDelLogFile( );
37 }
38
39 //**************************************************************************************************
40 // Find a binary using the user's PATH environment variable given the binary name.
41 //
42 // Argument List :
43 // ofnBin - The binary name without the path
44 //
45 // Return Values :
46 // true - Success (path prepended to oFnBinary)
47 // false - Failure
48
bFindBinary(wxFileName & rofnBinary)49 bool PrcBase::bFindBinary( wxFileName & rofnBinary )
50 {
51 wxPathList opl1;
52 wxFileName ofn1;
53 wxString os1, os2, os3;
54
55 m_osErrMsg = wxT("");
56
57 // Initial checks
58 if( ! rofnBinary.IsOk( ) ) return( false );
59
60 // Search environment variable PATH for the first occurrence of the binary
61 opl1.AddEnvList( wxT("PATH") );
62 ofn1 = opl1.FindAbsoluteValidPath( rofnBinary.GetFullName( ) );
63
64 // Check whether the binary was successfully found
65 if( !ofn1.IsOk( ) || !ofn1.FileExists( ) )
66 {
67 os1 << wxT("Can't find the binary : ") << m_ofnBinary.GetFullName( );
68 wxGetEnv( wxT("PATH"), &os2 );
69 os2.Prepend( wxT("$PATH = \n") );
70
71 // Set the object error message
72 os3 = os1 + wxT("\n\n") + os2;
73 SetErrMsg( os3 );
74
75 // If debug mode is enabled send the error message to the console
76 if( g_bDebug )
77 {
78 os3 = os1 + wxT(" (") + os2 + wxT(").");
79 std::cerr << "DEBUG : " << rosStrToLine( os3 ).mb_str( ) << "\n\n";
80 }
81
82 return( false );
83 }
84
85 m_ofnBinary = ofn1;
86
87 return( true );
88 }
89
90 //**************************************************************************************************
91 // Get the console output after a process has been initiated and record it in the log file.
92 //
93 // Return Values :
94 // true - Success
95 // false - Failure
96
bLogOutput(void)97 bool PrcBase::bLogOutput( void )
98 {
99 wxOutputStream * poStdOut;
100 wxInputStream * poStdIn;
101 wxInputStream * poStdErr;
102 wxString os1, os2;
103 wxChar oc1;
104
105 // Check that the log file name is valid
106 if( ! m_ofnLog.IsOk( ) ) return( false );
107
108 // Open the file
109 wxTextFile oFileLog( m_ofnLog.GetFullPath( ) );
110 if( oFileLog.Exists( ) )
111 { if( ! oFileLog.Open( ) ) return( false ); }
112 else { if( ! oFileLog.Create( ) ) return( false ); }
113
114 // Clear the file if it contains lines
115 oFileLog.Clear( );
116
117 // Get pointers to the input streams
118 poStdOut = GetOutputStream( );
119 poStdIn = GetInputStream( );
120 poStdErr = GetErrorStream( );
121
122 // Read the console input
123 while( bIsExec( ) || poStdIn->IsOk( ) || poStdErr->IsOk( ) )
124 {
125 // Get a line of data from stdout
126 while( poStdIn->CanRead( ) )
127 {
128 oc1 = poStdIn->GetC( );
129 if( oc1==wxT('\t') || (oc1>31 && oc1!=127) ) os1 << oc1;
130 if( oc1 == wxT('\n') ) { oFileLog.AddLine( os1 ); os1 = wxT(""); }
131 }
132
133 // Get a line of data from stderr
134 while( poStdErr->CanRead( ) )
135 {
136 oc1 = poStdErr->GetC( );
137 if( oc1==wxT('\t') || (oc1>31 && oc1!=127) ) os2 << oc1;
138 if( oc1 == wxT('\n') ) { oFileLog.AddLine( os2 ); os2 = wxT(""); }
139 }
140
141 wxYield( ); // Yield CPU to other processes
142 }
143
144 // Delete the stream objects
145 delete poStdOut;
146 delete poStdIn;
147 delete poStdErr;
148 SetPipeStreams( NULL, NULL, NULL );
149
150 if( ! os1.IsEmpty( ) ) oFileLog.AddLine( os1 );
151 if( ! os2.IsEmpty( ) ) oFileLog.AddLine( os2 );
152
153 oFileLog.Write( ); // Save the changes to disk
154 oFileLog.Close( ); // Close the log file
155
156 return( true );
157 }
158
159 //**************************************************************************************************
160 // Does the binary exist?
161 //
162 // Return Values :
163 // true - The binary does exist
164 // false - The binary doesn't exist
165
bBinExists(void)166 bool PrcBase::bBinExists( void )
167 {
168 if( !m_ofnBinary.IsOk( ) || !m_ofnBinary.FileExists( ) )
169 return( false );
170
171 return( true );
172 }
173
174 //**************************************************************************************************
175 // Set the file name of the binary to be executed.
176 //
177 // Argument List :
178 // rosFName - A string containing the binary file name
179 //
180 // Return Values :
181 // true - Success
182 // false - Failure
183
bSetBinary(const wxString & rosFName)184 bool PrcBase::bSetBinary( const wxString & rosFName )
185 {
186 if( rosFName.IsEmpty( ) ) return( false );
187
188 m_ofnBinary = rosFName;
189
190 if( ! bFindBinary( m_ofnBinary ) ) return( false );
191
192 return( true );
193 }
194
195 //**************************************************************************************************
196 // Set the argument list to be appended to the binary name.
197 //
198 // Argument List :
199 // rosArgLst - A string containing the argument list
200 //
201 // Return Values :
202 // true - Success
203 // false - Failure
204
bSetArgLst(const wxString & rosArgLst)205 bool PrcBase::bSetArgLst( const wxString & rosArgLst )
206 {
207 if( rosArgLst.IsEmpty( ) ) return( false );
208
209 m_osArgLst = rosArgLst;
210
211 return( true );
212 }
213
214 //**************************************************************************************************
215 // Set the process log file name.
216 // (If set all process output can be captured to this file.)
217 //
218 // Argument List :
219 // rosFName - A string containing the full path and file name
220 //
221 // Return Values :
222 // true - Success
223 // false - Failure
224
bSetLogFile(const wxString & rosFName)225 bool PrcBase::bSetLogFile( const wxString & rosFName )
226 {
227 wxFileName ofn1;
228
229 ofn1 = rosFName;
230
231 if( ! ofn1.IsOk( ) ) return( false );
232
233 if( ofn1.GetPath( ).IsEmpty( ) ) ofn1.SetPath( wxT(".") );
234
235 m_ofnLog = ofn1;
236
237 return( true );
238 }
239
240 //**************************************************************************************************
241 // Execute a process asynchronously.
242 // (Ie. Return as soon as the process has been launched).
243 //
244 // Return Values :
245 // true - Success
246 // false - Failure
247
bExecAsync(void)248 bool PrcBase::bExecAsync( void )
249 {
250 wxString os1, os2;
251
252 // Only execute simulation if it isn't already running
253 if( bIsExec( ) ) return( false );
254
255 // Clear error attributes
256 m_osErrMsg = wxT("");
257
258 // Check that the binary exists
259 if( ! bBinExists( ) )
260 if( ! bFindBinary( m_ofnBinary ) )
261 return( false );
262
263 // Construct the command line to be executed
264 os1 = roGetBinary( ).GetFullPath( );
265 if( ! rosGetArgLst( ).IsEmpty( ) )
266 os1 << wxT(' ') << rosGetArgLst( );
267
268 // Attempt to execute the simulation
269 m_iPid = (int) wxExecute( os1, wxEXEC_ASYNC, this );
270 if( m_iPid <= 0 )
271 {
272 os2.Empty( );
273 os2 << wxT("Couldn't start process : ") << os1;
274 SetErrMsg( os2 );
275 return( false );
276 }
277
278 return( true );
279 }
280
281 //**************************************************************************************************
282 // Execute a process synchronously.
283 // (Ie. wait for the process to terminate before returning).
284 //
285 // Return Values :
286 // true - Success
287 // false - Failure
288
bExecSync(void)289 bool PrcBase::bExecSync( void )
290 {
291 // Not yet implemented ??? 12/03/2010
292
293 return( false );
294
295 // long liRtn;
296
297 // wxEnableTopLevelWindows( false );
298 // liRtn = wxExecute( rosCmd, wxEXEC_SYNC );
299 // wxEnableTopLevelWindows( true );
300 // if( liRtn != 0 ) return( false );
301
302 // return( true );
303
304 // This is how I'd like to do it but it doesn't work 20/11/2003 ???
305 // wxEnableTopLevelWindows( false );
306 // int iRtn = (int) wxExecute( osCmd, wxEXEC_SYNC );
307 // wxEnableTopLevelWindows( true );
308
309 // wxProcess oProcess( wxPROCESS_DEFAULT );
310 // iPid = (int) wxExecute( osCmd, wxEXEC_SYNC );
311
312 // if( iPid == 0 )
313 // { // Error gnetlist could not be executed
314 // cerr << "The command:\n " << osCmd << "\ncould not be executed.";
315 // return( false );
316 // }
317
318 // for( ui1=0; ui1<300; ui1++ )
319 // { // Wait up to 30 seconds for the process to complete
320 //cerr << iPid << '\n';
321 // wxUsleep( 100 ); // Sleep for 100msec
322 // if( ! oProcess.Exists( iPid ) ) break;
323 // }
324 // if( oProcess.Exists( iPid ) )
325 // { // Error gnetlist had to be terminated prematurely
326 // oProcess.Kill( iPid );
327 // cerr << "The command:\n " << osCmd << "\ntook more than 30 sec. to "
328 // << "execute and so was terminated prematurely.";
329 // return( false );
330 // }
331 }
332
333 //**************************************************************************************************
334 // Stop the simulation currently in progress.
335 //
336 // Return Values :
337 // true - Success
338 // false - Failure
339
bKill(void)340 bool PrcBase::bKill( void )
341 {
342 if( ! bIsExec( ) ) return( true );
343 if( ! Exists( m_iPid ) ) return( true );
344
345 if( Kill( m_iPid, wxSIGTERM ) != wxKILL_OK ) return( false );
346
347 m_iPid = -1;
348 m_iExitCode = 0;
349
350 return( true );
351 }
352
353 //**************************************************************************************************
354 // Remove the log file.
355 //
356 // Return Values :
357 // Success - true
358 // Failure - false
359
bDelLogFile(void)360 bool PrcBase::bDelLogFile( void )
361 {
362 if( m_ofnLog.GetFullPath( ).IsEmpty( ) ) return( true );
363
364 if( ! ::wxFileExists( m_ofnLog.GetFullPath( ) ) ) return( true );
365
366 return( ::wxRemoveFile( m_ofnLog.GetFullPath( ) ) );
367 }
368
369 //**************************************************************************************************
370 // Collect the output from the simulator and print to a text control.
371 //
372 // Argument List :
373 // roTxtCtl - The text control to contain the simulator output
374
Print(TextCtrl & roTxtCtl)375 void PrcBase::Print( TextCtrl & roTxtCtl )
376 {
377 roTxtCtl.bClear( ); // Clear the text control
378
379 PrintCmd( roTxtCtl ); // Print the process command
380
381 PrintRsp( roTxtCtl ); // Print the process command response
382 }
383
384 //**************************************************************************************************
385 // Print the command envoking the process to a text control.
386 //
387 // Argument List :
388 // roTxtCtl - The text control to contain process input
389
PrintCmd(TextCtrl & roTxtCtl)390 void PrcBase::PrintCmd( TextCtrl & roTxtCtl )
391 {
392 wxString os1;
393
394 // Print the process command
395 os1.Empty( );
396 os1 << wxT(" ")
397 << wxT("*************** PROCESS COMMAND ***************");
398 roTxtCtl.bAppendLine( os1 );
399 os1.Empty( );
400 roTxtCtl.bAppendLine( os1 );
401 os1 << roGetBinary( ).GetFullPath( );
402 if( ! rosGetArgLst( ).IsEmpty( ) ) os1 << wxT(' ') << rosGetArgLst( );
403 roTxtCtl.bAppendLine( os1 );
404 os1.Empty( );
405 roTxtCtl.bAppendLine( os1 );
406 }
407
408 //**************************************************************************************************
409 // Collect the output from the process and print it to a text control.
410 //
411 // Argument List :
412 // roTxtCtl - The text control to contain the simulator output
413
PrintRsp(TextCtrl & roTxtCtl)414 void PrcBase::PrintRsp( TextCtrl & roTxtCtl )
415 {
416 wxString os1;
417
418 // Print the process command response
419 if( ! m_ofnLog.GetFullPath( ).IsEmpty( ) )
420 {
421 os1.Empty( );
422 os1 << wxT(" ")
423 << wxT("*************** PROCESS RESPONSE **************");
424 roTxtCtl.bAppendLine( os1 );
425 os1.Empty( );
426 roTxtCtl.bAppendLine( os1 );
427 if( m_ofnLog.IsOk( ) && m_ofnLog.FileExists( ) )
428 roTxtCtl.bAppendFile( m_ofnLog.GetFullPath( ) );
429 else
430 {
431 os1 << wxT("Couldn't load the file containing the process ouput : ")
432 << m_ofnLog.GetFullPath( );
433 roTxtCtl.bAppendLine( os1 );
434 }
435 }
436 }
437
438 //**************************************************************************************************
439 // Call-back function called when the process terminates.
440 // (WARNING : Be careful of this function definition, if it is incorrect the
441 // application can segment fault.)
442 //
443 // Argument List :
444 // iPid - The PID of the process which just terminated
445 // iStatus - The exit code of the process
446
OnTerminate(int iPid,int iStatus)447 void PrcBase::OnTerminate( int iPid, int iStatus )
448 {
449 if( iPid == m_iPid )
450 {
451 m_iPid = -1;
452 m_iExitCode = iStatus;
453 }
454 }
455
456 //**************************************************************************************************
457