]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/configtool/standalone/wxwin/ecutils.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / ecutils.cpp
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 // Copyright (C) 2003 John Dallaway
6 //
7 // This program is part of the eCos host tools.
8 //
9 // This program is free software; you can redistribute it and/or modify it 
10 // under the terms of the GNU General Public License as published by the Free 
11 // Software Foundation; either version 2 of the License, or (at your option) 
12 // any later version.
13 // 
14 // This program is distributed in the hope that it will be useful, but WITHOUT 
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
16 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
17 // more details.
18 // 
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc., 
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 //
23 // ----------------------------------------------------------------------------
24 //                                                                          
25 //####COPYRIGHTEND####
26 //
27 //===========================================================================
28 //===========================================================================
29 //#####DESCRIPTIONBEGIN####
30 //
31 // Author(s):   sdf, jld
32 // Contact(s):  sdf
33 // Date:                1998/08/11
34 // Version:             0.01
35 // Purpose:     
36 // Description: This is a collection of utility functions.
37 //              Modified by julians for wxWindows (originally CTUtils.h)
38 // Requires:    
39 // Provides:    
40 // See also:    
41 // Known bugs:  
42 // Usage:       
43 //
44 //####DESCRIPTIONEND####
45 //
46 //===========================================================================
47
48 #ifdef __GNUG__
49 #pragma implementation "ecutils.h"
50 #endif
51
52 // Includes other headers for precompiled compilation
53 #include "ecpch.h"
54
55 #ifdef __BORLANDC__
56 #pragma hdrstop
57 #endif
58
59 #include "ecutils.h"
60 #include "wx/listctrl.h"
61 #include "wx/stream.h"
62
63 #include <float.h> // for DBL_DIG macro
64 #include <sys/types.h>
65 #include <sys/stat.h>
66
67 #ifndef __WXMSW__
68 #include <errno.h>
69 #endif
70
71 #ifdef __WXMSW__
72 #include <tlhelp32.h>
73 #endif
74
75 #ifdef __CYGWIN__
76 #include <sys/cygwin.h> /* for cygwin_conv_to_*_path() */
77 #endif
78
79 #if 0
80
81 #define INCLUDEFILE <string>
82 #include "IncludeSTL.h"
83
84 #endif
85
86 // Chop str into pieces, using cSep as separator.
87 // " and \ have usual semantics
88 // Return value is array of pieces found.
89
90 int ecUtils::Chop(const wxString& psz, wxArrayString &ar, wxChar cSep,
91                   bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
92
93 {
94     if(wxT(' ') == cSep)
95     {
96         return Chop(psz, ar, wxT("\t\n\v\f\r "), bObserveStrings, bBackslashQuotes);
97     } else {
98         wxASSERT(wxT('\0')!=cSep);
99         wxChar c[2]={cSep,wxT('\0')};
100         return Chop(psz,ar,wxString(c),bObserveStrings,bBackslashQuotes);
101     }
102 }
103
104 int ecUtils::Chop(const wxString& str, wxArrayString &ar, const wxString& sep,
105                   bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
106 {
107     ar.Clear();
108     
109     const wxChar* pszSep = (const wxChar*) sep;
110     const wxChar* psz = (const wxChar*) str;
111     
112     int i=0;
113     for(;;){
114         // Skip multiple separators
115         while(*psz && wxStrchr(pszSep,*psz)){
116             psz++;
117         }
118         if(!*psz){
119             return i;
120         }
121         wxString strTok;
122         if(bObserveStrings){
123             bool bInString=FALSE;
124             do{
125                 if(*psz == wxT('\\') && bBackslashQuotes && psz[1]){
126                     strTok += psz[1];
127                     psz++;
128                 } else if(*psz == wxT('"')){
129                     bInString ^= 1;
130                 } else if (!bInString && *psz && NULL != wxStrchr(pszSep,*psz)) {
131                     break;
132                 } else {
133                     strTok+=*psz;
134                 }
135             } while (*++psz);
136         } else {
137             const wxChar* pszStart=psz;
138             do {
139                 psz++;
140             } while (*psz && ! wxStrchr(pszSep,*psz));
141             strTok=wxString(pszStart,psz-pszStart);
142         }
143         ar.Add(strTok);
144         i++;
145     }
146     return ar.GetCount();
147 }
148
149 #if 0
150
151 // vararg-style message box formatter
152 int ecUtils::MessageBoxF (LPCTSTR pszFormat, ...)
153 {
154   int rc;
155   va_list args;
156   va_start(args, pszFormat);
157   rc=ecUtils::vMessageBox(MB_OK, pszFormat,args);
158   va_end(args);
159   return rc;
160 }
161
162 // As above, but with type as first parameter.
163 int ecUtils::MessageBoxFT (UINT nType, LPCTSTR pszFormat, ...)
164 {
165   int rc;
166   va_list args;
167   va_start(args, pszFormat);
168   rc=ecUtils::vMessageBox(nType, pszFormat,args);
169   va_end(args);
170   return rc;
171 }
172
173 int ecUtils::vMessageBox(UINT nType, LPCTSTR  pszFormat, va_list marker)
174 {
175   int rc=0;
176   for(int nLength=100;nLength;) {
177     TCHAR *buf=new TCHAR[1+nLength];
178     int n=_vsntprintf(buf, nLength, pszFormat, marker ); 
179     if(-1==n){
180       nLength*=2;  // NT behavior
181     } else if (n<nLength){
182       rc=AfxMessageBox(buf,nType);
183       nLength=0;   // trigger exit from loop
184     } else {
185       nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
186     }
187     delete [] buf;
188   }
189   return rc;
190 }
191
192 #endif
193
194 bool ecUtils::StrToItemIntegerType(const wxString & str, long &d)
195 {
196         wxChar* pEnd;
197         bool rc;
198         errno=0;
199         bool bHex=(str.Len() > 2 && str[0]==wxT('0') && (str[1]==wxT('x')||str[1]==wxT('X')));
200         //d=_tcstol(str,&pEnd,bHex?16:10);
201         d=wxStrtol(str,&pEnd,bHex?16:10);
202         rc=(0==errno && (*pEnd==wxT('\0')));
203         return rc;
204 }
205
206 const wxString ecUtils::IntToStr(long d,bool bHex)
207 {
208   wxString s;
209   s.Printf(bHex?wxT("0x%08x"):wxT("%d"),d);
210   return s;
211 }
212
213 const wxString ecUtils::DoubleToStr (double dValue)
214 {
215   wxString s;
216   s.Printf(wxT("%.*e"), DBL_DIG, dValue);
217   return s;
218 }
219
220 bool ecUtils::StrToDouble (const wxString & strValue, double &dValue)
221 {
222         wxChar* pEnd;
223         errno = 0;
224         //dValue = _tcstod (strValue, &pEnd);
225         dValue = wxStrtod(strValue, &pEnd);
226         return (0 == errno) && (*pEnd == wxT('\0'));
227 }
228
229 #if 0
230 const wxString ecUtils::Explanation(CFileException & exc)
231 {
232         wxString strMsg;
233         switch(exc.m_cause){
234                 case CFileException::none: strMsg=wxT("No error occurred.");break;
235                 case CFileException::generic: strMsg=wxT("   An unspecified error occurred.");break;
236                 case CFileException::fileNotFound: strMsg=wxT("   The file could not be located.");break;
237                 case CFileException::badPath: strMsg=wxT("   All or part of the path is invalid.");break;
238                 case CFileException::tooManyOpenFiles: strMsg=wxT("   The permitted number of open files was exceeded.");break;
239                 case CFileException::accessDenied: strMsg=wxT("   The file could not be accessed.");break;
240                 case CFileException::invalidFile: strMsg=wxT("   There was an attempt to use an invalid file handle.");break;
241                 case CFileException::removeCurrentDir: strMsg=wxT("   The current working directory cannot be removed.");break;
242                 case CFileException::directoryFull: strMsg=wxT("   There are no more directory entries.");break;
243                 case CFileException::badSeek: strMsg=wxT("   There was an error trying to set the file pointer.");break;
244                 case CFileException::hardIO: strMsg=wxT("   There was a hardware error.");break;
245                 case CFileException::sharingViolation: strMsg=wxT("   SHARE.EXE was not loaded, or a shared region was locked.");break;
246                 case CFileException::lockViolation: strMsg=wxT("   There was an attempt to lock a region that was already locked.");break;
247                 case CFileException::diskFull: strMsg=wxT("   The disk is full.");break;
248                 case CFileException::endOfFile: strMsg=wxT("   The end of file was reached. ");break;
249                 default:
250                         strMsg=wxT(" Unknown cause");
251                         break;
252         }
253         return strMsg;
254 }
255
256
257 const wxString ecUtils::LoadString(UINT id)
258 {
259         wxString str;
260         str.LoadString(id);
261         return str;
262 }
263 #endif
264
265 const wxString ecUtils::NativeToPosixPath(const wxString & native)
266 {
267 #ifdef __CYGWIN__
268     if (native.IsEmpty())
269         return native;
270     else
271     {
272         wxString posix;
273         cygwin_conv_to_posix_path(native.c_str(), posix.GetWriteBuf(MAXPATHLEN + 1));
274         posix.UngetWriteBuf();
275         return posix;
276     }
277 #else
278     return native;
279 #endif
280 }
281
282 const wxString ecUtils::PosixToNativePath(const wxString & posix)
283 {
284 #ifdef __CYGWIN__
285     if (posix.IsEmpty())
286         return posix;
287     else
288     {
289         wxString native;
290         cygwin_conv_to_win32_path(posix.c_str(), native.GetWriteBuf(MAXPATHLEN + 1));
291         native.UngetWriteBuf();
292         return native;
293     }
294 #else
295     return posix;
296 #endif
297 }
298
299 bool ecUtils::AddToPath(const ecFileName & strFolder, bool bAtFront)
300 {
301     wxString strPath,strOldPath;
302     
303     if (wxGetEnv(wxT("PATH"), & strOldPath))
304     {
305         // Place the user tools folders at the head or tail of the new path
306         if(bAtFront)
307         {
308             strPath.Printf(wxT("%s;%s"), (const wxChar*) strFolder.ShortName(), (const wxChar*) strOldPath);
309         } else
310         {
311             strPath.Printf(wxT("%s;%s"), (const wxChar*) strOldPath, (const wxChar*) strFolder.ShortName());
312         }
313     } else
314     {
315         // unlikely, but ...
316         strPath = strFolder;
317     }
318     return (TRUE == wxSetEnv(wxT("PATH"),strPath));
319 }
320
321 #if 0           
322 wxString ecUtils::GetLastErrorMessageString()
323 {
324         wxString str;
325         PTCHAR pszMsg;
326         FormatMessage( 
327                 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
328                 NULL,
329                 GetLastError(),
330                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
331                 (LPTSTR)&pszMsg,
332                 0,
333                 NULL 
334         );
335
336         // Display the string.
337         str=pszMsg;
338   str.TrimRight();
339         // Free the buffer.
340         LocalFree(pszMsg);
341         return str;
342
343 }
344
345 bool ecUtils::Launch(const ecFileName &strFileName, const ecFileName &strViewer)
346 {
347         bool rc=false;
348
349         if(!strViewer.IsEmpty())//use custom editor
350         {
351                 wxString strCmdline(strViewer);
352                 
353                 PTCHAR pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
354                 GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
355                 strCmdline.ReleaseBuffer();
356
357                 strCmdline+=_TCHAR(' ');
358                 strCmdline+=strFileName;
359                 PROCESS_INFORMATION pi;
360                 STARTUPINFO si;
361
362                 si.cb = sizeof(STARTUPINFO); 
363                 si.lpReserved = NULL; 
364                 si.lpReserved2 = NULL; 
365                 si.cbReserved2 = 0; 
366                 si.lpDesktop = NULL; 
367                 si.dwFlags = 0; 
368                 si.lpTitle=NULL;
369
370                 if(CreateProcess(
371                         NULL, // app name
372                         //strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
373                         strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
374                         NULL, // process security
375                         NULL, // thread security
376                         TRUE, // inherit handles
377                         0,
378                         NULL, // environment
379                         NULL, // current dir
380                         &si, // startup info
381                         &pi)){
382             CloseHandle(pi.hProcess);
383             CloseHandle(pi.hThread);
384                         rc=true;
385                 } else {
386                         MessageBoxF(wxT("Failed to invoke %s.\n"),strCmdline);
387                 }
388                 strCmdline.ReleaseBuffer();
389         } else {// Use association
390                 TCHAR szExe[MAX_PATH];
391                 HINSTANCE h=FindExecutable(strFileName,wxT("."),szExe);
392                 if(int(h)<=32){
393                         wxString str;
394                         switch(int(h)){
395                                 case 0:  str=wxT("The system is out of memory or resources.");break;
396                                 case 31: str=wxT("There is no association for the specified file type.");break;
397                                 case ERROR_FILE_NOT_FOUND: str=wxT("The specified file was not found.");break;
398                                 case ERROR_PATH_NOT_FOUND: str=wxT("The specified path was not found.");break;
399                                 case ERROR_BAD_FORMAT:     str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
400                                 default: break;
401                         }
402                         MessageBoxF(wxT("Failed to open document %s.\r\n%s"),strFileName,str);
403                 } else {
404
405                         SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), wxT("open"),
406                                         strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
407
408                         sei.hInstApp=0;
409                         HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),wxT("open"), strFileName, NULL, wxT("."), 0)/*ShellExecuteEx(&sei)*/;
410                         if(int(hInst)<=32/*sei.hInstApp==0*/)
411                         {
412                                 wxString str;
413                                 switch(int(hInst))
414                                 {
415                                         case 0 : str=wxT("The operating system is out of memory or resources. ");break;
416                                         case ERROR_FILE_NOT_FOUND : str=wxT("The specified file was not found. ");break;
417                                         case ERROR_PATH_NOT_FOUND : str=wxT("The specified path was not found. ");break;
418                                         case ERROR_BAD_FORMAT : str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
419                                         case SE_ERR_ACCESSDENIED : str=wxT("The operating system denied access to the specified file. ");break;
420                                         case SE_ERR_ASSOCINCOMPLETE : str=wxT("The filename association is incomplete or invalid. ");break;
421                                         case SE_ERR_DDEBUSY : str=wxT("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
422                                         case SE_ERR_DDEFAIL : str=wxT("The DDE transaction failed. ");break;
423                                         case SE_ERR_DDETIMEOUT : str=wxT("The DDE transaction could not be completed because the request timed out. ");break;
424                                         case SE_ERR_DLLNOTFOUND : str=wxT("The specified dynamic-link library was not found. ");break;
425                                         //case SE_ERR_FNF : str=wxT("The specified file was not found. ");break;
426                                         case SE_ERR_NOASSOC : str=wxT("There is no application associated with the given filename extension. ");break;
427                                         case SE_ERR_OOM : str=wxT("There was not enough memory to complete the operation. ");break;
428                                         //case SE_ERR_PNF : str=wxT("The specified path was not found. ");break;
429                                         case SE_ERR_SHARE : str=wxT("A sharing violation occurred. ");break;
430                                         default: str=wxT("An unexpected error occurred");break;
431                                 }
432                                 MessageBoxF(wxT("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
433                         } else {
434                                 rc=true;
435                         }
436                 }
437         }
438         return rc;
439 }
440
441 #endif
442
443 void ecUtils::UnicodeToCStr(const wxChar* str,char *&psz)
444 {
445     int nLength=1 + wxStrlen(str);
446     psz=new char[nLength];
447 #ifdef _UNICODE
448     WideCharToMultiByte(CP_ACP, 0, str, -1, psz, nLength, NULL, NULL);
449 #else
450     strcpy(psz,str);
451 #endif
452 }
453
454 std::string ecUtils::UnicodeToStdStr(const wxChar* str)
455 {
456     std::string stdstr;
457     char *psz;
458     UnicodeToCStr(str,psz);
459     stdstr=std::string(psz);
460     delete psz;
461     return stdstr;
462 }
463
464 // ecUtils::StripExtraWhitespace() returns a modified version of
465 // a string in which each sequence of whitespace characters is
466 // replaced by a single space
467
468 static bool ecIsSpace(wxChar ch)
469 {
470         return (ch == wxT(' ') || ch == wxT('\r') || ch == wxT('\n') || ch == wxT('\t'));
471 }
472
473 wxString ecUtils::StripExtraWhitespace (const wxString & strInput)
474 {
475     wxString strOutput;
476     wxChar* o=strOutput.GetWriteBuf(1+strInput.Len());
477     for(const wxChar* c=strInput.GetData();*c;c++){
478         if(ecIsSpace(*c)){
479             *o++=wxT(' ');
480             if (ecIsSpace(c[1])){
481                 for(c=c+2; ecIsSpace(*c);c++);
482                 c--;
483             }
484         } else {
485             *o++=*c;
486         }
487     }
488     *o=0;
489     strOutput.UngetWriteBuf();
490     strOutput.Trim(TRUE);
491     strOutput.Trim(FALSE);
492     return strOutput;
493 #if 0    
494     wxString strOutput;
495     LPTSTR o=strOutput.GetBuffer(1+strInput.GetLength());
496     for(LPCTSTR c=strInput;*c;c++){
497         if(_istspace(*c)){
498             *o++=_TCHAR(' ');
499             if (_istspace(c[1])){
500                 for(c=c+2;_istspace(*c);c++);
501                 c--;
502             }
503         } else {
504             *o++=*c;
505         }
506     }
507     *o=0;
508     strOutput.ReleaseBuffer();
509     strOutput.TrimLeft();
510     strOutput.TrimRight();
511     return strOutput;
512 #endif
513 }
514
515 #if 0
516 ecFileName ecUtils::WPath(const std::string &str)
517 {
518   // Convert a path as read from cdl into host format
519   // Change / to \ throughout
520   ecFileName
521     strPath(str.c_str());
522   strPath.Replace (_TCHAR('/'), _TCHAR('\\'));
523   return strPath;
524 }
525
526 // Copy file helper function.
527 // This makes sure the destination file is only touched as necessary.
528 // It is written using Posix calls lest it should be more broadly applicable.
529
530 bool ecUtils::CopyFile(LPCTSTR pszSource,LPCTSTR pszDest)
531 {
532   // Compare the files.  First set rc to the result of the comparison (true if the same)
533   bool rc=false;
534
535   struct _stat s1,s2;
536   if(-1!=_tstat(pszSource,&s1) && -1!=_tstat(pszDest,&s2) && s1.st_size==s2.st_size){
537     // Files both exist and are of equal size
538     FILE *f1=_tfopen(pszSource,wxT("rb"));
539     if(f1){
540       FILE *f2=_tfopen(pszDest,wxT("rb"));
541       if(f2){
542         int nSize1,nSize2;
543         rc=true;
544         do{
545           char buf1[4096],buf2[4096];
546           nSize1=fread(buf1,1,sizeof buf1,f1);
547           nSize2=fread(buf2,1,sizeof buf2,f2);
548           if(nSize1!=nSize2 || 0!=memcmp(buf1,buf2,nSize1)){
549             rc=false;
550             break;
551           }
552         } while (nSize1>0);
553         fclose(f2);
554       }
555       fclose(f1);
556     }
557   }
558
559   if(rc){
560     // Files are identical
561   } else {
562     rc=TRUE==::CopyFile(pszSource,pszDest,FALSE);
563     if(rc){
564     } else {
565       MessageBoxF(wxT("Failed to copy '%s' to '%s' - %s"),pszSource,pszDest,GetLastErrorMessageString());
566     }
567   }
568
569   return rc;
570 }
571
572 #endif
573
574 /*
575  * wxStringToStringMap
576  *
577  * Stores string values keyed by strings
578  */
579
580 void wxStringToStringMap::Set(const wxString& key, const wxString& value)
581 {
582     wxString oldValue;
583     if (Find(key, oldValue))
584         Remove(key);
585     m_hashTable.Put(key, (wxObject*) new wxString(value));
586 }
587
588 bool wxStringToStringMap::Remove(const wxString& key)
589 {
590     wxString* str = (wxString*) m_hashTable.Delete(key);
591     if (str)
592     {
593         delete str;
594         return TRUE;
595     }
596     else
597         return FALSE;
598 }
599
600 bool wxStringToStringMap::Find(const wxString& key, wxString& value)
601 {
602     wxString* str = (wxString*) m_hashTable.Get(key);
603     if (str)
604     {
605         value = * str;
606         return TRUE;
607     }
608     else
609         return FALSE;
610 }
611
612 void wxStringToStringMap::Clear()
613 {
614     m_hashTable.BeginFind();
615     wxNode* node;
616     while ((node = m_hashTable.Next()))
617     {
618         wxString* str = (wxString*) node->Data();
619         delete str;
620     }
621 }
622
623 void wxStringToStringMap::BeginFind()
624 {
625     m_hashTable.BeginFind();
626 }
627
628 bool wxStringToStringMap::Next(wxString& key, wxString& value)
629 {
630     wxNode* node = m_hashTable.Next();
631     if (node)
632     {
633         value = * (wxString*) node->Data();
634         return TRUE;
635     }
636     else
637         return FALSE;
638 }
639
640 // Is str a member of arr?
641 bool wxArrayStringIsMember(const wxArrayString& arr, const wxString& str)
642 {
643     size_t i;
644     for (i = (size_t) 0; i < arr.GetCount(); i++)
645         if (arr[i] == str)
646             return TRUE;
647
648     return FALSE;
649 }
650
651 // Eliminate .. and .
652 wxString wxGetRealPath(const wxString& path)
653 {
654     wxChar* p = new wxChar[path.Len() + 1];
655     wxStrcpy(p, (const wxChar*) path);
656     wxRealPath(p);
657
658     wxString str(p);
659     delete[] p;
660     return str;
661 }
662
663 // A version of the above but prepending 'cwd' (current path) first
664 // if 'path' is relative
665 wxString wxGetRealPath(const wxString& cwd, const wxString& path)
666 {
667     wxString path1(path);
668
669     if (!wxIsAbsolutePath(path))
670     {
671         path1 = cwd;
672         if (path1.Last() != wxFILE_SEP_PATH)
673             path1 += wxFILE_SEP_PATH;
674         path1 += path;
675     }
676
677     return wxGetRealPath(path1);
678 }
679
680 // Find the absolute path where this application has been run from.
681 // argv0 is wxTheApp->argv[0]
682 // cwd is the current working directory (at startup)
683 // appVariableName is the name of a variable containing the directory for this app, e.g.
684 // MYAPPDIR. This is checked first.
685
686 wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName)
687 {
688     wxString str;
689
690     // Try appVariableName
691     if (!appVariableName.IsEmpty())
692     {
693         str = wxGetenv(appVariableName);
694         if (!str.IsEmpty())
695             return str;
696     }
697
698     if (wxIsAbsolutePath(argv0))
699         return wxPathOnly(argv0);
700     else
701     {
702         // Is it a relative path?
703         wxString currentDir(cwd);
704         if (currentDir.Last() != wxFILE_SEP_PATH)
705             currentDir += wxFILE_SEP_PATH;
706
707         str = currentDir + argv0;
708         if (wxFileExists(str))
709             return wxPathOnly(str);
710     }
711
712     // OK, it's neither an absolute path nor a relative path.
713     // Search PATH.
714
715     wxPathList pathList;
716     pathList.AddEnvList(wxT("PATH"));
717     str = pathList.FindAbsoluteValidPath(argv0);
718     if (!str.IsEmpty())
719         return wxPathOnly(str);
720
721     // Failed
722     return wxEmptyString;
723 }
724
725 // Make a path name with no separators, out of a full pathname,
726 // e.g. opt_ecos_ecos-1.4.5 out of /opt/ecos/ecos-1.4.5
727 wxString ecMakeNameFromPath(const wxString& path)
728 {
729     wxString p(path);
730     p.Replace(wxT("/"), wxT("_"));
731     p.Replace(wxT("\\"), wxT("_"));
732     p.Replace(wxT(":"), wxT("_"));
733     return p;
734 }
735
736
737 // Find the text of the list control item at the given column
738 wxString wxListCtrlGetItemTextColumn(wxListCtrl& listCtrl, long item, int col)
739 {
740     wxListItem listItem;
741     listItem.m_mask = wxLIST_MASK_TEXT;
742     listItem.m_itemId = item;
743     listItem.m_col = col;
744
745     if (listCtrl.GetItem(listItem))
746         return listItem.m_text;
747     else
748         return wxEmptyString;
749 }
750
751 // Select the given item
752 void wxListCtrlSelectItem(wxListCtrl& listCtrl, long sel, bool deselectOthers)
753 {
754     long n = listCtrl.GetItemCount();
755     long i;
756     if (deselectOthers)
757     {
758         for (i = 0; i < n; i++)
759         {
760             if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
761             {
762                 listCtrl.SetItemState(i, wxLIST_STATE_SELECTED, 0);
763             }
764         }
765     }
766     listCtrl.SetItemState(sel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
767 }
768
769 // Find the selection
770 long wxListCtrlGetSelection(wxListCtrl& listCtrl)
771 {
772     long n = listCtrl.GetItemCount();
773     long i;
774     for (i = 0; i < n; i++)
775     {
776         if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
777         {
778             return i;
779         }
780     }
781     return -1;
782 }
783
784 // Find which column the cursor is on
785 int wxListCtrlFindColumn(wxListCtrl& listCtrl, int noCols, int x)
786 {
787     int col = 0;
788     
789     // Find which column we're on
790     int width = 0;
791     int i;
792     for (i = 0; i < noCols; i++)
793     {
794         width += listCtrl.GetColumnWidth(i);
795         if (x <= width)
796         {
797             col = i;
798             break;
799         }
800     }
801     return col;
802 }
803
804 // Utility function
805 void wxRefreshControls(wxWindow* win)
806 {
807     wxNode *node = win->GetChildren().First();
808     while (node)
809     {
810         wxWindow* win = (wxWindow*) node->Data();
811         win->Refresh();
812         node = node->Next();
813     }
814 }
815
816 wxOutputStream& operator <<(wxOutputStream& stream, const wxString& s)
817 {
818     stream.Write(s, s.Length());
819     return stream;
820 }
821
822 wxOutputStream& operator <<(wxOutputStream& stream, long l)
823 {
824     wxString str;
825     str.Printf("%ld", l);
826     return stream << str;
827 }
828
829 wxOutputStream& operator <<(wxOutputStream& stream, const char c)
830 {
831     wxString str;
832     str.Printf("%c", c);
833     return stream << str;
834 }
835
836 /*
837  * ecDialog
838  * Supports features we want to have for all dialogs in the application.
839  * So far, this just allows dialogs to be resizeable under MSW by
840  * refreshing the controls in OnSize (otherwise there's a mess)
841  */
842
843 IMPLEMENT_CLASS(ecDialog, wxDialog)
844
845 BEGIN_EVENT_TABLE(ecDialog, wxDialog)
846 #ifdef __WXMSW__
847     EVT_SIZE(ecDialog::OnSize)
848 #endif
849 END_EVENT_TABLE()
850
851 void ecDialog::OnSize(wxSizeEvent& event)
852 {
853     wxDialog::OnSize(event);
854
855     wxRefreshControls(this);
856 }
857
858 /*
859  * Implements saving/loading of window settings - fonts only for now
860  */
861
862 wxWindowSettingsObject* wxWindowSettings::FindSettings(const wxString& windowName) const
863 {
864     wxNode* node = m_settings.First();
865     while (node)
866     {
867         wxWindowSettingsObject* obj = (wxWindowSettingsObject*) node->Data();
868         if (obj->m_windowName.CmpNoCase(windowName) == 0)
869             return obj;
870         node = node->Next();
871     }
872     return NULL;
873 }
874
875 bool wxWindowSettings::LoadConfig(wxConfigBase& config)
876 {
877     unsigned int i = 0;
878     for (i = 0; i < GetCount(); i++)
879     {
880         wxWindowSettingsObject* obj = GetNth(i);
881
882         wxString name(obj->m_windowName);
883         name.Replace(wxT(" "), wxT(""));
884
885         LoadFont(config, name, obj->m_font);
886     }
887
888     return TRUE;
889 }
890
891 bool wxWindowSettings::SaveConfig(wxConfigBase& config)
892 {
893     unsigned int i = 0;
894     for (i = 0; i < GetCount(); i++)
895     {
896         wxWindowSettingsObject* obj = GetNth(i);
897
898         wxString name(obj->m_windowName);
899         name.Replace(wxT(" "), wxT(""));
900
901         SaveFont(config, name, obj->m_font);
902     }
903
904     return TRUE;
905 }
906
907 // Load and save font descriptions
908 bool wxWindowSettings::LoadFont(wxConfigBase& config, const wxString& windowName, wxFont& font)
909 {
910     wxString pathBase(wxT("/Fonts/"));
911     pathBase += windowName;
912     pathBase += wxT("/");
913
914     int pointSize, family, style, weight;
915     bool underlined = FALSE;
916     wxString faceName;
917
918     if (!config.Read(pathBase + wxT("PointSize"), & pointSize))
919         return FALSE;
920
921     if (!config.Read(pathBase + wxT("Family"), & family))
922         return FALSE;
923
924     if (!config.Read(pathBase + wxT("Style"), & style))
925         return FALSE;
926
927     if (!config.Read(pathBase + wxT("Weight"), & weight))
928         return FALSE;
929
930     config.Read(pathBase + wxT("Underlined"), (bool*) & underlined);
931     config.Read(pathBase + wxT("FaceName"), & faceName);
932
933     wxFont font1(pointSize, family, style, weight, underlined, faceName);
934     font = font1;
935
936     return TRUE;    
937 }
938
939 bool wxWindowSettings::SaveFont(wxConfigBase& config, const wxString& windowName, const wxFont& font)
940 {
941     if (!font.Ok())
942         return FALSE;
943
944     wxString pathBase(wxT("/Fonts/"));
945     pathBase += windowName;
946     pathBase += wxT("/");
947
948     config.Write(pathBase + wxT("PointSize"), (long) font.GetPointSize());
949     config.Write(pathBase + wxT("Family"), (long) font.GetFamily());
950     config.Write(pathBase + wxT("Style"), (long) font.GetStyle());
951     config.Write(pathBase + wxT("Weight"), (long) font.GetWeight());
952     config.Write(pathBase + wxT("Underlined"), (long) font.GetUnderlined());
953     config.Write(pathBase + wxT("FaceName"), font.GetFaceName());
954
955     return TRUE;    
956 }
957
958 wxFont wxWindowSettings::GetFont(const wxString& name) const
959 {
960     wxWindowSettingsObject* obj = FindSettings(name);
961     if (!obj)
962         return wxFont();
963     else
964         return obj->m_font;
965 }
966
967 void wxWindowSettings::SetFont(const wxString& name, const wxFont& font)
968 {
969     wxWindowSettingsObject* obj = FindSettings(name);
970     if (!obj)
971     {
972         obj = new wxWindowSettingsObject(name, NULL) ;
973         obj->m_font = font;
974         m_settings.Append(obj);
975     }
976     obj->m_font = font;
977 }
978
979 wxWindow* wxWindowSettings::GetWindow(const wxString& name) const
980 {
981     wxWindowSettingsObject* obj = FindSettings(name);
982     if (!obj)
983         return NULL;
984     if (obj->m_arrWindow.GetCount() > 0)
985         return (wxWindow*) obj->m_arrWindow[0];
986     else
987         return NULL;
988 }
989
990 void wxWindowSettings::SetWindow(const wxString& name, wxWindow* win)
991 {
992     wxWindowSettingsObject* obj = FindSettings(name);
993     if (!obj)
994     {
995         obj = new wxWindowSettingsObject(name, win) ;
996         m_settings.Append(obj);
997     }
998     obj->m_arrWindow.Clear();
999
1000     if (win)
1001         obj->m_arrWindow.Add(win);
1002 }
1003
1004 wxArrayPtrVoid* wxWindowSettings::GetWindows(const wxString& name) const
1005 {
1006     wxWindowSettingsObject* obj = FindSettings(name);
1007     if (!obj)
1008         return NULL;
1009     return & obj->m_arrWindow ;
1010 }
1011
1012 void wxWindowSettings::SetWindows(const wxString& name, wxArrayPtrVoid& arr)
1013 {
1014     wxWindowSettingsObject* obj = FindSettings(name);
1015     if (!obj)
1016     {
1017         obj = new wxWindowSettingsObject(name, NULL) ;
1018         m_settings.Append(obj);
1019     }
1020     obj->m_arrWindow.Clear() ;
1021     obj->m_arrWindow = arr;
1022 }
1023
1024 bool wxWindowSettings::ApplyFontsToWindows()
1025 {
1026     if (m_useDefaults)
1027         return FALSE;
1028
1029     unsigned int i = 0;
1030     for (i = 0; i < GetCount(); i++)
1031     {
1032         wxWindowSettingsObject* obj = GetNth(i);
1033
1034         unsigned int j = 0;
1035         for (j = 0; j < obj->m_arrWindow.GetCount(); j++)
1036         {
1037             wxWindow* win = (wxWindow*) obj->m_arrWindow[j];
1038             win->SetFont(obj->m_font);
1039             win->Refresh();
1040         }
1041     }
1042     return TRUE;
1043 }
1044
1045 #ifdef __WIN32__
1046 // This will be obsolete when we switch to using the version included
1047 // in wxWindows (from wxWin 2.3.1 onwards)
1048 enum ecKillError
1049 {
1050     ecKILL_OK,              // no error
1051     ecKILL_BAD_SIGNAL,      // no such signal
1052     ecKILL_ACCESS_DENIED,   // permission denied
1053     ecKILL_NO_PROCESS,      // no such process
1054     ecKILL_ERROR            // another, unspecified error
1055 };
1056 #endif
1057
1058 // ----------------------------------------------------------------------------
1059 // process management
1060 // ----------------------------------------------------------------------------
1061
1062 #ifdef __WIN32__
1063
1064 // structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
1065 struct wxNewFindByPidParams
1066 {
1067     wxNewFindByPidParams() { hwnd = 0; pid = 0; }
1068
1069     // the HWND used to return the result
1070     HWND hwnd;
1071
1072     // the PID we're looking from
1073     DWORD pid;
1074 };
1075
1076 // wxKill helper: EnumWindows() callback which is used to find the first (top
1077 // level) window belonging to the given process
1078 static BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
1079 {
1080     DWORD pid;
1081     (void)::GetWindowThreadProcessId(hwnd, &pid);
1082
1083     wxNewFindByPidParams *params = (wxNewFindByPidParams *)lParam;
1084     if ( pid == params->pid )
1085     {
1086         // remember the window we found
1087         params->hwnd = hwnd;
1088
1089         // return FALSE to stop the enumeration
1090         return FALSE;
1091     }
1092
1093     // continue enumeration
1094     return TRUE;
1095 }
1096
1097 // This will be obsolete when we switch to using the version included
1098 // in wxWindows (from wxWin 2.3.1 onwards)
1099 int wxNewKill(long pid, wxSignal sig, ecKillError *krc = NULL)
1100 {
1101 #ifdef __WIN32__
1102     // get the process handle to operate on
1103     HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
1104                                     PROCESS_TERMINATE |
1105                                     PROCESS_QUERY_INFORMATION,
1106                                     FALSE, // not inheritable
1107                                     (DWORD)pid);
1108     if ( hProcess == NULL )
1109     {
1110         if ( krc )
1111         {
1112             if ( ::GetLastError() == ERROR_ACCESS_DENIED )
1113             {
1114                 *krc = ecKILL_ACCESS_DENIED;
1115             }
1116             else
1117             {
1118                 *krc = ecKILL_NO_PROCESS;
1119             }
1120         }
1121
1122         return -1;
1123     }
1124
1125     bool ok = TRUE;
1126     switch ( sig )
1127     {
1128         case wxSIGKILL:
1129             // kill the process forcefully returning -1 as error code
1130             if ( !::TerminateProcess(hProcess, (UINT)-1) )
1131             {
1132                 wxLogSysError(_("Failed to kill process %d"), pid);
1133
1134                 if ( krc )
1135                 {
1136                     // this is not supposed to happen if we could open the
1137                     // process
1138                     *krc = ecKILL_ERROR;
1139                 }
1140
1141                 ok = FALSE;
1142             }
1143             break;
1144
1145         case wxSIGNONE:
1146             // do nothing, we just want to test for process existence
1147             break;
1148
1149         default:
1150             // any other signal means "terminate"
1151             {
1152                 wxNewFindByPidParams params;
1153                 params.pid = (DWORD)pid;
1154
1155                 // EnumWindows() has nice semantics: it returns 0 if it found
1156                 // something or if an error occured and non zero if it
1157                 // enumerated all the window
1158                 if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
1159                 {
1160                     // did we find any window?
1161                     if ( params.hwnd )
1162                     {
1163                         // tell the app to close
1164                         //
1165                         // NB: this is the harshest way, the app won't have
1166                         //     opportunity to save any files, for example, but
1167                         //     this is probably what we want here. If not we
1168                         //     can also use SendMesageTimeout(WM_CLOSE)
1169                         if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
1170                         {
1171                             wxLogLastError(_T("PostMessage(WM_QUIT)"));
1172                         }
1173                     }
1174                     else // it was an error then
1175                     {
1176                         wxLogLastError(_T("EnumWindows"));
1177
1178                         ok = FALSE;
1179                     }
1180                 }
1181                 else // no windows for this PID
1182                 {
1183                     if ( krc )
1184                     {
1185                         *krc = ecKILL_ERROR;
1186                     }
1187
1188                     ok = FALSE;
1189                 }
1190             }
1191     }
1192
1193     // the return code
1194     DWORD rc;
1195
1196     if ( ok )
1197     {
1198         // as we wait for a short time, we can use just WaitForSingleObject()
1199         // and not MsgWaitForMultipleObjects()
1200         switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
1201         {
1202             case WAIT_OBJECT_0:
1203                 // process terminated
1204                 if ( !::GetExitCodeProcess(hProcess, &rc) )
1205                 {
1206                     wxLogLastError(_T("GetExitCodeProcess"));
1207                 }
1208                 break;
1209
1210             default:
1211                 wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
1212                 // fall through
1213
1214             case WAIT_FAILED:
1215                 wxLogLastError(_T("WaitForSingleObject"));
1216                 // fall through
1217
1218             case WAIT_TIMEOUT:
1219                 if ( krc )
1220                 {
1221                     *krc = ecKILL_ERROR;
1222                 }
1223
1224                 rc = STILL_ACTIVE;
1225                 break;
1226         }
1227     }
1228     else // !ok
1229     {
1230         // just to suppress the warnings about uninitialized variable
1231         rc = 0;
1232     }
1233
1234     ::CloseHandle(hProcess);
1235
1236     // the return code is the same as from Unix kill(): 0 if killed
1237     // successfully or -1 on error
1238     if ( sig == wxSIGNONE )
1239     {
1240         if ( ok && rc == STILL_ACTIVE )
1241         {
1242             // there is such process => success
1243             return 0;
1244         }
1245     }
1246     else // not SIGNONE
1247     {
1248         if ( ok && rc != STILL_ACTIVE )
1249         {
1250             // killed => success
1251             return 0;
1252         }
1253     }
1254 #else // Win15
1255     wxFAIL_MSG( _T("not implemented") );
1256 #endif // Win32/Win16
1257
1258     // error
1259     return -1;
1260 }
1261 #endif
1262
1263 int ecKill(long pid, wxSignal sig)
1264 {
1265 #if defined(__UNIX__) && !defined(__CYGWIN__)
1266     return wxKill(pid, sig);
1267 #elif defined(__WXMSW__)
1268     return wxNewKill(pid, sig);
1269 #else
1270     return -1;
1271 #endif
1272 }
1273
1274 #ifdef _WIN32
1275   #include <tlhelp32.h>
1276
1277   WXHINSTANCE wxProcessKiller::hInstLib1 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("PSAPI.DLL")) : (WXHINSTANCE) LoadLibrary(_T("Kernel32.DLL")) ;
1278   WXHINSTANCE wxProcessKiller::hInstLib2 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("NTDLL.DLL")): (WXHINSTANCE) NULL;
1279
1280 #endif
1281
1282 const unsigned int wxProcessKiller::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;
1283
1284 wxProcessKiller::wxProcessKiller(int pid):
1285   m_bVerbose(false),
1286   m_nExitCode(-1),
1287   m_idProcess(pid)
1288 {
1289 #ifdef _WIN32
1290       m_hProcess = (WXHANDLE) ::OpenProcess(SYNCHRONIZE |
1291           PROCESS_TERMINATE |
1292           PROCESS_QUERY_INFORMATION,
1293           FALSE, // not inheritable
1294           (DWORD) m_idProcess);
1295 #endif
1296 }
1297
1298 wxProcessKiller::~wxProcessKiller()
1299 {
1300 #ifdef _WIN32
1301     if (m_hProcess)
1302     {
1303         ::CloseHandle((HANDLE) m_hProcess);
1304     }
1305 #endif
1306 }
1307
1308 bool wxProcessKiller::Kill(bool bRecurse)
1309 {
1310     wxPInfoArray arPinfo;
1311     bool rc=false;
1312     if(m_idProcess && -1!=m_idProcess){
1313         // Start of with the easy one:
1314         if(bRecurse) {
1315             // Need to gather this information before we orphan our grandchildren:
1316             PSExtract(arPinfo);
1317         }
1318         
1319 #ifdef _WIN32
1320         
1321         if(m_hProcess){
1322             rc=(TRUE==::TerminateProcess((HANDLE) m_hProcess,PROCESS_KILL_EXIT_CODE));
1323             // dtor's (or subsequent Run's) responsibility to close the handle
1324         }
1325         
1326 #else
1327         rc=(0==kill(m_idProcess,SIGTERM));
1328         int status;
1329         waitpid(m_idProcess,&status,WNOHANG);
1330 #endif
1331         
1332         if(bRecurse) {
1333             // kill process *and* its children
1334             // FIXME: needs to be top-down
1335             for(int i=0;i<(signed)arPinfo.size();i++){
1336                 if(arPinfo[i].IsChildOf(m_idProcess)){
1337                     
1338 #ifdef _WIN32
1339                     // begin hack
1340                     // WHY NECESSARY??
1341                     const wxString strName(Name(arPinfo[i].PID));
1342                     if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){
1343                         continue;
1344                     }
1345                     // end hack
1346                     HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID);
1347                     if(hProcess){
1348                         rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE));
1349                         CloseHandle(hProcess);
1350                     } else {
1351                         rc=false;
1352                     }
1353 #else
1354                     rc&=(0==kill(arPinfo[i].PID,SIGTERM));
1355                     int status;
1356                     waitpid(arPinfo[i].PID,&status,WNOHANG);
1357 #endif
1358                 }
1359             }
1360         }
1361     }
1362     return rc;
1363 }
1364
1365 #ifdef _WIN32
1366 bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
1367 {
1368     bool rc=false;
1369     arPinfo.clear();
1370     // If Windows NT:
1371     switch(GetPlatform()) {
1372     case VER_PLATFORM_WIN32_NT:
1373         if(hInstLib1) {
1374             
1375             // Get procedure addresses.
1376             static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( (HINSTANCE) hInstLib1, "EnumProcesses" ) ;
1377             if( lpfEnumProcesses) {
1378                 
1379                 if(hInstLib2) {
1380                     
1381                     static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
1382                         (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib2,"NtQueryInformationProcess" ) ;
1383                     
1384                     if(lpfNtQueryInformationProcess){
1385                         DWORD dwMaxPids=256;
1386                         DWORD dwPidSize;
1387                         DWORD *arPids = NULL ;
1388                         do {
1389                             delete [] arPids;
1390                             arPids=new DWORD[dwMaxPids];
1391                         } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
1392                         
1393                         if(dwPidSize/sizeof(DWORD)<dwMaxPids){
1394                             rc=true;
1395                             for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
1396                                 // Regardless of OpenProcess success or failure, we
1397                                 // still call the enum func with the ProcID.
1398                                 DWORD pid=arPids[dwIndex];
1399                                 HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ); 
1400                                 if (hProcess ) {
1401                                     struct {
1402                                         DWORD ExitStatus; // receives process termination status
1403                                         DWORD PebBaseAddress; // receives process environment block address
1404                                         DWORD AffinityMask; // receives process affinity mask
1405                                         DWORD BasePriority; // receives process priority class
1406                                         ULONG UniqueProcessId; // receives process identifier
1407                                         ULONG InheritedFromUniqueProcessId; // receives parent process identifier
1408                                     } pbi;
1409                                     memset( &pbi, 0, sizeof(pbi)); 
1410                                     DWORD retLen; 
1411                                     __int64 ftCreation,ftExit,ftKernel,ftUser;
1412                                     if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
1413                                         TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
1414                                         // The second test is important.  It excludes orphaned processes who appear to have been adopted by virtue of a new
1415                                         // process having been created with the same ID as their original parent.
1416                                         wxPInfo p;
1417                                         p.PID=pid;
1418                                         p.PPID=pbi.InheritedFromUniqueProcessId;
1419                                         p.tCreation=ftCreation;
1420                                         p.tCpu=Time((ftKernel+ftUser)/10000);
1421                                         arPinfo.push_back(p);
1422                                     }
1423                                     
1424                                     CloseHandle(hProcess); 
1425                                     
1426                                 }
1427                             }
1428                         }
1429                         delete [] arPids;
1430                     }          
1431                 }
1432             }      
1433         }
1434         break;
1435     case VER_PLATFORM_WIN32_WINDOWS:
1436         
1437         if( hInstLib1) {
1438             
1439             static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
1440                 (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( (HINSTANCE) hInstLib1,"CreateToolhelp32Snapshot" ) ;
1441             static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
1442                 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32First" ) ;
1443             static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
1444                 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32Next" ) ;
1445             if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
1446                 
1447                 // Get a handle to a Toolhelp snapshot of the systems
1448                 // processes.
1449                 HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
1450                 if(INVALID_HANDLE_VALUE != hSnapShot) {
1451                     // Get the first process' information.
1452                     PROCESSENTRY32 procentry;
1453                     procentry.dwSize = sizeof(PROCESSENTRY32) ;
1454                     if(lpfProcess32First( hSnapShot, &procentry )){
1455                         rc=true;
1456                         do {
1457                             wxPInfo p;
1458                             p.PID=procentry.th32ProcessID;
1459                             p.PPID=procentry.th32ParentProcessID;
1460                             arPinfo.push_back(p);
1461                         } while(lpfProcess32Next( hSnapShot, &procentry ));
1462                     }
1463                     CloseHandle(hSnapShot);
1464                 }
1465             }
1466         }
1467         break;
1468     default:
1469         break;
1470     }    
1471     
1472     SetParents(arPinfo);
1473     
1474     if(!rc){
1475         wxLogError(_T("Couldn't get process information!\n"));
1476     }
1477     return rc;
1478 }
1479
1480 #else // UNIX
1481
1482 bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
1483 {
1484     arPinfo.clear();
1485     int i;
1486     FILE *f=popen("ps -l",_T("r") MODE_TEXT);
1487     if(f){
1488         char buf[100];
1489         while(fgets(buf,sizeof(buf)-1,f)){
1490             TCHAR discard[100];
1491             wxPInfo p;
1492             // Output is in the form
1493             //  F S   UID   PID  PPID  C PRI  NI ADDR    SZ WCHAN  TTY          TIME CMD
1494             //100 S   490   877   876  0  70   0    -   368 wait4  pts/0    00:00:00 bash
1495             int F,UID,C,PRI,NI,SZ,HH,MM,SS; 
1496             bool rc=(15==_stscanf(buf,_T("%d %s %d %d %d %d %d %d %s %d %s %s %d:%d:%d"),&F,discard,&UID,&p.PID,&p.PPID,&C,&PRI,&NI,discard,&SZ,discard,discard,&HH,&MM,&SS));
1497             if(rc){
1498                 p.tCpu=1000*(SS+60*(60*HH+MM));
1499                 arPinfo.push_back(p);
1500             }
1501         }
1502         pclose(f);
1503         for(i=0;i<(signed)arPinfo.size();i++){
1504             int pid=arPinfo[i].PPID;
1505             arPinfo[i].pParent=0;
1506             for(int j=0;j<(signed)arPinfo.size();j++){
1507                 if(i!=j && arPinfo[j].PID==pid){
1508                     arPinfo[i].pParent=&arPinfo[j];
1509                     break;
1510                 }
1511             }
1512         }
1513     } else {
1514         wxLogError(_T("Failed to run ps -l\n"));
1515     }
1516     return true; //FIXME
1517 }
1518
1519 #endif
1520
1521 void wxProcessKiller::SetParents(wxProcessKiller::wxPInfoArray &arPinfo)
1522 {
1523     int i;
1524     for(i=0;i<(signed)arPinfo.size();i++){
1525         wxPInfo &p=arPinfo[i];
1526         p.pParent=0;
1527         for(int j=0;j<(signed)arPinfo.size();j++){
1528             if(arPinfo[j].PID==p.PPID 
1529 #ifdef _WIN32
1530                 && arPinfo[j].tCreation<p.tCreation
1531 #endif
1532                 )
1533             {
1534                 arPinfo[i].pParent=&arPinfo[j];
1535                 break;
1536             }
1537         }
1538     }
1539     
1540     // Check for circularity
1541     bool bCircularity=false;
1542     for(i=0;i<(signed)arPinfo.size();i++){
1543         wxPInfo *p=&arPinfo[i];
1544         for(int j=0;j<(signed)arPinfo.size() && p;j++){
1545             p=p->pParent;
1546         }
1547         // If all is well, p should be NULL here.  Otherwise we have a loop.
1548         if(p){
1549             // Make sure it can't foul things up:
1550             arPinfo[i].pParent=0;
1551             bCircularity=true;
1552         }
1553     }
1554     
1555     if(bCircularity){
1556         wxLogError(_T("!!! Circularly linked process list at index %d\n"),i);
1557         for(int k=0;k<(signed)arPinfo.size();k++){
1558             const wxPInfo &p=arPinfo[k];
1559             wxLogError(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
1560         }
1561     }
1562 }
1563
1564 bool wxProcessKiller::wxPInfo::IsChildOf(int pid) const
1565 {
1566     for(wxPInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
1567         if(p->PID==pid){
1568             return true;
1569         }
1570     }
1571     return false;
1572 }
1573
1574 const wxString wxProcessKiller::Name(int pid)
1575 {
1576     wxString str;
1577     str.Printf(_T("id=%d"),pid);
1578 #ifdef _DEBUG
1579 #ifdef _WIN32
1580     if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){
1581         static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) =
1582             (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib1,"EnumProcessModules" ) ;
1583         static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )=
1584             (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( (HINSTANCE) hInstLib1,"GetModuleFileNameExA" ) ;
1585         if( lpfEnumProcessModules &&  lpfGetModuleFileNameEx ) {
1586             HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid);
1587             if(hProcess) {
1588                 HMODULE hMod;
1589                 DWORD dwSize;
1590                 if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){
1591                     // Get Full pathname:
1592                     TCHAR buf[1+MAX_PATH];
1593                     lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH);
1594                     str+=_TCHAR(' ');
1595                     str+=buf;
1596                 }
1597                 CloseHandle(hProcess);
1598             }
1599         }
1600     }
1601 #endif
1602 #endif
1603     return str;
1604 }
1605
1606 #ifdef _WIN32
1607 long wxProcessKiller::GetPlatform()
1608 {
1609     OSVERSIONINFO  osver;
1610     osver.dwOSVersionInfoSize = sizeof( osver ) ;
1611     return GetVersionEx( &osver ) ? (long) osver.dwPlatformId : (long)-1;
1612 }
1613 #endif
1614
1615 const wxString wxProcessKiller::ErrorString() const
1616 {
1617 #ifdef _WIN32
1618     TCHAR *pszMsg;
1619     FormatMessage(  
1620         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1621         NULL,
1622         m_nErr,
1623         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1624         (LPTSTR)&pszMsg,
1625         0,
1626         NULL 
1627         );
1628     return pszMsg;
1629 #else 
1630     return strerror(errno);
1631 #endif
1632 }
1633