Mercurial > ecos-v2_0-branch
diff 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 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/host/tools/Utils/win32/FileName.cpp @@ -0,0 +1,563 @@ +//####COPYRIGHTBEGIN#### +// +// ---------------------------------------------------------------------------- +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// +// 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#### +#include "stdafx.h" +#include "FileName.h" +#include <shlwapi.h> + +const TCHAR CFileName::cSep=_TCHAR('\\'); + +CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2): +CString(psz1) +{ + Normalize(); + operator+=(psz2); +} + +CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3): +CString(psz1) +{ + Normalize(); + operator+=(psz2); + operator+=(psz3); +} + +CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4): +CString(psz1) +{ + Normalize(); + operator+=(psz2); + operator+=(psz3); + operator+=(psz4); +} + +CFileName::CFileName(LPCTSTR psz1,LPCTSTR psz2,LPCTSTR psz3,LPCTSTR psz4,LPCTSTR psz5): +CString(psz1) +{ + operator+=(psz2); + operator+=(psz3); + operator+=(psz4); + operator+=(psz5); +} + +CFileName AFXAPI operator+(const CFileName& string1, const CFileName& string2) +{ + CFileName s; + s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, + string2.GetData()->nDataLength, string2.m_pchData); + return s; +} + +CFileName AFXAPI operator+(const CFileName& string, LPCTSTR lpsz) +{ + ASSERT(lpsz == NULL || AfxIsValidString(lpsz)); + CFileName s; + s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, + CFileName::SafeStrlen(lpsz), lpsz); + return s; +} + +CFileName AFXAPI operator+(LPCTSTR lpsz, const CFileName& string) +{ + ASSERT(lpsz == NULL || AfxIsValidString(lpsz)); + CFileName s; + s.ConcatCopy(CFileName::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, + string.m_pchData); + return s; +} + +CFileName AFXAPI operator+(const CFileName& string1, TCHAR ch) +{ + CFileName s; + s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch); + return s; +} + +CFileName AFXAPI operator+(TCHAR ch, const CFileName& string) +{ + CFileName s; + s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData); + return s; +} + +const CFileName& CFileName::operator+=(LPCTSTR lpsz) +{ + ASSERT(lpsz == NULL || AfxIsValidString(lpsz)); + ConcatInPlace(SafeStrlen(lpsz), lpsz); + return *this; +} + +const CFileName& CFileName::operator+=(TCHAR ch) +{ + ConcatInPlace(1, &ch); + return *this; +} + +const CFileName& CFileName::operator+=(const CFileName& string) +{ + ConcatInPlace(string.GetData()->nDataLength, string.m_pchData); + return *this; +} + +void CFileName::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData) +{ + if(nSrcLen>0){ + if(GetLength()>0){ + // Appending a single separator to a non-null string is a no-op + if(1==nSrcLen && cSep==*lpszSrcData){ + return; + } + // Count the intervening separators + int n=(cSep==m_pchData[GetLength()-1])+(cSep==*lpszSrcData); + switch(n){ + case 0: + CString::ConcatInPlace(1, &cSep); + break; + case 1: + break; + case 2: + lpszSrcData++; + nSrcLen--; + break; + } + } + CString::ConcatInPlace(nSrcLen, lpszSrcData); + } +} + +void CFileName::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, + int nSrc2Len, LPCTSTR lpszSrc2Data) +{ + int n=1; + int nNewLen = nSrc1Len + nSrc2Len; + if(nSrc1Len>0){ + if(1==nSrc2Len && cSep==*lpszSrc2Data){ + // Appending a single separator to a non-null string is a no-op + lpszSrc2Data++; + nSrc2Len--; + nNewLen--; + } else { + // Count the intervening separators + n=(cSep==lpszSrc1Data[nSrc1Len-1])+(cSep==*lpszSrc2Data); + + switch(n){ + case 0: + nNewLen++; + break; + case 1: + break; + case 2: + lpszSrc2Data++; + nSrc2Len--; + nNewLen--; + break; + } + } + } + if (nNewLen != 0) + { + AllocBuffer(nNewLen); + memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR)); + LPTSTR p=m_pchData+nSrc1Len; + if(0==n){ + *p++=cSep; + } + memcpy(p, lpszSrc2Data, nSrc2Len*sizeof(TCHAR)); + } +} + +void CFileName::Normalize() +{ + // Remove any trailing slash + int &n=GetData()->nDataLength; + if(n>1 && (cSep==m_pchData[n-1])){ + n--; + m_pchData[n] = _TCHAR('\0'); + } +} + + +const CFileName CFileName::FullName() const +{ + PTCHAR pFile; + DWORD dwSize=::GetFullPathName (*this, 0, NULL, &pFile); + if(dwSize>0){ + CString strCopy; + ::GetFullPathName (*this, 1+dwSize, strCopy.GetBuffer(1+dwSize), &pFile); + strCopy.ReleaseBuffer(); + return strCopy; + } else { + return *this; + } +} + +const CFileName CFileName::ShortName() const +{ + DWORD dwSize=::GetShortPathName (*this, NULL, 0); + if(dwSize>0){ + CString strCopy; + ::GetShortPathName (*this, strCopy.GetBuffer(1+dwSize), 1+dwSize); + strCopy.ReleaseBuffer(); + return strCopy; + } else { + return *this; + } +} + +const CFileName CFileName::NoSpaceName() const// sans spaces +{ + CStringArray ar1,ar2; + const CString str2(ShortName()); + + LPCTSTR pc,pcStart; + + pcStart=*this; + for(pc=*this;*pc;pc++){ + if(_TCHAR('\\')==*pc){ + ar1.Add(CString(pcStart,pc-pcStart)); + pcStart=pc; + } + } + ar1.Add(CString(pcStart,pc-pcStart)); + + pcStart=str2; + for(pc=str2;*pc;pc++){ + if(_TCHAR('\\')==*pc){ + ar2.Add(CString(pcStart,pc-pcStart)); + pcStart=pc; + } + } + ar2.Add(CString(pcStart,pc-pcStart)); + + ASSERT(ar1.GetSize()==ar2.GetSize()); + + CString rc; + for(int i=0;i<ar1.GetSize();i++){ + rc+=(-1==ar1[i].Find(_TCHAR(' ')))?ar1[i]:ar2[i]; + } + return rc; +} + +// +const CFileName CFileName::Tail() const +{ + TCHAR *ch=_tcsrchr(m_pchData,cSep); + return ch?ch+1:m_pchData; +} + +const CFileName CFileName::Head() const +{ + TCHAR *ch=_tcsrchr(m_pchData,cSep); + return ch?CFileName(m_pchData,ch-m_pchData):m_pchData; +} + +// GetFileAttributes is not available in Win95 so we test the water first +FILETIME CFileName::LastModificationTime() const +{ + static HINSTANCE hInst=LoadLibrary(_T("kernel32.dll")); + ASSERT(hInst); + +#ifdef _UNICODE +#define GETFILEATTRIBUTESNAME "GetFileAttributesExW" +#else +#define GETFILEATTRIBUTESNAME "GetFileAttributesExA" +#endif // !UNICODE + + typedef BOOL (WINAPI *GetFileAttributesP)(LPCTSTR,GET_FILEEX_INFO_LEVELS,LPVOID); + + static GetFileAttributesP p=(GetFileAttributesP)GetProcAddress(hInst,GETFILEATTRIBUTESNAME); + if(p){ + WIN32_FILE_ATTRIBUTE_DATA data; + + if((*p)(*this, GetFileExInfoStandard, (LPVOID)&data)){ + return data.ftLastWriteTime; + } + } else { + HANDLE h=CreateFile(*this,0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + FILETIME ft; + if(INVALID_HANDLE_VALUE!=h){ + BOOL b=::GetFileTime(h,NULL,NULL,&ft); + ::CloseHandle(h); + if(b){ + return ft; + } + } + } + static FILETIME ftNull={0,0}; + return ftNull; +} + +bool CFileName::SetFileAttributes(DWORD dwFileAttributes) const +{ + return ::SetFileAttributes (*this, dwFileAttributes)!=0; +} + +bool CFileName::SameFile(const CFileName &o) const +{ + return 0==ShortName().CompareNoCase(o.ShortName()); +} + +CFileName CFileName::ExpandEnvironmentStrings(LPCTSTR psz) +{ + // First call simply determines the size + CFileName f; + DWORD dwSize=::ExpandEnvironmentStrings(psz, NULL, 0); + if(dwSize>0){ + ::ExpandEnvironmentStrings(psz, f.GetBuffer(dwSize), dwSize); + f.ReleaseBuffer(); + } else { + f=psz; + } + return f; +} + +const CFileName& CFileName::ExpandEnvironmentStrings() +{ + *this=CFileName::ExpandEnvironmentStrings(*this); + return *this; +} + +// Helper for Relative() psz is in full format. +CFileName CFileName::Drive(LPCTSTR psz) +{ + if(_istalpha(psz[0])){ + return psz[0]; + } else if(cSep==psz[0]&&cSep==psz[1]){ + TCHAR *c=_tcschr(psz+2,cSep); + if(c){ + c=_tcschr(c+1,cSep); + if(c){ + return CString(psz,c-psz); + } + } + } + return _T(""); +} + +CFileName CFileName::Relative(LPCTSTR compare,LPCTSTR current) +{ + CString rc; + bool b=(TRUE==PathRelativePathTo(rc.GetBuffer(1+MAX_PATH),current,FILE_ATTRIBUTE_DIRECTORY,compare,0)); + rc.ReleaseBuffer(); + //TRACE(_T("compare=%s current=%s result=%s (b=%d)\n"),compare,current,b?rc:compare,b); + return b?rc:compare; +} + +const CFileName& CFileName::MakeRelative(LPCTSTR pszRelativeTo) +{ + *this=CFileName::Relative(*this,pszRelativeTo); + return *this; +} + + +CFileName CFileName::GetCurrentDirectory() +{ + CFileName f; + ::GetCurrentDirectory(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH)); + f.ReleaseBuffer(); + f.Normalize(); + return f; +} + + +const CFileName& CFileName::Append(LPCTSTR lpsz) +{ + ASSERT(lpsz == NULL || AfxIsValidString(lpsz)); + CString::ConcatInPlace(SafeStrlen(lpsz), lpsz); + return *this; + +} + +const CFileName& CFileName::Append(TCHAR ch) +{ + ConcatInPlace(1, &ch); + return *this; +} + +bool CFileName::IsAbsolute() const +{ + int nLength=GetLength(); + LPCTSTR psz=*this; + return + (nLength>0 && (cSep==psz[0]))|| // starts with '\' + (nLength>1 && ( + (_istalpha(psz[0]) && _TCHAR(':')==psz[1]) || // starts with [e.g.] "c:\" + (cSep==psz[0] && cSep==psz[1]))); // UNC +} + +// Return an array of filename pieces. Plugs '\0's into 'this', which +// is therefore subsequently only usable as referenced by the returned array. +LPCTSTR *CFileName::Chop() +{ + TCHAR *c; + // Count the separators + int nSeps=0; + for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){ + nSeps++; + } + LPCTSTR *ar=new LPCTSTR[2+nSeps]; // +1 for first, +1 for terminating 0 + ar[0]=m_pchData; + int i=1; + for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){ + ar[i++]=c+1; + *c=_TCHAR('\0'); + } + ar[i]=0; + return ar; +} + +CFileName CFileName::GetTempPath() +{ + CFileName f; + ::GetTempPath(1+_MAX_PATH,f.GetBuffer(1+_MAX_PATH)); + f.ReleaseBuffer(); + f.Normalize(); + return f; + +} + +const CFileName CFileName::CygPath () const +{ + TCHAR buf[2+MAX_PATH]; + LPCTSTR rc=buf+1; + if(!GetShortPathName(m_pchData,1+buf,MAX_PATH)){ + _tcscpy(1+buf,m_pchData); + } + if(_istalpha(*rc)&&_TCHAR(':')==rc[1]){ + // Convert c:\ to //c/ [this is the bit that requires the first char of buf] + buf[0]=_TCHAR('/'); + buf[2]=buf[1]; + buf[1]=_TCHAR('/'); + rc=buf; + } + for(TCHAR *c=buf+1;*c;c++){ + if(_TCHAR('\\')==*c){ + *c=_TCHAR('/'); + } + } + + return rc; +} + +bool CFileName::CreateDirectory(bool bParentsToo,bool bFailIfAlreadyExists) const +{ + LPCTSTR pszDir=m_pchData; + if(bParentsToo){ + // Create intermediate directories + for(LPCTSTR c=_tcschr(pszDir,_TCHAR('\\'));c;c=_tcschr(c+1,_TCHAR('\\'))){ + if(c==pszDir+2 && _istalpha(pszDir[0]) && _TCHAR(':')==pszDir[1]){ + continue; // don't attempt to create "C:" + } + const CFileName strDir(pszDir,c-pszDir); + if(!(strDir.IsDir()? (!bFailIfAlreadyExists) : ::CreateDirectory(strDir,NULL))){ + return false; + } + } + } + return IsDir()? (!bFailIfAlreadyExists) : (TRUE==::CreateDirectory(pszDir,NULL)); +} + + +const CString CFileName::Extension() const +{ + LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.')); + if(ch && !_tcschr(ch,cSep)){ + return CString(ch+1); + } else { + return _T(""); + } +} + +const CString CFileName::Root() const +{ + LPCTSTR ch=_tcsrchr(m_pchData,_TCHAR('.')); + if(ch && !_tcschr(ch,cSep)){ + return CString(m_pchData,ch-m_pchData); + } else { + return m_pchData; + } +} + +CFileName CFileName::SetCurrentDirectory(LPCTSTR pszDir) +{ + const CFileName strPwd=GetCurrentDirectory(); + return ::SetCurrentDirectory(pszDir)?strPwd:_T(""); +} + +bool CFileName::RecursivelyDelete() +{ + CFileNameArray ar; + for(int i=FindFiles(*this,ar)-1;i>=0;--i){ + ::DeleteFile(ar[i]); + } + for(i=FindFiles(*this,ar,_T("*.*"),true,0)-1;i>=0;--i){ + ::RemoveDirectory(ar[i]); + } + return TRUE==::RemoveDirectory(*this); +} + +int CFileName::FindFiles (LPCTSTR pszDir,CFileNameArray &ar,LPCTSTR pszPattern/*=_T("*.*")*/,bool bRecurse/*=true*/,DWORD dwExclude/*=FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN*/) +{ + ar.RemoveAll(); + CFileFind finder; + BOOL bMore=finder.FindFile(CFileName(pszDir)+pszPattern); + while (bMore) { + bMore = finder.FindNextFile(); + if(!finder.IsDots() && !finder.MatchesMask(dwExclude)){ + CFileName strFile(finder.GetFilePath()); + ar.Add(strFile); + } + } + if(bRecurse){ + CFileFind finder; + BOOL bMore=finder.FindFile(CFileName(pszDir)+_T("*.*")); + while (bMore) { + bMore = finder.FindNextFile(); + if(!finder.IsDots() && finder.IsDirectory()){ + CFileNameArray ar2; + FindFiles(finder.GetFilePath(),ar2,pszPattern,bRecurse,dwExclude); + ar.Append(ar2); + } + } + } + return ar.GetSize(); +} + +void CFileName::ReplaceExtension(LPCTSTR pszNewExt) +{ + ASSERT(pszNewExt); + if(_TCHAR('.')==*pszNewExt){ + // Be tolerant of whether '.' is included in what we are passed: + pszNewExt++; + } + LPTSTR pch=GetBuffer(2+GetLength()+_tcslen(pszNewExt)); + LPTSTR pcExt=_tcsrchr(pch,_TCHAR('.')); + if(NULL==pcExt || _tcschr(pcExt,cSep)){ + // No existing extension + pcExt=pch+GetLength(); + *pcExt++=_TCHAR('.'); + } + _tcscpy(pcExt+1,pszNewExt); + ReleaseBuffer(); +}
