]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/Utils/win32/CTUtils.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / win32 / CTUtils.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 // Requires:    
37 // Provides:    
38 // See also:    
39 // Known bugs:  
40 // Usage:       
41 //
42 //####DESCRIPTIONEND####
43 //
44 //===========================================================================
45 #include "stdafx.h"
46 #include "CTUtils.h"
47
48 #include <float.h> // for DBL_DIG macro
49 #include <sys/types.h>
50 #include <sys/stat.h>
51
52 #define INCLUDEFILE <string>
53 #include "IncludeSTL.h"
54
55 // Chop str into pieces, using cSep as separator.
56 // " and \ have usual semantics
57 // Return value is array of pieces found.
58
59 int CUtils::Chop(LPCTSTR psz,CStringArray &ar,TCHAR cSep,bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
60 {
61   if(_TCHAR(' ')==cSep){
62     return Chop(psz,ar,_T("\t\n\v\f\r "),bObserveStrings,bBackslashQuotes);
63   } else {
64     ASSERT(_TCHAR('\0')!=cSep);
65     TCHAR c[2]={cSep,_TCHAR('\0')};
66     return Chop(psz,ar,c,bObserveStrings,bBackslashQuotes);
67   }
68 }
69
70 int CUtils::Chop(LPCTSTR psz,CStringArray &ar,LPCTSTR pszSep,bool bObserveStrings/*=false*/,bool bBackslashQuotes/*=false*/)
71 {
72         ar.RemoveAll();
73         int i=0;
74         for(;;){
75                 // Skip multiple separators
76     while(*psz&&_tcschr(pszSep,*psz)){
77       psz++;
78     }
79                 if(!*psz){
80                         return i;
81                 }
82                 CString strTok;
83                 if(bObserveStrings){
84                         BOOL bInString=FALSE;
85                         do{
86                                 if(*psz==_TCHAR('\\') && bBackslashQuotes && psz[1]){
87                                         strTok+=psz[1];
88                                         psz++;
89                                 } else if(*psz==_TCHAR('"')){
90                                         bInString ^= 1;
91                                 } else if (!bInString && *psz && NULL!=_tcschr(pszSep,*psz)) {
92                                         break;
93                                 } else {
94                                         strTok+=*psz;
95                                 }
96                         } while (*++psz);
97                 } else {
98       LPCTSTR pszStart=psz;
99                         do {
100         psz++;
101                         } while (*psz && !_tcschr(pszSep,*psz));
102       strTok=CString(pszStart,psz-pszStart);
103                 }
104                 ar.SetAtGrow(i++,strTok);
105         }
106     return ar.GetSize();
107 }
108
109
110 // vararg-style message box formatter
111 int CUtils::MessageBoxF (LPCTSTR pszFormat, ...)
112 {
113   int rc;
114   va_list args;
115   va_start(args, pszFormat);
116   rc=CUtils::vMessageBox(MB_OK, pszFormat,args);
117   va_end(args);
118   return rc;
119 }
120
121 // As above, but with type as first parameter.
122 int CUtils::MessageBoxFT (UINT nType, LPCTSTR pszFormat, ...)
123 {
124   int rc;
125   va_list args;
126   va_start(args, pszFormat);
127   rc=CUtils::vMessageBox(nType, pszFormat,args);
128   va_end(args);
129   return rc;
130 }
131
132 int CUtils::vMessageBox(UINT nType, LPCTSTR  pszFormat, va_list marker)
133 {
134   int rc=0;
135   for(int nLength=100;nLength;) {
136     TCHAR *buf=new TCHAR[1+nLength];
137     int n=_vsntprintf(buf, nLength, pszFormat, marker ); 
138     if(-1==n){
139       nLength*=2;  // NT behavior
140     } else if (n<nLength){
141       rc=AfxMessageBox(buf,nType);
142       nLength=0;   // trigger exit from loop
143     } else {
144       nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
145     }
146     delete [] buf;
147   }
148   return rc;
149 }
150
151
152 BOOL CUtils::StrToItemIntegerType(const CString & str,__int64 &d)
153 {
154         extern int errno;
155         PTCHAR pEnd;
156         BOOL rc;
157         errno=0;
158         BOOL bHex=(str.GetLength()>2 && str[0]==_TCHAR('0') && (str[1]==_TCHAR('x')||str[1]==_TCHAR('X')));
159         d=_tcstol(str,&pEnd,bHex?16:10);
160         rc=(0==errno && (*pEnd==_TCHAR('\0')));
161         return rc;
162 }
163
164 const CString CUtils::IntToStr(__int64 d,bool bHex)
165 {
166   CString s;
167   s.Format(bHex?_T("0x%08x"):_T("%d"),d);
168   return s;
169 }
170
171 const CString CUtils::DoubleToStr (double dValue)
172 {
173   CString s;
174   s.Format (_T("%.*e"), DBL_DIG, dValue);
175   return s;
176 }
177
178 BOOL CUtils::StrToDouble (const CString & strValue, double &dValue)
179 {
180         extern int errno;
181         PTCHAR pEnd;
182         errno = 0;
183         dValue = _tcstod (strValue, &pEnd);
184         return (0 == errno) && (*pEnd == _TCHAR('\0'));
185 }
186
187 const CString CUtils::Explanation(CFileException & exc)
188 {
189         CString strMsg;
190         switch(exc.m_cause){
191                 case CFileException::none: strMsg=_T("No error occurred.");break;
192                 case CFileException::generic: strMsg=_T("   An unspecified error occurred.");break;
193                 case CFileException::fileNotFound: strMsg=_T("   The file could not be located.");break;
194                 case CFileException::badPath: strMsg=_T("   All or part of the path is invalid.");break;
195                 case CFileException::tooManyOpenFiles: strMsg=_T("   The permitted number of open files was exceeded.");break;
196                 case CFileException::accessDenied: strMsg=_T("   The file could not be accessed.");break;
197                 case CFileException::invalidFile: strMsg=_T("   There was an attempt to use an invalid file handle.");break;
198                 case CFileException::removeCurrentDir: strMsg=_T("   The current working directory cannot be removed.");break;
199                 case CFileException::directoryFull: strMsg=_T("   There are no more directory entries.");break;
200                 case CFileException::badSeek: strMsg=_T("   There was an error trying to set the file pointer.");break;
201                 case CFileException::hardIO: strMsg=_T("   There was a hardware error.");break;
202                 case CFileException::sharingViolation: strMsg=_T("   SHARE.EXE was not loaded, or a shared region was locked.");break;
203                 case CFileException::lockViolation: strMsg=_T("   There was an attempt to lock a region that was already locked.");break;
204                 case CFileException::diskFull: strMsg=_T("   The disk is full.");break;
205                 case CFileException::endOfFile: strMsg=_T("   The end of file was reached. ");break;
206                 default:
207                         strMsg=_T(" Unknown cause");
208                         break;
209         }
210         return strMsg;
211 }
212
213
214 const CString CUtils::LoadString(UINT id)
215 {
216         CString str;
217         str.LoadString(id);
218         return str;
219 }
220
221 bool CUtils::AddToPath(const CFileName & strFolder, bool bAtFront)
222 {
223         CString strPath,strOldPath;
224         int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0);
225         if(nSize>0){
226     GetEnvironmentVariable(_T("PATH"),strOldPath.GetBuffer(1+nSize),nSize);
227     strOldPath.ReleaseBuffer();
228                 // Place the user tools folders at the head or tail of the new path
229                 if(bAtFront){
230                         strPath.Format(_T("%s;%s"),strFolder.ShortName(),strOldPath);
231                 } else {
232                         strPath.Format(_T("%s;%s"),strOldPath,strFolder.ShortName());
233                 }
234         } else {
235                 // unlikely, but ...
236                 strPath=strFolder;
237         }
238   return TRUE==::SetEnvironmentVariable(_T("PATH"),strPath);
239 }
240
241                 
242
243 CString CUtils::GetLastErrorMessageString()
244 {
245         CString str;
246         PTCHAR pszMsg;
247         FormatMessage( 
248                 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
249                 NULL,
250                 GetLastError(),
251                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
252                 (LPTSTR)&pszMsg,
253                 0,
254                 NULL 
255         );
256
257         // Display the string.
258         str=pszMsg;
259   str.TrimRight();
260         // Free the buffer.
261         LocalFree(pszMsg);
262         return str;
263
264 }
265
266 bool CUtils::Launch(const CFileName &strFileName, const CFileName &strViewer)
267 {
268         bool rc=false;
269
270         if(!strViewer.IsEmpty())//use custom editor
271         {
272                 CString strCmdline(strViewer);
273                 
274                 PTCHAR pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
275                 GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
276                 strCmdline.ReleaseBuffer();
277
278                 strCmdline+=_TCHAR(' ');
279                 strCmdline+=strFileName;
280                 PROCESS_INFORMATION pi;
281                 STARTUPINFO si;
282
283                 si.cb = sizeof(STARTUPINFO); 
284                 si.lpReserved = NULL; 
285                 si.lpReserved2 = NULL; 
286                 si.cbReserved2 = 0; 
287                 si.lpDesktop = NULL; 
288                 si.dwFlags = 0; 
289                 si.lpTitle=NULL;
290
291                 if(CreateProcess(
292                         NULL, // app name
293                         //strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
294                         strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
295                         NULL, // process security
296                         NULL, // thread security
297                         TRUE, // inherit handles
298                         0,
299                         NULL, // environment
300                         NULL, // current dir
301                         &si, // startup info
302                         &pi)){
303             CloseHandle(pi.hProcess);
304             CloseHandle(pi.hThread);
305                         rc=true;
306                 } else {
307                         MessageBoxF(_T("Failed to invoke %s.\n"),strCmdline);
308                 }
309                 strCmdline.ReleaseBuffer();
310         } else {// Use association
311                 TCHAR szExe[MAX_PATH];
312                 HINSTANCE h=FindExecutable(strFileName,_T("."),szExe);
313                 if(int(h)<=32){
314                         CString str;
315                         switch(int(h)){
316                                 case 0:  str=_T("The system is out of memory or resources.");break;
317                                 case 31: str=_T("There is no association for the specified file type.");break;
318                                 case ERROR_FILE_NOT_FOUND: str=_T("The specified file was not found.");break;
319                                 case ERROR_PATH_NOT_FOUND: str=_T("The specified path was not found.");break;
320                                 case ERROR_BAD_FORMAT:     str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
321                                 default: break;
322                         }
323                         MessageBoxF(_T("Failed to open document %s.\r\n%s"),strFileName,str);
324                 } else {
325
326                         SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), _T("open"),
327                                         strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
328
329                         sei.hInstApp=0;
330                         HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),_T("open"), strFileName, NULL, _T("."), 0)/*ShellExecuteEx(&sei)*/;
331                         if(int(hInst)<=32/*sei.hInstApp==0*/)
332                         {
333                                 CString str;
334                                 switch(int(hInst))
335                                 {
336                                         case 0 : str=_T("The operating system is out of memory or resources. ");break;
337                                         case ERROR_FILE_NOT_FOUND : str=_T("The specified file was not found. ");break;
338                                         case ERROR_PATH_NOT_FOUND : str=_T("The specified path was not found. ");break;
339                                         case ERROR_BAD_FORMAT : str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
340                                         case SE_ERR_ACCESSDENIED : str=_T("The operating system denied access to the specified file. ");break;
341                                         case SE_ERR_ASSOCINCOMPLETE : str=_T("The filename association is incomplete or invalid. ");break;
342                                         case SE_ERR_DDEBUSY : str=_T("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
343                                         case SE_ERR_DDEFAIL : str=_T("The DDE transaction failed. ");break;
344                                         case SE_ERR_DDETIMEOUT : str=_T("The DDE transaction could not be completed because the request timed out. ");break;
345                                         case SE_ERR_DLLNOTFOUND : str=_T("The specified dynamic-link library was not found. ");break;
346                                         //case SE_ERR_FNF : str=_T("The specified file was not found. ");break;
347                                         case SE_ERR_NOASSOC : str=_T("There is no application associated with the given filename extension. ");break;
348                                         case SE_ERR_OOM : str=_T("There was not enough memory to complete the operation. ");break;
349                                         //case SE_ERR_PNF : str=_T("The specified path was not found. ");break;
350                                         case SE_ERR_SHARE : str=_T("A sharing violation occurred. ");break;
351                                         default: str=_T("An unexpected error occurred");break;
352                                 }
353                                 MessageBoxF(_T("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
354                         } else {
355                                 rc=true;
356                         }
357                 }
358         }
359         return rc;
360 }
361
362 void CUtils::UnicodeToCStr(LPCTSTR str,char *&psz)
363 {
364     int nLength=1+_tcslen(str);
365     psz=new char[nLength];
366     #ifdef _UNICODE
367     WideCharToMultiByte(CP_ACP, 0, str, -1, psz, nLength, NULL, NULL);
368     #else
369     strcpy(psz,str);
370     #endif
371 }
372
373 std::string CUtils::UnicodeToStdStr(LPCTSTR str)
374 {
375     std::string stdstr;
376     char *psz;
377     UnicodeToCStr(str,psz);
378     stdstr=std::string(psz);
379     delete psz;
380     return stdstr;
381 }
382
383 // CUtils::StripExtraWhitespace() returns a modified version of
384 // a string in which each sequence of whitespace characters is
385 // replaced by a single space
386
387 CString CUtils::StripExtraWhitespace (const CString & strInput)
388 {
389   CString strOutput;
390   LPTSTR o=strOutput.GetBuffer(1+strInput.GetLength());
391   for(LPCTSTR c=strInput;*c;c++){
392     if(_istspace(*c)){
393       *o++=_TCHAR(' ');
394       if (_istspace(c[1])){
395         for(c=c+2;_istspace(*c);c++);
396         c--;
397       }
398     } else {
399       *o++=*c;
400     }
401   }
402   *o=0;
403   strOutput.ReleaseBuffer();
404   strOutput.TrimLeft();
405   strOutput.TrimRight();
406   return strOutput;
407 }
408
409 CFileName CUtils::WPath(const std::string &str)
410 {
411   // Convert a path as read from cdl into host format
412   // Change / to \ throughout
413   CFileName
414     strPath(str.c_str());
415   strPath.Replace (_TCHAR('/'), _TCHAR('\\'));
416   return strPath;
417 }
418
419 // Copy file helper function.
420 // This makes sure the destination file is only touched as necessary.
421 // It is written using Posix calls lest it should be more broadly applicable.
422
423 bool CUtils::CopyFile(LPCTSTR pszSource,LPCTSTR pszDest)
424 {
425   // Compare the files.  First set rc to the result of the comparison (true if the same)
426   bool rc=false;
427
428   struct _stat s1,s2;
429   if(-1!=_tstat(pszSource,&s1) && -1!=_tstat(pszDest,&s2) && s1.st_size==s2.st_size){
430     // Files both exist and are of equal size
431     FILE *f1=_tfopen(pszSource,_T("rb"));
432     if(f1){
433       FILE *f2=_tfopen(pszDest,_T("rb"));
434       if(f2){
435         int nSize1,nSize2;
436         rc=true;
437         do{
438           char buf1[4096],buf2[4096];
439           nSize1=fread(buf1,1,sizeof buf1,f1);
440           nSize2=fread(buf2,1,sizeof buf2,f2);
441           if(nSize1!=nSize2 || 0!=memcmp(buf1,buf2,nSize1)){
442             rc=false;
443             break;
444           }
445         } while (nSize1>0);
446         fclose(f2);
447       }
448       fclose(f1);
449     }
450   }
451
452   if(rc){
453     // Files are identical
454     TRACE(_T("Copy not necessary: '%s' to '%s'\n"),pszSource,pszDest);
455   } else {
456     rc=TRUE==::CopyFile(pszSource,pszDest,FALSE);
457     if(rc){
458       TRACE(_T("Copied '%s' to '%s'\n"),pszSource,pszDest);
459     } else {
460       MessageBoxF(_T("Failed to copy '%s' to '%s' - %s"),pszSource,pszDest,GetLastErrorMessageString());
461     }
462   }
463
464   return rc;
465 }