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