1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 // Copyright (C) 2003 John Dallaway
7 // This program is part of the eCos host tools.
9 // This program is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by the Free
11 // Software Foundation; either version 2 of the License, or (at your option)
14 // This program is distributed in the hope that it will be useful, but WITHOUT
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // ----------------------------------------------------------------------------
25 //####COPYRIGHTEND####
28 #pragma implementation "filename.h"
31 // Includes other headers for precompiled compilation
38 #include "wx/filefn.h"
39 #include "wx/confbase.h" // For wxExpandEnvVars
50 #include "wx/msw/winundef.h"
51 #ifdef CreateDirectory
52 #undef CreateDirectory
54 #ifdef ExpandEnvironmentStrings
55 #undef ExpandEnvironmentStrings
57 #ifdef GetCurrentDirectory
58 #undef GetCurrentDirectory
60 #ifdef SetCurrentDirectory
61 #undef SetCurrentDirectory
76 const wxChar ecFileName::cSep=wxFILE_SEP_PATH;
78 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2):
85 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3):
93 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3,const wxChar* psz4):
102 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3,const wxChar* psz4,const wxChar* psz5):
112 ecFileName::~ecFileName()
114 // Unfortunately we can't do this since GetStringData is private in wxString.
115 // So for now, we may memory leaks since ~wxString is not virtual.
116 //GetStringData()->Unlock();
120 ecFileName operator+(const ecFileName& string1, const ecFileName& string2)
123 s.ConcatCopy(string1, string2);
127 ecFileName operator+(const ecFileName& string, const wxChar* lpsz)
133 s.ConcatCopy(string, wxString(lpsz));
137 ecFileName operator+(const wxChar* lpsz, const ecFileName& string)
143 s.ConcatCopy(wxString(lpsz), string);
147 ecFileName operator+(const ecFileName& string1, wxChar ch)
150 s.ConcatCopy(string1, wxString(ch));
154 ecFileName operator+(wxChar ch, const ecFileName& string)
157 s.ConcatCopy(wxString(ch), string);
161 const ecFileName& ecFileName::operator+=(const wxChar* lpsz)
166 ConcatInPlace(wxString(lpsz));
170 const ecFileName& ecFileName::operator+=(wxChar ch)
172 ConcatInPlace(wxString(ch));
176 const ecFileName& ecFileName::operator+=(const ecFileName& string)
178 ConcatInPlace(string);
182 void ecFileName::ConcatInPlace(const wxString& src)
184 ConcatCopy(* this, src);
187 void ecFileName::ConcatCopy(const wxString& src1,
188 const wxString& src2)
190 int nSrc1Len = src1.Len();
191 int nSrc2Len = src2.Len();
193 int nNewLen = nSrc1Len + nSrc2Len;
196 if(1==nSrc2Len && cSep==src2[0])
198 // Appending a single separator to a non-null string is a no-op
201 // Count the intervening separators
202 n=(cSep==src1[nSrc1Len-1])+(cSep==src2[0]);
206 (*this) = src1 + wxString(cSep) + src2;
209 (*this) = src1 + src2;
212 (*this) = src1 + src2.Mid(1);
220 void ecFileName::Normalize()
222 // Remove any trailing seperator
224 if (len > 0 && (*this)[(size_t)(len - 1)] == cSep)
225 (*this) = Mid(0, len - 1);
229 const ecFileName ecFileName::FullName() const
233 long dwSize=::GetFullPathName (*this, 0, NULL, &pFile);
236 ::GetFullPathName (*this, 1+dwSize, strCopy.GetWriteBuf(1+dwSize), &pFile);
237 strCopy.UngetWriteBuf();
243 return wxGetCwd() + wxString(cSep) + wxString(*this);
247 const ecFileName ecFileName::ShortName() const
250 long dwSize=::GetShortPathName (*this, NULL, 0);
253 ::GetShortPathName (*this, strCopy.GetWriteBuf(1+dwSize), 1+dwSize);
254 strCopy.UngetWriteBuf();
264 const ecFileName ecFileName::NoSpaceName() const// sans spaces
269 // Only replace components with spaces with FAT names.
270 wxArrayString ar1,ar2;
271 const wxString str2(ShortName());
275 unsigned int len = Len();
277 for (i = 0; i < len; i++)
279 if(wxTChar('\\')==(*this)[i])
281 ar1.Add(this->Mid(pcStart, i - pcStart + 1));
285 ar1.Add(this->Mid(pcStart, i - pcStart + 1));
289 for (i = 0; i < len; i++)
291 if(wxTChar('\\')==str2[i])
293 ar2.Add(str2.Mid(pcStart, i - pcStart + 1));
297 ar2.Add(str2.Mid(pcStart, i - pcStart + 1));
299 wxASSERT(ar1.Count()==ar2.Count());
302 for(i=0;i<ar1.Count();i++){
303 rc+=(-1==ar1[i].Find(wxTChar(' ')))?ar1[i]:ar2[i];
310 const ecFileName ecFileName::Tail() const
312 return AfterLast(cSep);
315 const ecFileName ecFileName::Head() const
317 return BeforeLast(cSep);
320 time_t ecFileName::LastModificationTime() const
322 return wxFileModificationTime(* this);
325 // GetFileAttributes is not available in Win95 so we test the water first
326 static HINSTANCE hInst=LoadLibrary(_T("kernel32.dll"));
330 #define GETFILEATTRIBUTESNAME "GetFileAttributesExW"
332 #define GETFILEATTRIBUTESNAME "GetFileAttributesExA"
335 typedef BOOL (WINAPI *GetFileAttributesP)(const wxChar*,GET_FILEEX_INFO_LEVELS,LPVOID);
337 static GetFileAttributesP p=(GetFileAttributesP)GetProcAddress(hInst,GETFILEATTRIBUTESNAME);
339 WIN32_FILE_ATTRIBUTE_DATA data;
341 if((*p)(*this, GetFileExInfoStandard, (LPVOID)&data)){
342 return data.ftLastWriteTime;
345 HANDLE h=CreateFile(*this,0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
347 if(INVALID_HANDLE_VALUE!=h){
348 BOOL b=::GetFileTime(h,NULL,NULL,&ft);
355 static FILETIME ftNull={0,0};
361 bool ecFileName::SetFileAttributes(long dwFileAttributes) const
363 return ::SetFileAttributes (*this, dwFileAttributes)!=0;
367 bool ecFileName::Exists () const
369 return IsFile() || IsDir() ;
372 bool ecFileName::IsDir () const
374 return wxPathExists(* this);
377 bool ecFileName::IsFile () const
379 #if defined(__WXMAC__)
381 if (filename && stat (wxUnix2MacFilename(filename), &stbuf) == 0 )
386 if ((*this) != wxT("") && wxStat (wxFNSTRINGCAST fn_str(), &st) == 0 && (st.st_mode & S_IFREG))
393 bool ecFileName::IsReadOnly () const
396 long a=GetFileAttributes(* this); return 0xFFFFFFFF!=a && (0!=(a&FILE_ATTRIBUTE_READONLY ));
398 wxFAIL_MSG("ecFileName::IsReadOnly not supported on this platform.");
403 bool ecFileName::SameFile(const ecFileName &o) const
406 return 0==ShortName().CmpNoCase(o.ShortName());
408 // On most other platforms, case is important.
413 ecFileName ecFileName::ExpandEnvironmentStrings(const wxChar* psz)
415 // wxExpandEnvVars is from confbase.h
417 ecFileName f = wxExpandEnvVars(psz);
421 const ecFileName& ecFileName::ExpandEnvironmentStrings()
423 *this=ecFileName::ExpandEnvironmentStrings(*this);
428 // Helper for Relative() psz is in full format.
429 ecFileName ecFileName::Drive(const wxChar* psz)
431 if(wxIsalpha(psz[0])){
433 } else if(cSep==psz[0]&&cSep==psz[1]){
434 wxChar *c=_tcschr(psz+2,cSep);
438 return wxString(psz,c-psz);
446 ecFileName ecFileName::Relative(const wxChar* compare,const wxChar* current)
450 bool b=(TRUE==PathRelativePathTo(rc.GetWriteBuf(1+MAX_PATH),current,FILE_ATTRIBUTE_DIRECTORY,compare,0));
452 return b?(ecFileName)rc:(ecFileName)compare;
454 wxFAIL_MSG("ecFileName::Relative not implemented on this platform.");
459 const ecFileName& ecFileName::MakeRelative(const wxChar* pszRelativeTo)
461 *this=ecFileName::Relative(*this,pszRelativeTo);
466 ecFileName ecFileName::GetCurrentDirectory()
476 const ecFileName& ecFileName::Append(const wxChar* lpsz)
481 //wxString::ConcatInPlace(lpsz);
482 wxString::Append(lpsz);
487 const ecFileName& ecFileName::Append(wxChar ch)
489 ConcatInPlace(wxString(ch));
493 bool ecFileName::IsAbsolute() const
496 const wxString& psz=*this;
498 (nLength>0 && (cSep==psz[0]))|| // starts with '\'
500 (wxIsalpha(psz[0]) && wxTChar(':')==psz[1]) || // starts with [e.g.] "c:\"
501 (cSep==psz[0] && cSep==psz[1]))); // UNC
506 // Return an array of filename pieces. Plugs '\0's into 'this', which
507 // is therefore subsequently only usable as referenced by the returned array.
508 const wxChar* *ecFileName::Chop()
511 // Count the separators
513 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
516 const wxChar* *ar=new const wxChar*[2+nSeps]; // +1 for first, +1 for terminating 0
519 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
528 ecFileName ecFileName::GetTempPath()
533 ::GetTempPathW(1+MAX_PATH,f.GetWriteBuf(1+MAX_PATH));
535 ::GetTempPathA(1+MAX_PATH,f.GetWriteBuf(1+MAX_PATH));
538 #elif defined(__WXGTK__)
540 wxFAIL("ecFileName::GetTempPath() not implemented on this platform.");
546 const ecFileName ecFileName::CygPath () const
549 ecFileName rc = ShortName();
550 if(wxIsalpha(rc[(size_t)0]) && wxTChar(':')==rc[(size_t)1])
552 // Convert c:\ to /cygdrive/c/
553 wxString s = wxString(wxT("/cygdrive/")) + wxString(rc[(size_t)0]) + rc.Mid(2);
557 for (i = 0; i < rc.Len(); i++)
559 if (rc[i] == wxTChar('\\'))
560 rc[i] = wxTChar('/');
563 const ecFileName& rc = * this;
569 bool ecFileName::CreateDirectory(bool bParentsToo,bool bFailIfAlreadyExists) const
573 // Create intermediate directories
575 // 'rest' will progressively have its separators replaced by underscores in order
576 // to find the next separator
577 wxString rest = * this;
579 int len = rest.Len();
582 // If the path is a network path, ignore the first part of the path
583 if (len > 2 && (rest.GetChar(0) == wxT('\\') || rest.GetChar(0) == wxT('/')) && (rest.GetChar(1) == wxT('\\') || rest.GetChar(1) == wxT('/')))
585 rest.SetChar(0,wxT('_')); rest.SetChar(1,wxT('_'));
586 lastPos = rest.Find(cSep);
587 if (lastPos != -1 && lastPos >= 0)
588 rest.SetChar(lastPos,wxT('_'));
592 while (lastPos != -1)
594 lastPos = rest.Find(cSep);
595 if (lastPos != -1 && lastPos >= 0)
597 rest[lastPos] = wxT('_'); // So we find the NEXT separator
599 // don't attempt to create "C: or /"
600 if (lastPos > 0 && (*this)[lastPos-1] == wxT(':'))
602 else if (lastPos == 0)
606 // Fail if any of the dirs exist already
607 wxString str(this->Mid(0, lastPos));
608 bool alreadyExists = wxDirExists(str);
609 if (alreadyExists && bFailIfAlreadyExists)
619 return IsDir()? (!bFailIfAlreadyExists) : (TRUE==wxMkdir(*this));
623 const wxString ecFileName::Extension() const
625 wxString path, name, ext;
627 wxSplitPath(*this, & path, & name, & ext);
631 const wxString ecFileName::Root() const
633 return wxPathOnly(*this);
636 ecFileName ecFileName::SetCurrentDirectory(const wxChar* pszDir)
638 const ecFileName strPwd=wxGetCwd();
639 if (::wxSetWorkingDirectory(pszDir))
645 bool ecFileName::RecursivelyDelete()
649 for(i=FindFiles(*this,ar)-1;i>=0;--i){
652 for(i=FindFiles(*this,ar,wxT("*.*"),TRUE,0)-1;i>=0;--i){
655 return TRUE==wxRmdir(*this);
658 // TODO: take account of dwExclude
659 int ecFileName::FindFiles (const wxString& pszDir,wxArrayString &ar,const wxString& pszPattern/*=wxT("*.*")*/,bool bRecurse/*=TRUE*/,long dwExclude/*=wxDIR_DIRS|wxDIR_HIDDEN*/)
668 bool bMore = dir.GetFirst(& fileName, pszPattern, wxDIR_FILES);
671 if (fileName != wxT(".") && fileName != wxT(".."))
674 ecFileName path(pszDir);
675 path += (const wxChar*) fileName;
678 bMore = dir.GetNext(& fileName);
684 // Since wxDir isn't rentrant, we need to gather all the directories
694 bool bMore = dir.GetFirst(& fileName, wxT("*"), wxDIR_DIRS);
697 if (fileName != wxT(".") && fileName != wxT(".."))
700 ecFileName path(pszDir);
701 path += (const wxChar*) fileName;
704 bMore = dir.GetNext(& fileName);
709 for (i = 0; i < ar2.Count(); i++)
712 FindFiles(f, ar, pszPattern, bRecurse, dwExclude);
719 void ecFileName::ReplaceExtension(const wxString& newExt)
721 wxString ext = newExt;
722 if (ext[(unsigned) 0] == wxT('.'))
725 wxStripExtension(* this);
726 this->wxString::Append(wxT("."));
727 this->wxString::Append(ext);