comparison host/tools/Utils/win32/FileName.cpp @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 74dbf4c3f2e1
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
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 #include "stdafx.h"
26 #include "FileName.h"
27 #include <shlwapi.h>
28
29 const TCHAR CFileName::cSep=_TCHAR('\\');
30
31 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2):
32 CString(psz1)
33 {
34 Normalize();
35 operator+=(psz2);
36 }
37
38 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3):
39 CString(psz1)
40 {
41 Normalize();
42 operator+=(psz2);
43 operator+=(psz3);
44 }
45
46 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4):
47 CString(psz1)
48 {
49 Normalize();
50 operator+=(psz2);
51 operator+=(psz3);
52 operator+=(psz4);
53 }
54
55 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4,LPCTSTR psz5):
56 CString(psz1)
57 {
58 operator+=(psz2);
59 operator+=(psz3);
60 operator+=(psz4);
61 operator+=(psz5);
62 }
63
64 CFileName AFXAPI operator+(const CFileName& string1, const CFileName& string2)
65 {
66 CFileName s;
67 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
68 string2.GetData()->nDataLength, string2.m_pchData);
69 return s;
70 }
71
72 CFileName AFXAPI operator+(const CFileName& string, LPCTSTR lpsz)
73 {
74 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
75 CFileName s;
76 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
77 CFileName::SafeStrlen(lpsz), lpsz);
78 return s;
79 }
80
81 CFileName AFXAPI operator+(LPCTSTR lpsz, const CFileName& string)
82 {
83 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
84 CFileName s;
85 s.ConcatCopy(CFileName::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
86 string.m_pchData);
87 return s;
88 }
89
90 CFileName AFXAPI operator+(const CFileName& string1, TCHAR ch)
91 {
92 CFileName s;
93 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
94 return s;
95 }
96
97 CFileName AFXAPI operator+(TCHAR ch, const CFileName& string)
98 {
99 CFileName s;
100 s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
101 return s;
102 }
103
104 const CFileName& CFileName::operator+=(LPCTSTR lpsz)
105 {
106 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
107 ConcatInPlace(SafeStrlen(lpsz), lpsz);
108 return *this;
109 }
110
111 const CFileName& CFileName::operator+=(TCHAR ch)
112 {
113 ConcatInPlace(1, &ch);
114 return *this;
115 }
116
117 const CFileName& CFileName::operator+=(const CFileName& string)
118 {
119 ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
120 return *this;
121 }
122
123 void CFileName::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
124 {
125 if(nSrcLen>0){
126 if(GetLength()>0){
127 // Appending a single separator to a non-null string is a no-op
128 if(1==nSrcLen && cSep==*lpszSrcData){
129 return;
130 }
131 // Count the intervening separators
132 int n=(cSep==m_pchData[GetLength()-1])+(cSep==*lpszSrcData);
133 switch(n){
134 case 0:
135 CString::ConcatInPlace(1, &cSep);
136 break;
137 case 1:
138 break;
139 case 2:
140 lpszSrcData++;
141 nSrcLen--;
142 break;
143 }
144 }
145 CString::ConcatInPlace(nSrcLen, lpszSrcData);
146 }
147 }
148
149 void CFileName::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
150 int nSrc2Len, LPCTSTR lpszSrc2Data)
151 {
152 int n=1;
153 int nNewLen = nSrc1Len + nSrc2Len;
154 if(nSrc1Len>0){
155 if(1==nSrc2Len && cSep==*lpszSrc2Data){
156 // Appending a single separator to a non-null string is a no-op
157 lpszSrc2Data++;
158 nSrc2Len--;
159 nNewLen--;
160 } else {
161 // Count the intervening separators
162 n=(cSep==lpszSrc1Data[nSrc1Len-1])+(cSep==*lpszSrc2Data);
163
164 switch(n){
165 case 0:
166 nNewLen++;
167 break;
168 case 1:
169 break;
170 case 2:
171 lpszSrc2Data++;
172 nSrc2Len--;
173 nNewLen--;
174 break;
175 }
176 }
177 }
178 if (nNewLen != 0)
179 {
180 AllocBuffer(nNewLen);
181 memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
182 LPTSTR p=m_pchData+nSrc1Len;
183 if(0==n){
184 *p++=cSep;
185 }
186 memcpy(p, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
187 }
188 }
189
190 void CFileName::Normalize()
191 {
192 // Remove any trailing slash
193 int &n=GetData()->nDataLength;
194 if(n>1 && (cSep==m_pchData[n-1])){
195 n--;
196 m_pchData[n] = _TCHAR('\0');
197 }
198 }
199
200
201 const CFileName CFileName::FullName() const
202 {
203 PTCHAR pFile;
204 DWORD dwSize=::GetFullPathName (*this, 0, NULL, &pFile);
205 if(dwSize>0){
206 CString strCopy;
207 ::GetFullPathName (*this, 1+dwSize, strCopy.GetBuffer(1+dwSize), &pFile);
208 strCopy.ReleaseBuffer();
209 return strCopy;
210 } else {
211 return *this;
212 }
213 }
214
215 const CFileName CFileName::ShortName() const
216 {
217 DWORD dwSize=::GetShortPathName (*this, NULL, 0);
218 if(dwSize>0){
219 CString strCopy;
220 ::GetShortPathName (*this, strCopy.GetBuffer(1+dwSize), 1+dwSize);
221 strCopy.ReleaseBuffer();
222 return strCopy;
223 } else {
224 return *this;
225 }
226 }
227
228 const CFileName CFileName::NoSpaceName() const// sans spaces
229 {
230 CStringArray ar1,ar2;
231 const CString str2(ShortName());
232
233 LPCTSTR pc,pcStart;
234
235 pcStart=*this;
236 for(pc=*this;*pc;pc++){
237 if(_TCHAR('\\')==*pc){
238 ar1.Add(CString(pcStart,pc-pcStart));
239 pcStart=pc;
240 }
241 }
242 ar1.Add(CString(pcStart,pc-pcStart));
243
244 pcStart=str2;
245 for(pc=str2;*pc;pc++){
246 if(_TCHAR('\\')==*pc){
247 ar2.Add(CString(pcStart,pc-pcStart));
248 pcStart=pc;
249 }
250 }
251 ar2.Add(CString(pcStart,pc-pcStart));
252
253 ASSERT(ar1.GetSize()==ar2.GetSize());
254
255 CString rc;
256 for(int i=0;i<ar1.GetSize();i++){
257 rc+=(-1==ar1[i].Find(_TCHAR(' ')))?ar1[i]:ar2[i];
258 }
259 return rc;
260 }
261
262 //
263 const CFileName CFileName::Tail() const
264 {
265 TCHAR *ch=_tcsrchr(m_pchData,cSep);
266 return ch?ch+1:m_pchData;
267 }
268
269 const CFileName CFileName::Head() const
270 {
271 TCHAR *ch=_tcsrchr(m_pchData,cSep);
272 return ch?CFileName(m_pchData,ch-m_pchData):m_pchData;
273 }
274
275 // GetFileAttributes is not available in Win95 so we test the water first
276 FILETIME CFileName::LastModificationTime() const
277 {
278 static HINSTANCE hInst=LoadLibrary(_T("kernel32.dll"));
279 ASSERT(hInst);
280
281 #ifdef _UNICODE
282 #define GETFILEATTRIBUTESNAME "GetFileAttributesExW"
283 #else
284 #define GETFILEATTRIBUTESNAME "GetFileAttributesExA"
285 #endif // !UNICODE
286
287 typedef BOOL (WINAPI *GetFileAttributesP)(LPCTSTR,GET_FILEEX_INFO_LEVELS,LPVOID);
288
289 static GetFileAttributesP p=(GetFileAttributesP)GetProcAddress(hInst,GETFILEATTRIBUTESNAME);
290 if(p){
291 WIN32_FILE_ATTRIBUTE_DATA data;
292
293 if((*p)(*this, GetFileExInfoStandard, (LPVOID)&data)){
294 return data.ftLastWriteTime;
295 }
296 } else {
297 HANDLE h=CreateFile(*this,0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
298 FILETIME ft;
299 if(INVALID_HANDLE_VALUE!=h){
300 BOOL b=::GetFileTime(h,NULL,NULL,&ft);
301 ::CloseHandle(h);
302 if(b){
303 return ft;
304 }
305 }
306 }
307 static FILETIME ftNull={0,0};
308 return ftNull;
309 }
310
311 bool CFileName::SetFileAttributes(DWORD dwFileAttributes) const
312 {
313 return ::SetFileAttributes (*this, dwFileAttributes)!=0;
314 }
315
316 bool CFileName::SameFile(const CFileName &o) const
317 {
318 return 0==ShortName().CompareNoCase(o.ShortName());
319 }
320
321 CFileName CFileName::ExpandEnvironmentStrings(LPCTSTR psz)
322 {
323 // First call simply determines the size
324 CFileName f;
325 DWORD dwSize=::ExpandEnvironmentStrings(psz, NULL, 0);
326 if(dwSize>0){
327 ::ExpandEnvironmentStrings(psz, f.GetBuffer(dwSize), dwSize);
328 f.ReleaseBuffer();
329 } else {
330 f=psz;
331 }
332 return f;
333 }
334
335 const CFileName& CFileName::ExpandEnvironmentStrings()
336 {
337 *this=CFileName::ExpandEnvironmentStrings(*this);
338 return *this;
339 }
340
341 // Helper for Relative() psz is in full format.
342 CFileName CFileName::Drive(LPCTSTR psz)
343 {
344 if(_istalpha(psz[0])){
345 return psz[0];
346 } else if(cSep==psz[0]&&cSep==psz[1]){
347 TCHAR *c=_tcschr(psz+2,cSep);
348 if(c){
349 c=_tcschr(c+1,cSep);
350 if(c){
351 return CString(psz,c-psz);
352 }
353 }
354 }
355 return _T("");
356 }
357
358 CFileName CFileName::Relative(LPCTSTR compare,LPCTSTR current)
359 {
360 CString rc;
361 bool b=(TRUE==PathRelativePathTo(rc.GetBuffer(1+MAX_PATH),current,FILE_ATTRIBUTE_DIRECTORY,compare,0));
362 rc.ReleaseBuffer();
363 //TRACE(_T("compare=%s current=%s result=%s (b=%d)\n"),compare,current,b?rc:compare,b);
364 return b?rc:compare;
365 }
366
367 const CFileName& CFileName::MakeRelative(LPCTSTR pszRelativeTo)
368 {
369 *this=CFileName::Relative(*this,pszRelativeTo);
370 return *this;
371 }
372
373
374 CFileName CFileName::GetCurrentDirectory()
375 {
376 CFileName f;
377 ::GetCurrentDirectory(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH));
378 f.ReleaseBuffer();
379 f.Normalize();
380 return f;
381 }
382
383
384 const CFileName& CFileName::Append(LPCTSTR lpsz)
385 {
386 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
387 CString::ConcatInPlace(SafeStrlen(lpsz), lpsz);
388 return *this;
389
390 }
391
392 const CFileName& CFileName::Append(TCHAR ch)
393 {
394 ConcatInPlace(1, &ch);
395 return *this;
396 }
397
398 bool CFileName::IsAbsolute() const
399 {
400 int nLength=GetLength();
401 LPCTSTR psz=*this;
402 return
403 (nLength>0 && (cSep==psz[0]))|| // starts with '\'
404 (nLength>1 && (
405 (_istalpha(psz[0]) && _TCHAR(':')==psz[1]) || // starts with [e.g.] "c:\"
406 (cSep==psz[0] && cSep==psz[1]))); // UNC
407 }
408
409 // Return an array of filename pieces. Plugs '\0's into 'this', which
410 // is therefore subsequently only usable as referenced by the returned array.
411 LPCTSTR *CFileName::Chop()
412 {
413 TCHAR *c;
414 // Count the separators
415 int nSeps=0;
416 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
417 nSeps++;
418 }
419 LPCTSTR *ar=new LPCTSTR[2+nSeps]; // +1 for first, +1 for terminating 0
420 ar[0]=m_pchData;
421 int i=1;
422 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
423 ar[i++]=c+1;
424 *c=_TCHAR('\0');
425 }
426 ar[i]=0;
427 return ar;
428 }
429
430 CFileName CFileName::GetTempPath()
431 {
432 CFileName f;
433 ::GetTempPath(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH));
434 f.ReleaseBuffer();
435 f.Normalize();
436 return f;
437
438 }
439
440 const CFileName CFileName::CygPath () const
441 {
442 TCHAR buf[2+MAX_PATH];
443 LPCTSTR rc=buf+1;
444 if(!GetShortPathName(m_pchData,1+buf,MAX_PATH)){
445 _tcscpy(1+buf,m_pchData);
446 }
447 if(_istalpha(*rc)&&_TCHAR(':')==rc[1]){
448 // Convert c:\ to //c/ [this is the bit that requires the first char of buf]
449 buf[0]=_TCHAR('/');
450 buf[2]=buf[1];
451 buf[1]=_TCHAR('/');
452 rc=buf;
453 }
454 for(TCHAR *c=buf+1;*c;c++){
455 if(_TCHAR('\\')==*c){
456 *c=_TCHAR('/');
457 }
458 }
459
460 return rc;
461 }
462
463 bool CFileName::CreateDirectory(bool bParentsToo,bool bFailIfAlreadyExists) const
464 {
465 LPCTSTR pszDir=m_pchData;
466 if(bParentsToo){
467 // Create intermediate directories
468 for(LPCTSTR c=_tcschr(pszDir,_TCHAR('\\'));c;c=_tcschr(c+1,_TCHAR('\\'))){
469 if(c==pszDir+2 && _istalpha(pszDir[0]) && _TCHAR(':')==pszDir[1]){
470 continue; // don't attempt to create "C:"
471 }
472 const CFileName strDir(pszDir,c-pszDir);
473 if(!(strDir.IsDir()? (!bFailIfAlreadyExists) : ::CreateDirectory(strDir,NULL))){
474 return false;
475 }
476 }
477 }
478 return IsDir()? (!bFailIfAlreadyExists) : (TRUE==::CreateDirectory(pszDir,NULL));
479 }
480
481
482 const CString CFileName::Extension() const
483 {
484 LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.'));
485 if(ch && !_tcschr(ch,cSep)){
486 return CString(ch+1);
487 } else {
488 return _T("");
489 }
490 }
491
492 const CString CFileName::Root() const
493 {
494 LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.'));
495 if(ch && !_tcschr(ch,cSep)){
496 return CString(m_pchData,ch-m_pchData);
497 } else {
498 return m_pchData;
499 }
500 }
501
502 CFileName CFileName::SetCurrentDirectory(LPCTSTR pszDir)
503 {
504 const CFileName strPwd=GetCurrentDirectory();
505 return ::SetCurrentDirectory(pszDir)?strPwd:_T("");
506 }
507
508 bool CFileName::RecursivelyDelete()
509 {
510 CFileNameArray ar;
511 for(int i=FindFiles(*this,ar)-1;i>=0;--i){
512 ::DeleteFile(ar[i]);
513 }
514 for(i=FindFiles(*this,ar,_T("*.*"),true,0)-1;i>=0;--i){
515 ::RemoveDirectory(ar[i]);
516 }
517 return TRUE==::RemoveDirectory(*this);
518 }
519
520 int CFileName::FindFiles (LPCTSTR pszDir,CFileNameArray &ar,LPCTSTR pszPattern/*=_T("*.*")*/,bool bRecurse/*=true*/,DWORD dwExclude/*=FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN*/)
521 {
522 ar.RemoveAll();
523 CFileFind finder;
524 BOOL bMore=finder.FindFile(CFileName(pszDir)+pszPattern);
525 while (bMore) {
526 bMore = finder.FindNextFile();
527 if(!finder.IsDots() && !finder.MatchesMask(dwExclude)){
528 CFileName strFile(finder.GetFilePath());
529 ar.Add(strFile);
530 }
531 }
532 if(bRecurse){
533 CFileFind finder;
534 BOOL bMore=finder.FindFile(CFileName(pszDir)+_T("*.*"));
535 while (bMore) {
536 bMore = finder.FindNextFile();
537 if(!finder.IsDots() && finder.IsDirectory()){
538 CFileNameArray ar2;
539 FindFiles(finder.GetFilePath(),ar2,pszPattern,bRecurse,dwExclude);
540 ar.Append(ar2);
541 }
542 }
543 }
544 return ar.GetSize();
545 }
546
547 void CFileName::ReplaceExtension(LPCTSTR pszNewExt)
548 {
549 ASSERT(pszNewExt);
550 if(_TCHAR('.')==*pszNewExt){
551 // Be tolerant of whether '.' is included in what we are passed:
552 pszNewExt++;
553 }
554 LPTSTR pch=GetBuffer(2+GetLength()+_tcslen(pszNewExt));
555 LPTSTR pcExt=_tcsrchr(pch,_TCHAR('.'));
556 if(NULL==pcExt || _tcschr(pcExt,cSep)){
557 // No existing extension
558 pcExt=pch+GetLength();
559 *pcExt++=_TCHAR('.');
560 }
561 _tcscpy(pcExt+1,pszNewExt);
562 ReleaseBuffer();
563 }