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"
52 #ifdef CreateDirectory
53 #undef CreateDirectory
55 #ifdef ExpandEnvironmentStrings
56 #undef ExpandEnvironmentStrings
58 #ifdef GetCurrentDirectory
59 #undef GetCurrentDirectory
61 #ifdef SetCurrentDirectory
62 #undef SetCurrentDirectory
78 const wxChar ecFileName::cSep=wxFILE_SEP_PATH;
80 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2):
87 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3):
95 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3,const wxChar* psz4):
104 ecFileName::ecFileName(const wxChar* psz1,const wxChar* psz2,const wxChar* psz3,const wxChar* psz4,const wxChar* psz5):
114 ecFileName::~ecFileName()
116 // Unfortunately we can't do this since GetStringData is private in wxString.
117 // So for now, we may memory leaks since ~wxString is not virtual.
118 //GetStringData()->Unlock();
122 ecFileName operator+(const ecFileName& string1, const ecFileName& string2)
125 s.ConcatCopy(string1, string2);
129 ecFileName operator+(const ecFileName& string, const wxChar* lpsz)
135 s.ConcatCopy(string, wxString(lpsz));
139 ecFileName operator+(const wxChar* lpsz, const ecFileName& string)
145 s.ConcatCopy(wxString(lpsz), string);
149 ecFileName operator+(const ecFileName& string1, wxChar ch)
152 s.ConcatCopy(string1, wxString(ch));
156 ecFileName operator+(wxChar ch, const ecFileName& string)
159 s.ConcatCopy(wxString(ch), string);
163 const ecFileName& ecFileName::operator+=(const wxChar* lpsz)
168 ConcatInPlace(wxString(lpsz));
172 const ecFileName& ecFileName::operator+=(wxChar ch)
174 ConcatInPlace(wxString(ch));
178 const ecFileName& ecFileName::operator+=(const ecFileName& string)
180 ConcatInPlace(string);
184 void ecFileName::ConcatInPlace(const wxString& src)
186 ConcatCopy(* this, src);
189 void ecFileName::ConcatCopy(const wxString& src1,
190 const wxString& src2)
192 int nSrc1Len = src1.Len();
193 int nSrc2Len = src2.Len();
195 int nNewLen = nSrc1Len + nSrc2Len;
198 if(1==nSrc2Len && cSep==src2[0])
200 // Appending a single separator to a non-null string is a no-op
203 // Count the intervening separators
204 n=(cSep==src1[nSrc1Len-1])+(cSep==src2[0]);
208 (*this) = src1 + wxString(cSep) + src2;
211 (*this) = src1 + src2;
214 (*this) = src1 + src2.Mid(1);
222 void ecFileName::Normalize()
224 // Remove any trailing seperator
226 if (len > 0 && (*this)[(size_t)(len - 1)] == cSep)
227 (*this) = Mid(0, len - 1);
231 const ecFileName ecFileName::FullName() const
235 long dwSize=::GetFullPathName (*this, 0, NULL, &pFile);
238 ::GetFullPathName (*this, 1+dwSize, strCopy.GetWriteBuf(1+dwSize), &pFile);
239 strCopy.UngetWriteBuf();
245 return wxGetCwd() + wxString(cSep) + wxString(*this);
249 const ecFileName ecFileName::ShortName() const
252 long dwSize=::GetShortPathName (*this, NULL, 0);
255 ::GetShortPathName (*this, strCopy.GetWriteBuf(1+dwSize), 1+dwSize);
256 strCopy.UngetWriteBuf();
266 const ecFileName ecFileName::NoSpaceName() const// sans spaces
271 // Only replace components with spaces with FAT names.
272 wxArrayString ar1,ar2;
273 const wxString str2(ShortName());
277 unsigned int len = Len();
279 for (i = 0; i < len; i++)
281 if(wxTChar('\\')==(*this)[i])
283 ar1.Add(this->Mid(pcStart, i - pcStart + 1));
287 ar1.Add(this->Mid(pcStart, i - pcStart + 1));
291 for (i = 0; i < len; i++)
293 if(wxTChar('\\')==str2[i])
295 ar2.Add(str2.Mid(pcStart, i - pcStart + 1));
299 ar2.Add(str2.Mid(pcStart, i - pcStart + 1));
301 wxASSERT(ar1.Count()==ar2.Count());
304 for(i=0;i<ar1.Count();i++){
305 rc+=(-1==ar1[i].Find(wxTChar(' ')))?ar1[i]:ar2[i];
312 const ecFileName ecFileName::Tail() const
314 return AfterLast(cSep);
317 const ecFileName ecFileName::Head() const
319 return BeforeLast(cSep);
322 time_t ecFileName::LastModificationTime() const
324 return wxFileModificationTime(* this);
327 // GetFileAttributes is not available in Win95 so we test the water first
328 static HINSTANCE hInst=LoadLibrary(_T("kernel32.dll"));
332 #define GETFILEATTRIBUTESNAME "GetFileAttributesExW"
334 #define GETFILEATTRIBUTESNAME "GetFileAttributesExA"
337 typedef BOOL (WINAPI *GetFileAttributesP)(const wxChar*,GET_FILEEX_INFO_LEVELS,LPVOID);
339 static GetFileAttributesP p=(GetFileAttributesP)GetProcAddress(hInst,GETFILEATTRIBUTESNAME);
341 WIN32_FILE_ATTRIBUTE_DATA data;
343 if((*p)(*this, GetFileExInfoStandard, (LPVOID)&data)){
344 return data.ftLastWriteTime;
347 HANDLE h=CreateFile(*this,0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
349 if(INVALID_HANDLE_VALUE!=h){
350 BOOL b=::GetFileTime(h,NULL,NULL,&ft);
357 static FILETIME ftNull={0,0};
363 bool ecFileName::SetFileAttributes(long dwFileAttributes) const
365 return ::SetFileAttributes (*this, dwFileAttributes)!=0;
369 bool ecFileName::Exists () const
371 return IsFile() || IsDir() ;
374 bool ecFileName::IsDir () const
376 return wxPathExists(* this);
379 bool ecFileName::IsFile () const
381 #if defined(__WXMAC__)
383 if (filename && stat (wxUnix2MacFilename(filename), &stbuf) == 0 )
388 if ((*this) != wxT("") && wxStat (wxFNSTRINGCAST fn_str(), &st) == 0 && (st.st_mode & S_IFREG))
395 bool ecFileName::IsReadOnly () const
398 long a=GetFileAttributes(* this); return 0xFFFFFFFF!=a && (0!=(a&FILE_ATTRIBUTE_READONLY ));
400 wxFAIL_MSG("ecFileName::IsReadOnly not supported on this platform.");
405 bool ecFileName::SameFile(const ecFileName &o) const
408 return 0==ShortName().CmpNoCase(o.ShortName());
410 // On most other platforms, case is important.
415 ecFileName ecFileName::ExpandEnvironmentStrings(const wxChar* psz)
417 // wxExpandEnvVars is from confbase.h
419 ecFileName f = wxExpandEnvVars(psz);
423 const ecFileName& ecFileName::ExpandEnvironmentStrings()
425 *this=ecFileName::ExpandEnvironmentStrings(*this);
430 // Helper for Relative() psz is in full format.
431 ecFileName ecFileName::Drive(const wxChar* psz)
433 if(wxIsalpha(psz[0])){
435 } else if(cSep==psz[0]&&cSep==psz[1]){
436 wxChar *c=_tcschr(psz+2,cSep);
440 return wxString(psz,c-psz);
448 ecFileName ecFileName::Relative(const wxChar* compare,const wxChar* current)
452 bool b=(TRUE==PathRelativePathTo(rc.GetWriteBuf(1+MAX_PATH),current,FILE_ATTRIBUTE_DIRECTORY,compare,0));
454 return b?(ecFileName)rc:(ecFileName)compare;
456 wxFAIL_MSG("ecFileName::Relative not implemented on this platform.");
461 const ecFileName& ecFileName::MakeRelative(const wxChar* pszRelativeTo)
463 *this=ecFileName::Relative(*this,pszRelativeTo);
468 ecFileName ecFileName::GetCurrentDirectory()
478 const ecFileName& ecFileName::Append(const wxChar* lpsz)
483 //wxString::ConcatInPlace(lpsz);
484 wxString::Append(lpsz);
489 const ecFileName& ecFileName::Append(wxChar ch)
491 ConcatInPlace(wxString(ch));
495 bool ecFileName::IsAbsolute() const
498 const wxString& psz=*this;
500 (nLength>0 && (cSep==psz[0]))|| // starts with '\'
502 (wxIsalpha(psz[0]) && wxTChar(':')==psz[1]) || // starts with [e.g.] "c:\"
503 (cSep==psz[0] && cSep==psz[1]))); // UNC
508 // Return an array of filename pieces. Plugs '\0's into 'this', which
509 // is therefore subsequently only usable as referenced by the returned array.
510 const wxChar* *ecFileName::Chop()
513 // Count the separators
515 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
518 const wxChar* *ar=new const wxChar*[2+nSeps]; // +1 for first, +1 for terminating 0
521 for(c=_tcschr(m_pchData,cSep);c;c=_tcschr(c+1,cSep)){
530 ecFileName ecFileName::GetTempPath()
535 ::GetTempPathW(1+MAX_PATH,f.GetWriteBuf(1+MAX_PATH));
537 ::GetTempPathA(1+MAX_PATH,f.GetWriteBuf(1+MAX_PATH));
540 #elif defined(__WXGTK__)
542 wxFAIL("ecFileName::GetTempPath() not implemented on this platform.");
548 const ecFileName ecFileName::CygPath () const
551 ecFileName rc = ShortName();
552 if(wxIsalpha(rc[(size_t)0]) && wxTChar(':')==rc[(size_t)1])
554 // Convert c:\ to /cygdrive/c/
555 wxString s = wxString(wxT("/cygdrive/")) + wxString(rc[(size_t)0]) + rc.Mid(2);
559 for (i = 0; i < rc.Len(); i++)
561 if (rc[i] == wxTChar('\\'))
562 rc[i] = wxTChar('/');
565 const ecFileName& rc = * this;
571 bool ecFileName::CreateDirectory(bool bParentsToo,bool bFailIfAlreadyExists) const
575 // Create intermediate directories
577 // 'rest' will progressively have its separators replaced by underscores in order
578 // to find the next separator
579 wxString rest = * this;
581 int len = rest.Len();
584 // If the path is a network path, ignore the first part of the path
585 if (len > 2 && (rest.GetChar(0) == wxT('\\') || rest.GetChar(0) == wxT('/')) && (rest.GetChar(1) == wxT('\\') || rest.GetChar(1) == wxT('/')))
587 rest.SetChar(0,wxT('_')); rest.SetChar(1,wxT('_'));
588 lastPos = rest.Find(cSep);
589 if (lastPos != -1 && lastPos >= 0)
590 rest.SetChar(lastPos,wxT('_'));
594 while (lastPos != -1)
596 lastPos = rest.Find(cSep);
597 if (lastPos != -1 && lastPos >= 0)
599 rest[lastPos] = wxT('_'); // So we find the NEXT separator
601 // don't attempt to create "C: or /"
602 if (lastPos > 0 && (*this)[lastPos-1] == wxT(':'))
604 else if (lastPos == 0)
608 // Fail if any of the dirs exist already
609 wxString str(this->Mid(0, lastPos));
610 bool alreadyExists = wxDirExists(str);
611 if (alreadyExists && bFailIfAlreadyExists)
621 return IsDir()? (!bFailIfAlreadyExists) : (TRUE==wxMkdir(*this));
625 const wxString ecFileName::Extension() const
627 wxString path, name, ext;
629 wxSplitPath(*this, & path, & name, & ext);
633 const wxString ecFileName::Root() const
635 return wxPathOnly(*this);
638 ecFileName ecFileName::SetCurrentDirectory(const wxChar* pszDir)
640 const ecFileName strPwd=wxGetCwd();
641 if (::wxSetWorkingDirectory(pszDir))
647 bool ecFileName::RecursivelyDelete()
651 for(i=FindFiles(*this,ar)-1;i>=0;--i){
654 for(i=FindFiles(*this,ar,wxT("*.*"),TRUE,0)-1;i>=0;--i){
657 return TRUE==wxRmdir(*this);
660 // TODO: take account of dwExclude
661 int ecFileName::FindFiles (const wxString& pszDir,wxArrayString &ar,const wxString& pszPattern/*=wxT("*.*")*/,bool bRecurse/*=TRUE*/,long dwExclude/*=wxDIR_DIRS|wxDIR_HIDDEN*/)
670 bool bMore = dir.GetFirst(& fileName, pszPattern, wxDIR_FILES);
673 if (fileName != wxT(".") && fileName != wxT(".."))
676 ecFileName path(pszDir);
677 path += (const wxChar*) fileName;
680 bMore = dir.GetNext(& fileName);
686 // Since wxDir isn't rentrant, we need to gather all the directories
696 bool bMore = dir.GetFirst(& fileName, wxT("*"), wxDIR_DIRS);
699 if (fileName != wxT(".") && fileName != wxT(".."))
702 ecFileName path(pszDir);
703 path += (const wxChar*) fileName;
706 bMore = dir.GetNext(& fileName);
711 for (i = 0; i < ar2.Count(); i++)
714 FindFiles(f, ar, pszPattern, bRecurse, dwExclude);
721 void ecFileName::ReplaceExtension(const wxString& newExt)
723 wxString ext = newExt;
724 if (ext[(unsigned) 0] == wxT('.'))
727 wxStripExtension(* this);
728 this->wxString::Append(wxT("."));
729 this->wxString::Append(ext);