]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - tools/src/tools/configtool/standalone/wxwin/ecutils.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / ecutils.cpp
diff --git a/tools/src/tools/configtool/standalone/wxwin/ecutils.cpp b/tools/src/tools/configtool/standalone/wxwin/ecutils.cpp
new file mode 100644 (file)
index 0000000..a7ec2e5
--- /dev/null
@@ -0,0 +1,1633 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+// Copyright (C) 2003 John Dallaway
+//
+// This program is part of the eCos host tools.
+//
+// This program is free software; you can redistribute it and/or modify it 
+// under the terms of the GNU General Public License as published by the Free 
+// Software Foundation; either version 2 of the License, or (at your option) 
+// any later version.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+// more details.
+// 
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+//
+//===========================================================================
+//===========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):  sdf, jld
+// Contact(s): sdf
+// Date:               1998/08/11
+// Version:            0.01
+// Purpose:    
+// Description:        This is a collection of utility functions.
+//              Modified by julians for wxWindows (originally CTUtils.h)
+// Requires:   
+// Provides:   
+// See also:    
+// Known bugs: 
+// Usage:      
+//
+//####DESCRIPTIONEND####
+//
+//===========================================================================
+
+#ifdef __GNUG__
+#pragma implementation "ecutils.h"
+#endif
+
+// Includes other headers for precompiled compilation
+#include "ecpch.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#include "ecutils.h"
+#include "wx/listctrl.h"
+#include "wx/stream.h"
+
+#include <float.h> // for DBL_DIG macro
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef __WXMSW__
+#include <errno.h>
+#endif
+
+#ifdef __WXMSW__
+#include <tlhelp32.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h> /* for cygwin_conv_to_*_path() */
+#endif
+
+#if 0
+
+#define INCLUDEFILE <string>
+#include "IncludeSTL.h"
+
+#endif
+
+// Chop str into pieces, using cSep as separator.
+// " and \ have usual semantics
+// Return value is array of pieces found.
+
+int ecUtils::Chop(const wxString& psz, wxArrayString &ar, wxChar cSep,
+                  bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
+
+{
+    if(wxT(' ') == cSep)
+    {
+        return Chop(psz, ar, wxT("\t\n\v\f\r "), bObserveStrings, bBackslashQuotes);
+    } else {
+        wxASSERT(wxT('\0')!=cSep);
+        wxChar c[2]={cSep,wxT('\0')};
+        return Chop(psz,ar,wxString(c),bObserveStrings,bBackslashQuotes);
+    }
+}
+
+int ecUtils::Chop(const wxString& str, wxArrayString &ar, const wxString& sep,
+                  bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
+{
+    ar.Clear();
+    
+    const wxChar* pszSep = (const wxChar*) sep;
+    const wxChar* psz = (const wxChar*) str;
+    
+    int i=0;
+    for(;;){
+        // Skip multiple separators
+        while(*psz && wxStrchr(pszSep,*psz)){
+            psz++;
+        }
+        if(!*psz){
+            return i;
+        }
+        wxString strTok;
+        if(bObserveStrings){
+            bool bInString=FALSE;
+            do{
+                if(*psz == wxT('\\') && bBackslashQuotes && psz[1]){
+                    strTok += psz[1];
+                    psz++;
+                } else if(*psz == wxT('"')){
+                    bInString ^= 1;
+                } else if (!bInString && *psz && NULL != wxStrchr(pszSep,*psz)) {
+                    break;
+                } else {
+                    strTok+=*psz;
+                }
+            } while (*++psz);
+        } else {
+            const wxChar* pszStart=psz;
+            do {
+                psz++;
+            } while (*psz && ! wxStrchr(pszSep,*psz));
+            strTok=wxString(pszStart,psz-pszStart);
+        }
+        ar.Add(strTok);
+        i++;
+    }
+    return ar.GetCount();
+}
+
+#if 0
+
+// vararg-style message box formatter
+int ecUtils::MessageBoxF (LPCTSTR pszFormat, ...)
+{
+  int rc;
+  va_list args;
+  va_start(args, pszFormat);
+  rc=ecUtils::vMessageBox(MB_OK, pszFormat,args);
+  va_end(args);
+  return rc;
+}
+
+// As above, but with type as first parameter.
+int ecUtils::MessageBoxFT (UINT nType, LPCTSTR pszFormat, ...)
+{
+  int rc;
+  va_list args;
+  va_start(args, pszFormat);
+  rc=ecUtils::vMessageBox(nType, pszFormat,args);
+  va_end(args);
+  return rc;
+}
+
+int ecUtils::vMessageBox(UINT nType, LPCTSTR  pszFormat, va_list marker)
+{
+  int rc=0;
+  for(int nLength=100;nLength;) {
+    TCHAR *buf=new TCHAR[1+nLength];
+    int n=_vsntprintf(buf, nLength, pszFormat, marker ); 
+    if(-1==n){
+      nLength*=2;  // NT behavior
+    } else if (n<nLength){
+      rc=AfxMessageBox(buf,nType);
+      nLength=0;   // trigger exit from loop
+    } else {
+      nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
+    }
+    delete [] buf;
+  }
+  return rc;
+}
+
+#endif
+
+bool ecUtils::StrToItemIntegerType(const wxString & str, long &d)
+{
+       wxChar* pEnd;
+       bool rc;
+       errno=0;
+       bool bHex=(str.Len() > 2 && str[0]==wxT('0') && (str[1]==wxT('x')||str[1]==wxT('X')));
+       //d=_tcstol(str,&pEnd,bHex?16:10);
+       d=wxStrtol(str,&pEnd,bHex?16:10);
+       rc=(0==errno && (*pEnd==wxT('\0')));
+       return rc;
+}
+
+const wxString ecUtils::IntToStr(long d,bool bHex)
+{
+  wxString s;
+  s.Printf(bHex?wxT("0x%08x"):wxT("%d"),d);
+  return s;
+}
+
+const wxString ecUtils::DoubleToStr (double dValue)
+{
+  wxString s;
+  s.Printf(wxT("%.*e"), DBL_DIG, dValue);
+  return s;
+}
+
+bool ecUtils::StrToDouble (const wxString & strValue, double &dValue)
+{
+       wxChar* pEnd;
+       errno = 0;
+       //dValue = _tcstod (strValue, &pEnd);
+       dValue = wxStrtod(strValue, &pEnd);
+       return (0 == errno) && (*pEnd == wxT('\0'));
+}
+
+#if 0
+const wxString ecUtils::Explanation(CFileException & exc)
+{
+       wxString strMsg;
+       switch(exc.m_cause){
+               case CFileException::none: strMsg=wxT("No error occurred.");break;
+               case CFileException::generic: strMsg=wxT("   An unspecified error occurred.");break;
+               case CFileException::fileNotFound: strMsg=wxT("   The file could not be located.");break;
+               case CFileException::badPath: strMsg=wxT("   All or part of the path is invalid.");break;
+               case CFileException::tooManyOpenFiles: strMsg=wxT("   The permitted number of open files was exceeded.");break;
+               case CFileException::accessDenied: strMsg=wxT("   The file could not be accessed.");break;
+               case CFileException::invalidFile: strMsg=wxT("   There was an attempt to use an invalid file handle.");break;
+               case CFileException::removeCurrentDir: strMsg=wxT("   The current working directory cannot be removed.");break;
+               case CFileException::directoryFull: strMsg=wxT("   There are no more directory entries.");break;
+               case CFileException::badSeek: strMsg=wxT("   There was an error trying to set the file pointer.");break;
+               case CFileException::hardIO: strMsg=wxT("   There was a hardware error.");break;
+               case CFileException::sharingViolation: strMsg=wxT("   SHARE.EXE was not loaded, or a shared region was locked.");break;
+               case CFileException::lockViolation: strMsg=wxT("   There was an attempt to lock a region that was already locked.");break;
+               case CFileException::diskFull: strMsg=wxT("   The disk is full.");break;
+               case CFileException::endOfFile: strMsg=wxT("   The end of file was reached. ");break;
+               default:
+                       strMsg=wxT(" Unknown cause");
+                       break;
+       }
+       return strMsg;
+}
+
+
+const wxString ecUtils::LoadString(UINT id)
+{
+       wxString str;
+       str.LoadString(id);
+       return str;
+}
+#endif
+
+const wxString ecUtils::NativeToPosixPath(const wxString & native)
+{
+#ifdef __CYGWIN__
+    if (native.IsEmpty())
+        return native;
+    else
+    {
+        wxString posix;
+        cygwin_conv_to_posix_path(native.c_str(), posix.GetWriteBuf(MAXPATHLEN + 1));
+        posix.UngetWriteBuf();
+        return posix;
+    }
+#else
+    return native;
+#endif
+}
+
+const wxString ecUtils::PosixToNativePath(const wxString & posix)
+{
+#ifdef __CYGWIN__
+    if (posix.IsEmpty())
+        return posix;
+    else
+    {
+        wxString native;
+        cygwin_conv_to_win32_path(posix.c_str(), native.GetWriteBuf(MAXPATHLEN + 1));
+        native.UngetWriteBuf();
+        return native;
+    }
+#else
+    return posix;
+#endif
+}
+
+bool ecUtils::AddToPath(const ecFileName & strFolder, bool bAtFront)
+{
+    wxString strPath,strOldPath;
+    
+    if (wxGetEnv(wxT("PATH"), & strOldPath))
+    {
+        // Place the user tools folders at the head or tail of the new path
+        if(bAtFront)
+        {
+            strPath.Printf(wxT("%s;%s"), (const wxChar*) strFolder.ShortName(), (const wxChar*) strOldPath);
+        } else
+        {
+            strPath.Printf(wxT("%s;%s"), (const wxChar*) strOldPath, (const wxChar*) strFolder.ShortName());
+        }
+    } else
+    {
+        // unlikely, but ...
+        strPath = strFolder;
+    }
+    return (TRUE == wxSetEnv(wxT("PATH"),strPath));
+}
+
+#if 0          
+wxString ecUtils::GetLastErrorMessageString()
+{
+       wxString str;
+       PTCHAR pszMsg;
+       FormatMessage( 
+               FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+               NULL,
+               GetLastError(),
+               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+               (LPTSTR)&pszMsg,
+               0,
+               NULL 
+       );
+
+       // Display the string.
+       str=pszMsg;
+  str.TrimRight();
+       // Free the buffer.
+       LocalFree(pszMsg);
+       return str;
+
+}
+
+bool ecUtils::Launch(const ecFileName &strFileName, const ecFileName &strViewer)
+{
+       bool rc=false;
+
+       if(!strViewer.IsEmpty())//use custom editor
+       {
+               wxString strCmdline(strViewer);
+               
+               PTCHAR pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
+               GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
+               strCmdline.ReleaseBuffer();
+
+               strCmdline+=_TCHAR(' ');
+               strCmdline+=strFileName;
+               PROCESS_INFORMATION pi;
+               STARTUPINFO si;
+
+               si.cb = sizeof(STARTUPINFO); 
+               si.lpReserved = NULL; 
+               si.lpReserved2 = NULL; 
+               si.cbReserved2 = 0; 
+               si.lpDesktop = NULL; 
+               si.dwFlags = 0; 
+               si.lpTitle=NULL;
+
+               if(CreateProcess(
+                       NULL, // app name
+                       //strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
+                       strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
+                       NULL, // process security
+                       NULL, // thread security
+                       TRUE, // inherit handles
+                       0,
+                       NULL, // environment
+                       NULL, // current dir
+                       &si, // startup info
+                       &pi)){
+            CloseHandle(pi.hProcess);
+            CloseHandle(pi.hThread);
+                       rc=true;
+               } else {
+                       MessageBoxF(wxT("Failed to invoke %s.\n"),strCmdline);
+               }
+               strCmdline.ReleaseBuffer();
+       } else {// Use association
+               TCHAR szExe[MAX_PATH];
+               HINSTANCE h=FindExecutable(strFileName,wxT("."),szExe);
+               if(int(h)<=32){
+                       wxString str;
+                       switch(int(h)){
+                               case 0:  str=wxT("The system is out of memory or resources.");break;
+                               case 31: str=wxT("There is no association for the specified file type.");break;
+                               case ERROR_FILE_NOT_FOUND: str=wxT("The specified file was not found.");break;
+                               case ERROR_PATH_NOT_FOUND: str=wxT("The specified path was not found.");break;
+                               case ERROR_BAD_FORMAT:     str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
+                               default: break;
+                       }
+                       MessageBoxF(wxT("Failed to open document %s.\r\n%s"),strFileName,str);
+               } else {
+
+                       SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), wxT("open"),
+                                       strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
+
+                       sei.hInstApp=0;
+                       HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),wxT("open"), strFileName, NULL, wxT("."), 0)/*ShellExecuteEx(&sei)*/;
+                       if(int(hInst)<=32/*sei.hInstApp==0*/)
+                       {
+                               wxString str;
+                               switch(int(hInst))
+                               {
+                                       case 0 : str=wxT("The operating system is out of memory or resources. ");break;
+                                       case ERROR_FILE_NOT_FOUND : str=wxT("The specified file was not found. ");break;
+                                       case ERROR_PATH_NOT_FOUND : str=wxT("The specified path was not found. ");break;
+                                       case ERROR_BAD_FORMAT : str=wxT("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
+                                       case SE_ERR_ACCESSDENIED : str=wxT("The operating system denied access to the specified file. ");break;
+                                       case SE_ERR_ASSOCINCOMPLETE : str=wxT("The filename association is incomplete or invalid. ");break;
+                                       case SE_ERR_DDEBUSY : str=wxT("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
+                                       case SE_ERR_DDEFAIL : str=wxT("The DDE transaction failed. ");break;
+                                       case SE_ERR_DDETIMEOUT : str=wxT("The DDE transaction could not be completed because the request timed out. ");break;
+                                       case SE_ERR_DLLNOTFOUND : str=wxT("The specified dynamic-link library was not found. ");break;
+                                       //case SE_ERR_FNF : str=wxT("The specified file was not found. ");break;
+                                       case SE_ERR_NOASSOC : str=wxT("There is no application associated with the given filename extension. ");break;
+                                       case SE_ERR_OOM : str=wxT("There was not enough memory to complete the operation. ");break;
+                                       //case SE_ERR_PNF : str=wxT("The specified path was not found. ");break;
+                                       case SE_ERR_SHARE : str=wxT("A sharing violation occurred. ");break;
+                                       default: str=wxT("An unexpected error occurred");break;
+                               }
+                               MessageBoxF(wxT("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
+                       } else {
+                               rc=true;
+                       }
+               }
+       }
+       return rc;
+}
+
+#endif
+
+void ecUtils::UnicodeToCStr(const wxChar* str,char *&psz)
+{
+    int nLength=1 + wxStrlen(str);
+    psz=new char[nLength];
+#ifdef _UNICODE
+    WideCharToMultiByte(CP_ACP, 0, str, -1, psz, nLength, NULL, NULL);
+#else
+    strcpy(psz,str);
+#endif
+}
+
+std::string ecUtils::UnicodeToStdStr(const wxChar* str)
+{
+    std::string stdstr;
+    char *psz;
+    UnicodeToCStr(str,psz);
+    stdstr=std::string(psz);
+    delete psz;
+    return stdstr;
+}
+
+// ecUtils::StripExtraWhitespace() returns a modified version of
+// a string in which each sequence of whitespace characters is
+// replaced by a single space
+
+static bool ecIsSpace(wxChar ch)
+{
+       return (ch == wxT(' ') || ch == wxT('\r') || ch == wxT('\n') || ch == wxT('\t'));
+}
+
+wxString ecUtils::StripExtraWhitespace (const wxString & strInput)
+{
+    wxString strOutput;
+    wxChar* o=strOutput.GetWriteBuf(1+strInput.Len());
+    for(const wxChar* c=strInput.GetData();*c;c++){
+        if(ecIsSpace(*c)){
+            *o++=wxT(' ');
+            if (ecIsSpace(c[1])){
+                for(c=c+2; ecIsSpace(*c);c++);
+                c--;
+            }
+        } else {
+            *o++=*c;
+        }
+    }
+    *o=0;
+    strOutput.UngetWriteBuf();
+    strOutput.Trim(TRUE);
+    strOutput.Trim(FALSE);
+    return strOutput;
+#if 0    
+    wxString strOutput;
+    LPTSTR o=strOutput.GetBuffer(1+strInput.GetLength());
+    for(LPCTSTR c=strInput;*c;c++){
+        if(_istspace(*c)){
+            *o++=_TCHAR(' ');
+            if (_istspace(c[1])){
+                for(c=c+2;_istspace(*c);c++);
+                c--;
+            }
+        } else {
+            *o++=*c;
+        }
+    }
+    *o=0;
+    strOutput.ReleaseBuffer();
+    strOutput.TrimLeft();
+    strOutput.TrimRight();
+    return strOutput;
+#endif
+}
+
+#if 0
+ecFileName ecUtils::WPath(const std::string &str)
+{
+  // Convert a path as read from cdl into host format
+  // Change / to \ throughout
+  ecFileName
+    strPath(str.c_str());
+  strPath.Replace (_TCHAR('/'), _TCHAR('\\'));
+  return strPath;
+}
+
+// Copy file helper function.
+// This makes sure the destination file is only touched as necessary.
+// It is written using Posix calls lest it should be more broadly applicable.
+
+bool ecUtils::CopyFile(LPCTSTR pszSource,LPCTSTR pszDest)
+{
+  // Compare the files.  First set rc to the result of the comparison (true if the same)
+  bool rc=false;
+
+  struct _stat s1,s2;
+  if(-1!=_tstat(pszSource,&s1) && -1!=_tstat(pszDest,&s2) && s1.st_size==s2.st_size){
+    // Files both exist and are of equal size
+    FILE *f1=_tfopen(pszSource,wxT("rb"));
+    if(f1){
+      FILE *f2=_tfopen(pszDest,wxT("rb"));
+      if(f2){
+        int nSize1,nSize2;
+        rc=true;
+        do{
+          char buf1[4096],buf2[4096];
+          nSize1=fread(buf1,1,sizeof buf1,f1);
+          nSize2=fread(buf2,1,sizeof buf2,f2);
+          if(nSize1!=nSize2 || 0!=memcmp(buf1,buf2,nSize1)){
+            rc=false;
+            break;
+          }
+        } while (nSize1>0);
+        fclose(f2);
+      }
+      fclose(f1);
+    }
+  }
+
+  if(rc){
+    // Files are identical
+  } else {
+    rc=TRUE==::CopyFile(pszSource,pszDest,FALSE);
+    if(rc){
+    } else {
+      MessageBoxF(wxT("Failed to copy '%s' to '%s' - %s"),pszSource,pszDest,GetLastErrorMessageString());
+    }
+  }
+
+  return rc;
+}
+
+#endif
+
+/*
+ * wxStringToStringMap
+ *
+ * Stores string values keyed by strings
+ */
+
+void wxStringToStringMap::Set(const wxString& key, const wxString& value)
+{
+    wxString oldValue;
+    if (Find(key, oldValue))
+        Remove(key);
+    m_hashTable.Put(key, (wxObject*) new wxString(value));
+}
+
+bool wxStringToStringMap::Remove(const wxString& key)
+{
+    wxString* str = (wxString*) m_hashTable.Delete(key);
+    if (str)
+    {
+        delete str;
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+bool wxStringToStringMap::Find(const wxString& key, wxString& value)
+{
+    wxString* str = (wxString*) m_hashTable.Get(key);
+    if (str)
+    {
+        value = * str;
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+void wxStringToStringMap::Clear()
+{
+    m_hashTable.BeginFind();
+    wxNode* node;
+    while ((node = m_hashTable.Next()))
+    {
+        wxString* str = (wxString*) node->Data();
+        delete str;
+    }
+}
+
+void wxStringToStringMap::BeginFind()
+{
+    m_hashTable.BeginFind();
+}
+
+bool wxStringToStringMap::Next(wxString& key, wxString& value)
+{
+    wxNode* node = m_hashTable.Next();
+    if (node)
+    {
+        value = * (wxString*) node->Data();
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+// Is str a member of arr?
+bool wxArrayStringIsMember(const wxArrayString& arr, const wxString& str)
+{
+    size_t i;
+    for (i = (size_t) 0; i < arr.GetCount(); i++)
+        if (arr[i] == str)
+            return TRUE;
+
+    return FALSE;
+}
+
+// Eliminate .. and .
+wxString wxGetRealPath(const wxString& path)
+{
+    wxChar* p = new wxChar[path.Len() + 1];
+    wxStrcpy(p, (const wxChar*) path);
+    wxRealPath(p);
+
+    wxString str(p);
+    delete[] p;
+    return str;
+}
+
+// A version of the above but prepending 'cwd' (current path) first
+// if 'path' is relative
+wxString wxGetRealPath(const wxString& cwd, const wxString& path)
+{
+    wxString path1(path);
+
+    if (!wxIsAbsolutePath(path))
+    {
+        path1 = cwd;
+        if (path1.Last() != wxFILE_SEP_PATH)
+            path1 += wxFILE_SEP_PATH;
+        path1 += path;
+    }
+
+    return wxGetRealPath(path1);
+}
+
+// Find the absolute path where this application has been run from.
+// argv0 is wxTheApp->argv[0]
+// cwd is the current working directory (at startup)
+// appVariableName is the name of a variable containing the directory for this app, e.g.
+// MYAPPDIR. This is checked first.
+
+wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName)
+{
+    wxString str;
+
+    // Try appVariableName
+    if (!appVariableName.IsEmpty())
+    {
+        str = wxGetenv(appVariableName);
+        if (!str.IsEmpty())
+            return str;
+    }
+
+    if (wxIsAbsolutePath(argv0))
+        return wxPathOnly(argv0);
+    else
+    {
+        // Is it a relative path?
+        wxString currentDir(cwd);
+        if (currentDir.Last() != wxFILE_SEP_PATH)
+            currentDir += wxFILE_SEP_PATH;
+
+        str = currentDir + argv0;
+        if (wxFileExists(str))
+            return wxPathOnly(str);
+    }
+
+    // OK, it's neither an absolute path nor a relative path.
+    // Search PATH.
+
+    wxPathList pathList;
+    pathList.AddEnvList(wxT("PATH"));
+    str = pathList.FindAbsoluteValidPath(argv0);
+    if (!str.IsEmpty())
+        return wxPathOnly(str);
+
+    // Failed
+    return wxEmptyString;
+}
+
+// Make a path name with no separators, out of a full pathname,
+// e.g. opt_ecos_ecos-1.4.5 out of /opt/ecos/ecos-1.4.5
+wxString ecMakeNameFromPath(const wxString& path)
+{
+    wxString p(path);
+    p.Replace(wxT("/"), wxT("_"));
+    p.Replace(wxT("\\"), wxT("_"));
+    p.Replace(wxT(":"), wxT("_"));
+    return p;
+}
+
+
+// Find the text of the list control item at the given column
+wxString wxListCtrlGetItemTextColumn(wxListCtrl& listCtrl, long item, int col)
+{
+    wxListItem listItem;
+    listItem.m_mask = wxLIST_MASK_TEXT;
+    listItem.m_itemId = item;
+    listItem.m_col = col;
+
+    if (listCtrl.GetItem(listItem))
+        return listItem.m_text;
+    else
+        return wxEmptyString;
+}
+
+// Select the given item
+void wxListCtrlSelectItem(wxListCtrl& listCtrl, long sel, bool deselectOthers)
+{
+    long n = listCtrl.GetItemCount();
+    long i;
+    if (deselectOthers)
+    {
+        for (i = 0; i < n; i++)
+        {
+            if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
+            {
+                listCtrl.SetItemState(i, wxLIST_STATE_SELECTED, 0);
+            }
+        }
+    }
+    listCtrl.SetItemState(sel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
+}
+
+// Find the selection
+long wxListCtrlGetSelection(wxListCtrl& listCtrl)
+{
+    long n = listCtrl.GetItemCount();
+    long i;
+    for (i = 0; i < n; i++)
+    {
+        if (listCtrl.GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+// Find which column the cursor is on
+int wxListCtrlFindColumn(wxListCtrl& listCtrl, int noCols, int x)
+{
+    int col = 0;
+    
+    // Find which column we're on
+    int width = 0;
+    int i;
+    for (i = 0; i < noCols; i++)
+    {
+        width += listCtrl.GetColumnWidth(i);
+        if (x <= width)
+        {
+            col = i;
+            break;
+        }
+    }
+    return col;
+}
+
+// Utility function
+void wxRefreshControls(wxWindow* win)
+{
+    wxNode *node = win->GetChildren().First();
+    while (node)
+    {
+        wxWindow* win = (wxWindow*) node->Data();
+        win->Refresh();
+        node = node->Next();
+    }
+}
+
+wxOutputStream& operator <<(wxOutputStream& stream, const wxString& s)
+{
+    stream.Write(s, s.Length());
+    return stream;
+}
+
+wxOutputStream& operator <<(wxOutputStream& stream, long l)
+{
+    wxString str;
+    str.Printf("%ld", l);
+    return stream << str;
+}
+
+wxOutputStream& operator <<(wxOutputStream& stream, const char c)
+{
+    wxString str;
+    str.Printf("%c", c);
+    return stream << str;
+}
+
+/*
+ * ecDialog
+ * Supports features we want to have for all dialogs in the application.
+ * So far, this just allows dialogs to be resizeable under MSW by
+ * refreshing the controls in OnSize (otherwise there's a mess)
+ */
+
+IMPLEMENT_CLASS(ecDialog, wxDialog)
+
+BEGIN_EVENT_TABLE(ecDialog, wxDialog)
+#ifdef __WXMSW__
+    EVT_SIZE(ecDialog::OnSize)
+#endif
+END_EVENT_TABLE()
+
+void ecDialog::OnSize(wxSizeEvent& event)
+{
+    wxDialog::OnSize(event);
+
+    wxRefreshControls(this);
+}
+
+/*
+ * Implements saving/loading of window settings - fonts only for now
+ */
+
+wxWindowSettingsObject* wxWindowSettings::FindSettings(const wxString& windowName) const
+{
+    wxNode* node = m_settings.First();
+    while (node)
+    {
+        wxWindowSettingsObject* obj = (wxWindowSettingsObject*) node->Data();
+        if (obj->m_windowName.CmpNoCase(windowName) == 0)
+            return obj;
+        node = node->Next();
+    }
+    return NULL;
+}
+
+bool wxWindowSettings::LoadConfig(wxConfigBase& config)
+{
+    unsigned int i = 0;
+    for (i = 0; i < GetCount(); i++)
+    {
+        wxWindowSettingsObject* obj = GetNth(i);
+
+        wxString name(obj->m_windowName);
+        name.Replace(wxT(" "), wxT(""));
+
+        LoadFont(config, name, obj->m_font);
+    }
+
+    return TRUE;
+}
+
+bool wxWindowSettings::SaveConfig(wxConfigBase& config)
+{
+    unsigned int i = 0;
+    for (i = 0; i < GetCount(); i++)
+    {
+        wxWindowSettingsObject* obj = GetNth(i);
+
+        wxString name(obj->m_windowName);
+        name.Replace(wxT(" "), wxT(""));
+
+        SaveFont(config, name, obj->m_font);
+    }
+
+    return TRUE;
+}
+
+// Load and save font descriptions
+bool wxWindowSettings::LoadFont(wxConfigBase& config, const wxString& windowName, wxFont& font)
+{
+    wxString pathBase(wxT("/Fonts/"));
+    pathBase += windowName;
+    pathBase += wxT("/");
+
+    int pointSize, family, style, weight;
+    bool underlined = FALSE;
+    wxString faceName;
+
+    if (!config.Read(pathBase + wxT("PointSize"), & pointSize))
+        return FALSE;
+
+    if (!config.Read(pathBase + wxT("Family"), & family))
+        return FALSE;
+
+    if (!config.Read(pathBase + wxT("Style"), & style))
+        return FALSE;
+
+    if (!config.Read(pathBase + wxT("Weight"), & weight))
+        return FALSE;
+
+    config.Read(pathBase + wxT("Underlined"), (bool*) & underlined);
+    config.Read(pathBase + wxT("FaceName"), & faceName);
+
+    wxFont font1(pointSize, family, style, weight, underlined, faceName);
+    font = font1;
+
+    return TRUE;    
+}
+
+bool wxWindowSettings::SaveFont(wxConfigBase& config, const wxString& windowName, const wxFont& font)
+{
+    if (!font.Ok())
+        return FALSE;
+
+    wxString pathBase(wxT("/Fonts/"));
+    pathBase += windowName;
+    pathBase += wxT("/");
+
+    config.Write(pathBase + wxT("PointSize"), (long) font.GetPointSize());
+    config.Write(pathBase + wxT("Family"), (long) font.GetFamily());
+    config.Write(pathBase + wxT("Style"), (long) font.GetStyle());
+    config.Write(pathBase + wxT("Weight"), (long) font.GetWeight());
+    config.Write(pathBase + wxT("Underlined"), (long) font.GetUnderlined());
+    config.Write(pathBase + wxT("FaceName"), font.GetFaceName());
+
+    return TRUE;    
+}
+
+wxFont wxWindowSettings::GetFont(const wxString& name) const
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+        return wxFont();
+    else
+        return obj->m_font;
+}
+
+void wxWindowSettings::SetFont(const wxString& name, const wxFont& font)
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+    {
+        obj = new wxWindowSettingsObject(name, NULL) ;
+        obj->m_font = font;
+        m_settings.Append(obj);
+    }
+    obj->m_font = font;
+}
+
+wxWindow* wxWindowSettings::GetWindow(const wxString& name) const
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+        return NULL;
+    if (obj->m_arrWindow.GetCount() > 0)
+        return (wxWindow*) obj->m_arrWindow[0];
+    else
+        return NULL;
+}
+
+void wxWindowSettings::SetWindow(const wxString& name, wxWindow* win)
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+    {
+        obj = new wxWindowSettingsObject(name, win) ;
+        m_settings.Append(obj);
+    }
+    obj->m_arrWindow.Clear();
+
+    if (win)
+        obj->m_arrWindow.Add(win);
+}
+
+wxArrayPtrVoid* wxWindowSettings::GetWindows(const wxString& name) const
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+        return NULL;
+    return & obj->m_arrWindow ;
+}
+
+void wxWindowSettings::SetWindows(const wxString& name, wxArrayPtrVoid& arr)
+{
+    wxWindowSettingsObject* obj = FindSettings(name);
+    if (!obj)
+    {
+        obj = new wxWindowSettingsObject(name, NULL) ;
+        m_settings.Append(obj);
+    }
+    obj->m_arrWindow.Clear() ;
+    obj->m_arrWindow = arr;
+}
+
+bool wxWindowSettings::ApplyFontsToWindows()
+{
+    if (m_useDefaults)
+        return FALSE;
+
+    unsigned int i = 0;
+    for (i = 0; i < GetCount(); i++)
+    {
+        wxWindowSettingsObject* obj = GetNth(i);
+
+        unsigned int j = 0;
+        for (j = 0; j < obj->m_arrWindow.GetCount(); j++)
+        {
+            wxWindow* win = (wxWindow*) obj->m_arrWindow[j];
+            win->SetFont(obj->m_font);
+            win->Refresh();
+        }
+    }
+    return TRUE;
+}
+
+#ifdef __WIN32__
+// This will be obsolete when we switch to using the version included
+// in wxWindows (from wxWin 2.3.1 onwards)
+enum ecKillError
+{
+    ecKILL_OK,              // no error
+    ecKILL_BAD_SIGNAL,      // no such signal
+    ecKILL_ACCESS_DENIED,   // permission denied
+    ecKILL_NO_PROCESS,      // no such process
+    ecKILL_ERROR            // another, unspecified error
+};
+#endif
+
+// ----------------------------------------------------------------------------
+// process management
+// ----------------------------------------------------------------------------
+
+#ifdef __WIN32__
+
+// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
+struct wxNewFindByPidParams
+{
+    wxNewFindByPidParams() { hwnd = 0; pid = 0; }
+
+    // the HWND used to return the result
+    HWND hwnd;
+
+    // the PID we're looking from
+    DWORD pid;
+};
+
+// wxKill helper: EnumWindows() callback which is used to find the first (top
+// level) window belonging to the given process
+static BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
+{
+    DWORD pid;
+    (void)::GetWindowThreadProcessId(hwnd, &pid);
+
+    wxNewFindByPidParams *params = (wxNewFindByPidParams *)lParam;
+    if ( pid == params->pid )
+    {
+        // remember the window we found
+        params->hwnd = hwnd;
+
+        // return FALSE to stop the enumeration
+        return FALSE;
+    }
+
+    // continue enumeration
+    return TRUE;
+}
+
+// This will be obsolete when we switch to using the version included
+// in wxWindows (from wxWin 2.3.1 onwards)
+int wxNewKill(long pid, wxSignal sig, ecKillError *krc = NULL)
+{
+#ifdef __WIN32__
+    // get the process handle to operate on
+    HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
+                                    PROCESS_TERMINATE |
+                                    PROCESS_QUERY_INFORMATION,
+                                    FALSE, // not inheritable
+                                    (DWORD)pid);
+    if ( hProcess == NULL )
+    {
+        if ( krc )
+        {
+            if ( ::GetLastError() == ERROR_ACCESS_DENIED )
+            {
+                *krc = ecKILL_ACCESS_DENIED;
+            }
+            else
+            {
+                *krc = ecKILL_NO_PROCESS;
+            }
+        }
+
+        return -1;
+    }
+
+    bool ok = TRUE;
+    switch ( sig )
+    {
+        case wxSIGKILL:
+            // kill the process forcefully returning -1 as error code
+            if ( !::TerminateProcess(hProcess, (UINT)-1) )
+            {
+                wxLogSysError(_("Failed to kill process %d"), pid);
+
+                if ( krc )
+                {
+                    // this is not supposed to happen if we could open the
+                    // process
+                    *krc = ecKILL_ERROR;
+                }
+
+                ok = FALSE;
+            }
+            break;
+
+        case wxSIGNONE:
+            // do nothing, we just want to test for process existence
+            break;
+
+        default:
+            // any other signal means "terminate"
+            {
+                wxNewFindByPidParams params;
+                params.pid = (DWORD)pid;
+
+                // EnumWindows() has nice semantics: it returns 0 if it found
+                // something or if an error occured and non zero if it
+                // enumerated all the window
+                if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
+                {
+                    // did we find any window?
+                    if ( params.hwnd )
+                    {
+                        // tell the app to close
+                        //
+                        // NB: this is the harshest way, the app won't have
+                        //     opportunity to save any files, for example, but
+                        //     this is probably what we want here. If not we
+                        //     can also use SendMesageTimeout(WM_CLOSE)
+                        if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
+                        {
+                            wxLogLastError(_T("PostMessage(WM_QUIT)"));
+                        }
+                    }
+                    else // it was an error then
+                    {
+                        wxLogLastError(_T("EnumWindows"));
+
+                        ok = FALSE;
+                    }
+                }
+                else // no windows for this PID
+                {
+                    if ( krc )
+                    {
+                        *krc = ecKILL_ERROR;
+                    }
+
+                    ok = FALSE;
+                }
+            }
+    }
+
+    // the return code
+    DWORD rc;
+
+    if ( ok )
+    {
+        // as we wait for a short time, we can use just WaitForSingleObject()
+        // and not MsgWaitForMultipleObjects()
+        switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
+        {
+            case WAIT_OBJECT_0:
+                // process terminated
+                if ( !::GetExitCodeProcess(hProcess, &rc) )
+                {
+                    wxLogLastError(_T("GetExitCodeProcess"));
+                }
+                break;
+
+            default:
+                wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
+                // fall through
+
+            case WAIT_FAILED:
+                wxLogLastError(_T("WaitForSingleObject"));
+                // fall through
+
+            case WAIT_TIMEOUT:
+                if ( krc )
+                {
+                    *krc = ecKILL_ERROR;
+                }
+
+                rc = STILL_ACTIVE;
+                break;
+        }
+    }
+    else // !ok
+    {
+        // just to suppress the warnings about uninitialized variable
+        rc = 0;
+    }
+
+    ::CloseHandle(hProcess);
+
+    // the return code is the same as from Unix kill(): 0 if killed
+    // successfully or -1 on error
+    if ( sig == wxSIGNONE )
+    {
+        if ( ok && rc == STILL_ACTIVE )
+        {
+            // there is such process => success
+            return 0;
+        }
+    }
+    else // not SIGNONE
+    {
+        if ( ok && rc != STILL_ACTIVE )
+        {
+            // killed => success
+            return 0;
+        }
+    }
+#else // Win15
+    wxFAIL_MSG( _T("not implemented") );
+#endif // Win32/Win16
+
+    // error
+    return -1;
+}
+#endif
+
+int ecKill(long pid, wxSignal sig)
+{
+#if defined(__UNIX__) && !defined(__CYGWIN__)
+    return wxKill(pid, sig);
+#elif defined(__WXMSW__)
+    return wxNewKill(pid, sig);
+#else
+    return -1;
+#endif
+}
+
+#ifdef _WIN32
+  #include <tlhelp32.h>
+
+  WXHINSTANCE wxProcessKiller::hInstLib1 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("PSAPI.DLL")) : (WXHINSTANCE) LoadLibrary(_T("Kernel32.DLL")) ;
+  WXHINSTANCE wxProcessKiller::hInstLib2 = VER_PLATFORM_WIN32_NT==wxProcessKiller::GetPlatform()? (WXHINSTANCE) LoadLibrary(_T("NTDLL.DLL")): (WXHINSTANCE) NULL;
+
+#endif
+
+const unsigned int wxProcessKiller::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;
+
+wxProcessKiller::wxProcessKiller(int pid):
+  m_bVerbose(false),
+  m_nExitCode(-1),
+  m_idProcess(pid)
+{
+#ifdef _WIN32
+      m_hProcess = (WXHANDLE) ::OpenProcess(SYNCHRONIZE |
+          PROCESS_TERMINATE |
+          PROCESS_QUERY_INFORMATION,
+          FALSE, // not inheritable
+          (DWORD) m_idProcess);
+#endif
+}
+
+wxProcessKiller::~wxProcessKiller()
+{
+#ifdef _WIN32
+    if (m_hProcess)
+    {
+        ::CloseHandle((HANDLE) m_hProcess);
+    }
+#endif
+}
+
+bool wxProcessKiller::Kill(bool bRecurse)
+{
+    wxPInfoArray arPinfo;
+    bool rc=false;
+    if(m_idProcess && -1!=m_idProcess){
+        // Start of with the easy one:
+        if(bRecurse) {
+            // Need to gather this information before we orphan our grandchildren:
+            PSExtract(arPinfo);
+        }
+        
+#ifdef _WIN32
+        
+        if(m_hProcess){
+            rc=(TRUE==::TerminateProcess((HANDLE) m_hProcess,PROCESS_KILL_EXIT_CODE));
+            // dtor's (or subsequent Run's) responsibility to close the handle
+        }
+        
+#else
+        rc=(0==kill(m_idProcess,SIGTERM));
+        int status;
+        waitpid(m_idProcess,&status,WNOHANG);
+#endif
+        
+        if(bRecurse) {
+            // kill process *and* its children
+            // FIXME: needs to be top-down
+            for(int i=0;i<(signed)arPinfo.size();i++){
+                if(arPinfo[i].IsChildOf(m_idProcess)){
+                    
+#ifdef _WIN32
+                    // begin hack
+                    // WHY NECESSARY??
+                    const wxString strName(Name(arPinfo[i].PID));
+                    if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){
+                        continue;
+                    }
+                    // end hack
+                    HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID);
+                    if(hProcess){
+                        rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE));
+                        CloseHandle(hProcess);
+                    } else {
+                        rc=false;
+                    }
+#else
+                    rc&=(0==kill(arPinfo[i].PID,SIGTERM));
+                    int status;
+                    waitpid(arPinfo[i].PID,&status,WNOHANG);
+#endif
+                }
+            }
+        }
+    }
+    return rc;
+}
+
+#ifdef _WIN32
+bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    bool rc=false;
+    arPinfo.clear();
+    // If Windows NT:
+    switch(GetPlatform()) {
+    case VER_PLATFORM_WIN32_NT:
+        if(hInstLib1) {
+            
+            // Get procedure addresses.
+            static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( (HINSTANCE) hInstLib1, "EnumProcesses" ) ;
+            if( lpfEnumProcesses) {
+                
+                if(hInstLib2) {
+                    
+                    static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
+                        (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib2,"NtQueryInformationProcess" ) ;
+                    
+                    if(lpfNtQueryInformationProcess){
+                        DWORD dwMaxPids=256;
+                        DWORD dwPidSize;
+                        DWORD *arPids = NULL ;
+                        do {
+                            delete [] arPids;
+                            arPids=new DWORD[dwMaxPids];
+                        } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
+                        
+                        if(dwPidSize/sizeof(DWORD)<dwMaxPids){
+                            rc=true;
+                            for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
+                                // Regardless of OpenProcess success or failure, we
+                                // still call the enum func with the ProcID.
+                                DWORD pid=arPids[dwIndex];
+                                HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ); 
+                                if (hProcess ) {
+                                    struct {
+                                        DWORD ExitStatus; // receives process termination status
+                                        DWORD PebBaseAddress; // receives process environment block address
+                                        DWORD AffinityMask; // receives process affinity mask
+                                        DWORD BasePriority; // receives process priority class
+                                        ULONG UniqueProcessId; // receives process identifier
+                                        ULONG InheritedFromUniqueProcessId; // receives parent process identifier
+                                    } pbi;
+                                    memset( &pbi, 0, sizeof(pbi)); 
+                                    DWORD retLen; 
+                                    __int64 ftCreation,ftExit,ftKernel,ftUser;
+                                    if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
+                                        TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
+                                        // The second test is important.  It excludes orphaned processes who appear to have been adopted by virtue of a new
+                                        // process having been created with the same ID as their original parent.
+                                        wxPInfo p;
+                                        p.PID=pid;
+                                        p.PPID=pbi.InheritedFromUniqueProcessId;
+                                        p.tCreation=ftCreation;
+                                        p.tCpu=Time((ftKernel+ftUser)/10000);
+                                        arPinfo.push_back(p);
+                                    }
+                                    
+                                    CloseHandle(hProcess); 
+                                    
+                                }
+                            }
+                        }
+                        delete [] arPids;
+                    }          
+                }
+            }      
+        }
+        break;
+    case VER_PLATFORM_WIN32_WINDOWS:
+        
+        if( hInstLib1) {
+            
+            static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
+                (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( (HINSTANCE) hInstLib1,"CreateToolhelp32Snapshot" ) ;
+            static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
+                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32First" ) ;
+            static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
+                (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( (HINSTANCE) hInstLib1, "Process32Next" ) ;
+            if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
+                
+                // Get a handle to a Toolhelp snapshot of the systems
+                // processes.
+                HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
+                if(INVALID_HANDLE_VALUE != hSnapShot) {
+                    // Get the first process' information.
+                    PROCESSENTRY32 procentry;
+                    procentry.dwSize = sizeof(PROCESSENTRY32) ;
+                    if(lpfProcess32First( hSnapShot, &procentry )){
+                        rc=true;
+                        do {
+                            wxPInfo p;
+                            p.PID=procentry.th32ProcessID;
+                            p.PPID=procentry.th32ParentProcessID;
+                            arPinfo.push_back(p);
+                        } while(lpfProcess32Next( hSnapShot, &procentry ));
+                    }
+                    CloseHandle(hSnapShot);
+                }
+            }
+        }
+        break;
+    default:
+        break;
+    }    
+    
+    SetParents(arPinfo);
+    
+    if(!rc){
+        wxLogError(_T("Couldn't get process information!\n"));
+    }
+    return rc;
+}
+
+#else // UNIX
+
+bool wxProcessKiller::PSExtract(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    arPinfo.clear();
+    int i;
+    FILE *f=popen("ps -l",_T("r") MODE_TEXT);
+    if(f){
+        char buf[100];
+        while(fgets(buf,sizeof(buf)-1,f)){
+            TCHAR discard[100];
+            wxPInfo p;
+            // Output is in the form
+            //  F S   UID   PID  PPID  C PRI  NI ADDR    SZ WCHAN  TTY          TIME CMD
+            //100 S   490   877   876  0  70   0    -   368 wait4  pts/0    00:00:00 bash
+            int F,UID,C,PRI,NI,SZ,HH,MM,SS; 
+            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));
+            if(rc){
+                p.tCpu=1000*(SS+60*(60*HH+MM));
+                arPinfo.push_back(p);
+            }
+        }
+        pclose(f);
+        for(i=0;i<(signed)arPinfo.size();i++){
+            int pid=arPinfo[i].PPID;
+            arPinfo[i].pParent=0;
+            for(int j=0;j<(signed)arPinfo.size();j++){
+                if(i!=j && arPinfo[j].PID==pid){
+                    arPinfo[i].pParent=&arPinfo[j];
+                    break;
+                }
+            }
+        }
+    } else {
+        wxLogError(_T("Failed to run ps -l\n"));
+    }
+    return true; //FIXME
+}
+
+#endif
+
+void wxProcessKiller::SetParents(wxProcessKiller::wxPInfoArray &arPinfo)
+{
+    int i;
+    for(i=0;i<(signed)arPinfo.size();i++){
+        wxPInfo &p=arPinfo[i];
+        p.pParent=0;
+        for(int j=0;j<(signed)arPinfo.size();j++){
+            if(arPinfo[j].PID==p.PPID 
+#ifdef _WIN32
+                && arPinfo[j].tCreation<p.tCreation
+#endif
+                )
+            {
+                arPinfo[i].pParent=&arPinfo[j];
+                break;
+            }
+        }
+    }
+    
+    // Check for circularity
+    bool bCircularity=false;
+    for(i=0;i<(signed)arPinfo.size();i++){
+        wxPInfo *p=&arPinfo[i];
+        for(int j=0;j<(signed)arPinfo.size() && p;j++){
+            p=p->pParent;
+        }
+        // If all is well, p should be NULL here.  Otherwise we have a loop.
+        if(p){
+            // Make sure it can't foul things up:
+            arPinfo[i].pParent=0;
+            bCircularity=true;
+        }
+    }
+    
+    if(bCircularity){
+        wxLogError(_T("!!! Circularly linked process list at index %d\n"),i);
+        for(int k=0;k<(signed)arPinfo.size();k++){
+            const wxPInfo &p=arPinfo[k];
+            wxLogError(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
+        }
+    }
+}
+
+bool wxProcessKiller::wxPInfo::IsChildOf(int pid) const
+{
+    for(wxPInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
+        if(p->PID==pid){
+            return true;
+        }
+    }
+    return false;
+}
+
+const wxString wxProcessKiller::Name(int pid)
+{
+    wxString str;
+    str.Printf(_T("id=%d"),pid);
+#ifdef _DEBUG
+#ifdef _WIN32
+    if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){
+        static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) =
+            (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( (HINSTANCE) hInstLib1,"EnumProcessModules" ) ;
+        static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )=
+            (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( (HINSTANCE) hInstLib1,"GetModuleFileNameExA" ) ;
+        if( lpfEnumProcessModules &&  lpfGetModuleFileNameEx ) {
+            HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid);
+            if(hProcess) {
+                HMODULE hMod;
+                DWORD dwSize;
+                if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){
+                    // Get Full pathname:
+                    TCHAR buf[1+MAX_PATH];
+                    lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH);
+                    str+=_TCHAR(' ');
+                    str+=buf;
+                }
+                CloseHandle(hProcess);
+            }
+        }
+    }
+#endif
+#endif
+    return str;
+}
+
+#ifdef _WIN32
+long wxProcessKiller::GetPlatform()
+{
+    OSVERSIONINFO  osver;
+    osver.dwOSVersionInfoSize = sizeof( osver ) ;
+    return GetVersionEx( &osver ) ? (long) osver.dwPlatformId : (long)-1;
+}
+#endif
+
+const wxString wxProcessKiller::ErrorString() const
+{
+#ifdef _WIN32
+    TCHAR *pszMsg;
+    FormatMessage(  
+        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL,
+        m_nErr,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+        (LPTSTR)&pszMsg,
+        0,
+        NULL 
+        );
+    return pszMsg;
+#else 
+    return strerror(errno);
+#endif
+}
+