1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
6 // This program is part of the eCos host tools.
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)
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
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.
22 // ----------------------------------------------------------------------------
24 //####COPYRIGHTEND####
29 const TCHAR CFileName::cSep=_TCHAR('\\');
31 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2):
38 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3):
46 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4):
55 CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4,LPCTSTR psz5):
64 CFileName AFXAPI operator+(const CFileName& string1, const CFileName& string2)
67 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
68 string2.GetData()->nDataLength, string2.m_pchData);
72 CFileName AFXAPI operator+(const CFileName& string, LPCTSTR lpsz)
74 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
76 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
77 CFileName::SafeStrlen(lpsz), lpsz);
81 CFileName AFXAPI operator+(LPCTSTR lpsz, const CFileName& string)
83 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
85 s.ConcatCopy(CFileName::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
90 CFileName AFXAPI operator+(const CFileName& string1, TCHAR ch)
93 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
97 CFileName AFXAPI operator+(TCHAR ch, const CFileName& string)
100 s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
104 const CFileName& CFileName::operator+=(LPCTSTR lpsz)
106 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
107 ConcatInPlace(SafeStrlen(lpsz), lpsz);
111 const CFileName& CFileName::operator+=(TCHAR ch)
113 ConcatInPlace(1, &ch);
117 const CFileName& CFileName::operator+=(const CFileName& string)
119 ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
123 void CFileName::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
127 // Appending a single separator to a non-null string is a no-op
128 if(1==nSrcLen && cSep==*lpszSrcData){
131 // Count the intervening separators
132 int n=(cSep==m_pchData[GetLength()-1])+(cSep==*lpszSrcData);
135 CString::ConcatInPlace(1, &cSep);
145 CString::ConcatInPlace(nSrcLen, lpszSrcData);
149 void CFileName::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
150 int nSrc2Len, LPCTSTR lpszSrc2Data)
153 int nNewLen = nSrc1Len + nSrc2Len;
155 if(1==nSrc2Len && cSep==*lpszSrc2Data){
156 // Appending a single separator to a non-null string is a no-op
161 // Count the intervening separators
162 n=(cSep==lpszSrc1Data[nSrc1Len-1])+(cSep==*lpszSrc2Data);
180 AllocBuffer(nNewLen);
181 memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
182 LPTSTR p=m_pchData+nSrc1Len;
186 memcpy(p, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
190 void CFileName::Normalize()
192 // Remove any trailing slash
193 int &n=GetData()->nDataLength;
194 if(n>1 && (cSep==m_pchData[n-1])){
196 m_pchData[n] = _TCHAR('\0');
201 const CFileName CFileName::FullName() const
204 DWORD dwSize=::GetFullPathName (*this, 0, NULL, &pFile);
207 ::GetFullPathName (*this, 1+dwSize, strCopy.GetBuffer(1+dwSize), &pFile);
208 strCopy.ReleaseBuffer();
215 const CFileName CFileName::ShortName() const
217 DWORD dwSize=::GetShortPathName (*this, NULL, 0);
220 ::GetShortPathName (*this, strCopy.GetBuffer(1+dwSize), 1+dwSize);
221 strCopy.ReleaseBuffer();
228 const CFileName CFileName::NoSpaceName() const// sans spaces
230 CStringArray ar1,ar2;
231 const CString str2(ShortName());
236 for(pc=*this;*pc;pc++){
237 if(_TCHAR('\\')==*pc){
238 ar1.Add(CString(pcStart,pc-pcStart));
242 ar1.Add(CString(pcStart,pc-pcStart));
245 for(pc=str2;*pc;pc++){
246 if(_TCHAR('\\')==*pc){
247 ar2.Add(CString(pcStart,pc-pcStart));
251 ar2.Add(CString(pcStart,pc-pcStart));
253 ASSERT(ar1.GetSize()==ar2.GetSize());
256 for(int i=0;i<ar1.GetSize();i++){
257 rc+=(-1==ar1[i].Find(_TCHAR(' ')))?ar1[i]:ar2[i];
263 const CFileName CFileName::Tail() const
265 TCHAR *ch=_tcsrchr(m_pchData,cSep);
266 return ch?ch+1:m_pchData;
269 const CFileName CFileName::Head() const
271 TCHAR *ch=_tcsrchr(m_pchData,cSep);
272 return ch?CFileName(m_pchData,ch-m_pchData):m_pchData;
275 // GetFileAttributes is not available in Win95 so we test the water first
276 FILETIME CFileName::LastModificationTime() const
278 static HINSTANCE hInst=LoadLibrary(_T("kernel32.dll"));
282 #define GETFILEATTRIBUTESNAME "GetFileAttributesExW"
284 #define GETFILEATTRIBUTESNAME "GetFileAttributesExA"
287 typedef BOOL (WINAPI *GetFileAttributesP)(LPCTSTR,GET_FILEEX_INFO_LEVELS,LPVOID);
289 static GetFileAttributesP p=(GetFileAttributesP)GetProcAddress(hInst,GETFILEATTRIBUTESNAME);
291 WIN32_FILE_ATTRIBUTE_DATA data;
293 if((*p)(*this, GetFileExInfoStandard, (LPVOID)&data)){
294 return data.ftLastWriteTime;
297 HANDLE h=CreateFile(*this,0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
299 if(INVALID_HANDLE_VALUE!=h){
300 BOOL b=::GetFileTime(h,NULL,NULL,&ft);
307 static FILETIME ftNull={0,0};
311 bool CFileName::SetFileAttributes(DWORD dwFileAttributes) const
313 return ::SetFileAttributes (*this, dwFileAttributes)!=0;
316 bool CFileName::SameFile(const CFileName &o) const
318 return 0==ShortName().CompareNoCase(o.ShortName());
321 CFileName CFileName::ExpandEnvironmentStrings(LPCTSTR psz)
323 // First call simply determines the size
325 DWORD dwSize=::ExpandEnvironmentStrings(psz, NULL, 0);
327 ::ExpandEnvironmentStrings(psz, f.GetBuffer(dwSize), dwSize);
335 const CFileName& CFileName::ExpandEnvironmentStrings()
337 *this=CFileName::ExpandEnvironmentStrings(*this);
341 // Helper for Relative() psz is in full format.
342 CFileName CFileName::Drive(LPCTSTR psz)
344 if(_istalpha(psz[0])){
346 } else if(cSep==psz[0]&&cSep==psz[1]){
347 TCHAR *c=_tcschr(psz+2,cSep);
351 return CString(psz,c-psz);
358 CFileName CFileName::Relative(LPCTSTR compare,LPCTSTR current)
361 bool b=(TRUE==PathRelativePathTo(rc.GetBuffer(1+MAX_PATH),current,FILE_ATTRIBUTE_DIRECTORY,compare,0));
363 //TRACE(_T("compare=%s current=%s result=%s (b=%d)\n"),compare,current,b?rc:compare,b);
367 const CFileName& CFileName::MakeRelative(LPCTSTR pszRelativeTo)
369 *this=CFileName::Relative(*this,pszRelativeTo);
374 CFileName CFileName::GetCurrentDirectory()
377 ::GetCurrentDirectory(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH));
384 const CFileName& CFileName::Append(LPCTSTR lpsz)
386 ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
387 CString::ConcatInPlace(SafeStrlen(lpsz), lpsz);
392 const CFileName& CFileName::Append(TCHAR ch)
394 ConcatInPlace(1, &ch);
398 bool CFileName::IsAbsolute() const
400 int nLength=GetLength();
403 (nLength>0 && (cSep==psz[0]))|| // starts with '\'
405 (_istalpha(psz[0]) && _TCHAR(':')==psz[1]) || // starts with [e.g.] "c:\"
406 (cSep==psz[0] && cSep==psz[1]))); // UNC
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()
414 // Count the separators
416 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
419 LPCTSTR *ar=new LPCTSTR[2+nSeps]; // +1 for first, +1 for terminating 0
422 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
430 CFileName CFileName::GetTempPath()
433 ::GetTempPath(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH));
440 const CFileName CFileName::CygPath () const
442 TCHAR buf[2+MAX_PATH];
444 if(!GetShortPathName(m_pchData,1+buf,MAX_PATH)){
445 _tcscpy(1+buf,m_pchData);
447 if(_istalpha(*rc)&&_TCHAR(':')==rc[1]){
448 // Convert c:\ to //c/ [this is the bit that requires the first char of buf]
454 for(TCHAR *c=buf+1;*c;c++){
455 if(_TCHAR('\\')==*c){
463 bool CFileName::CreateDirectory(bool bParentsToo,bool bFailIfAlreadyExists) const
465 LPCTSTR pszDir=m_pchData;
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:"
472 const CFileName strDir(pszDir,c-pszDir);
473 if(!(strDir.IsDir()? (!bFailIfAlreadyExists) : ::CreateDirectory(strDir,NULL))){
478 return IsDir()? (!bFailIfAlreadyExists) : (TRUE==::CreateDirectory(pszDir,NULL));
482 const CString CFileName::Extension() const
484 LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.'));
485 if(ch && !_tcschr(ch,cSep)){
486 return CString(ch+1);
492 const CString CFileName::Root() const
494 LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.'));
495 if(ch && !_tcschr(ch,cSep)){
496 return CString(m_pchData,ch-m_pchData);
502 CFileName CFileName::SetCurrentDirectory(LPCTSTR pszDir)
504 const CFileName strPwd=GetCurrentDirectory();
505 return ::SetCurrentDirectory(pszDir)?strPwd:_T("");
508 bool CFileName::RecursivelyDelete()
511 for(int i=FindFiles(*this,ar)-1;i>=0;--i){
514 for(i=FindFiles(*this,ar,_T("*.*"),true,0)-1;i>=0;--i){
515 ::RemoveDirectory(ar[i]);
517 return TRUE==::RemoveDirectory(*this);
520 int CFileName::FindFiles (LPCTSTR pszDir,CFileNameArray &ar,LPCTSTR pszPattern/*=_T("*.*")*/,bool bRecurse/*=true*/,DWORD dwExclude/*=FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN*/)
524 BOOL bMore=finder.FindFile(CFileName(pszDir)+pszPattern);
526 bMore = finder.FindNextFile();
527 if(!finder.IsDots() && !finder.MatchesMask(dwExclude)){
528 CFileName strFile(finder.GetFilePath());
534 BOOL bMore=finder.FindFile(CFileName(pszDir)+_T("*.*"));
536 bMore = finder.FindNextFile();
537 if(!finder.IsDots() && finder.IsDirectory()){
539 FindFiles(finder.GetFilePath(),ar2,pszPattern,bRecurse,dwExclude);
547 void CFileName::ReplaceExtension(LPCTSTR pszNewExt)
550 if(_TCHAR('.')==*pszNewExt){
551 // Be tolerant of whether '.' is included in what we are passed:
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('.');
561 _tcscpy(pcExt+1,pszNewExt);