X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/27d98837f3b5589c40137f4a1fa75d28cde75c46..d94de683a60b20153591cc3f8f52a97cf9ce9453:/src/common/filefn.cpp diff --git a/src/common/filefn.cpp b/src/common/filefn.cpp index dec3887eb3..c2614443c7 100644 --- a/src/common/filefn.cpp +++ b/src/common/filefn.cpp @@ -24,16 +24,22 @@ #pragma hdrstop #endif +#include "wx/filefn.h" + #ifndef WX_PRECOMP #include "wx/intl.h" #include "wx/log.h" #include "wx/utils.h" + #include "wx/crt.h" #endif -#include "wx/file.h" // This does include filefn.h +#include "wx/dynarray.h" +#include "wx/file.h" #include "wx/filename.h" #include "wx/dir.h" +#include "wx/tokenzr.h" + // there are just too many of those... #ifdef __VISUALC__ #pragma warning(disable:4706) // assignment within conditional expression @@ -113,54 +119,84 @@ const int wxInvalidOffset = -1; // macros // ---------------------------------------------------------------------------- -// we need to translate Mac filenames before passing them to OS functions +// translate the filenames before passing them to OS functions #define OS_FILENAME(s) (s.fn_str()) // ============================================================================ // implementation // ============================================================================ -#ifdef wxNEED_WX_UNISTD_H +// ---------------------------------------------------------------------------- +// wrappers around standard POSIX functions +// ---------------------------------------------------------------------------- -WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) -{ - return stat( wxConvFile.cWX2MB( file_name ), buf ); -} +#if wxUSE_UNICODE && defined __BORLANDC__ \ + && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 -WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) +// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only +// regardless of the mode parameter. This hack works around the problem by +// setting the mode with _wchmod. +// +int wxCRT_Open(const wchar_t *pathname, int flags, mode_t mode) { - return access( wxConvFile.cWX2MB( pathname ), mode ); -} + int moreflags = 0; -WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) -{ - return open( wxConvFile.cWX2MB( pathname ), flags, mode ); + // we only want to fix the mode when the file is actually created, so + // when creating first try doing it O_EXCL so we can tell if the file + // was already there. + if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) + moreflags = O_EXCL; + + int fd = _wopen(pathname, flags | moreflags, mode); + + // the file was actually created and needs fixing + if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) + { + close(fd); + _wchmod(pathname, mode); + fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); + } + // the open failed, but it may have been because the added O_EXCL stopped + // the opening of an existing file, so try again without. + else if (fd == -1 && moreflags != 0) + { + fd = _wopen(pathname, flags & ~O_CREAT); + } + + return fd; } #endif - // wxNEED_WX_UNISTD_H // ---------------------------------------------------------------------------- // wxPathList // ---------------------------------------------------------------------------- -// IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList) - -static inline wxChar* MYcopystring(const wxString& s) +bool wxPathList::Add(const wxString& path) { - wxChar* copy = new wxChar[s.length() + 1]; - return wxStrcpy(copy, s.c_str()); -} + // add a path separator to force wxFileName to interpret it always as a directory + // (i.e. if we are called with '/home/user' we want to consider it a folder and + // not, as wxFileName would consider, a filename). + wxFileName fn(path + wxFileName::GetPathSeparator()); + + // add only normalized relative/absolute paths + // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to + // normalize paths which starts with ".." (which can be normalized only if + // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return false; -static inline wxChar* MYcopystring(const wxChar* s) -{ - wxChar* copy = new wxChar[wxStrlen(s) + 1]; - return wxStrcpy(copy, s); + wxString toadd = fn.GetPath(); + if (Index(toadd) == wxNOT_FOUND) + wxArrayString::Add(toadd); // do not add duplicates + + return true; } -void wxPathList::Add (const wxString& path) +void wxPathList::Add(const wxArrayString &arr) { - wxStringList::Add (WXSTRINGCAST path); + for (size_t j=0; j < arr.GetCount(); j++) + Add(arr[j]); } // Add paths e.g. from the PATH environment variable @@ -168,43 +204,24 @@ void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) { // No environment variables on WinCE #ifndef __WXWINCE__ + + // The space has been removed from the tokenizers, otherwise a + // path such as "C:\Program Files" would be split into 2 paths: + // "C:\Program" and "Files"; this is true for both Windows and Unix. + static const wxChar PATH_TOKS[] = #if defined(__WINDOWS__) || defined(__OS2__) - /* - The space has been removed from the tokenizers, otherwise a - path such as "C:\Program Files" would be split into 2 paths: - "C:\Program" and "Files" - */ -// wxT(" ;"); // Don't separate with colon in DOS (used for drive) wxT(";"); // Don't separate with colon in DOS (used for drive) #else - wxT(" :;"); + wxT(":;"); #endif - wxString val ; - if (wxGetEnv (WXSTRINGCAST envVariable, &val)) + wxString val; + if ( wxGetEnv(envVariable, &val) ) { - wxChar *s = MYcopystring (val); - wxChar *save_ptr, *token = wxStrtok (s, PATH_TOKS, &save_ptr); - - if (token) - { - Add(token); - while (token) - { - if ( (token = wxStrtok ((wxChar *) NULL, PATH_TOKS, &save_ptr)) - != NULL ) - { - Add(token); - } - } - } - - // suppress warning about unused variable save_ptr when wxStrtok() is a - // macro which throws away its third argument - save_ptr = token; - - delete [] s; + // split into an array of string the value of the env var + wxArrayString arr = wxStringTokenize(val, PATH_TOKS); + WX_APPEND_ARRAY(*this, arr); } #endif // !__WXWINCE__ } @@ -212,65 +229,53 @@ void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) // Given a full filename (with path), ensure that that file can // be accessed again USING FILENAME ONLY by adding the path // to the list if not already there. -void wxPathList::EnsureFileAccessible (const wxString& path) +bool wxPathList::EnsureFileAccessible (const wxString& path) { - wxString path_only(wxPathOnly(path)); - if ( !path_only.empty() ) - { - if ( !Member(path_only) ) - Add(path_only); - } + return Add(wxPathOnly(path)); } -bool wxPathList::Member (const wxString& path) +#if WXWIN_COMPATIBILITY_2_6 +bool wxPathList::Member (const wxString& path) const { - for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext()) - { - wxString path2( node->GetData() ); - if ( -#if defined(__WINDOWS__) || defined(__OS2__) || defined(__VMS__) || defined(__WXMAC__) - // Case INDEPENDENT - path.CompareTo (path2, wxString::ignoreCase) == 0 -#else - // Case sensitive File System - path.CompareTo (path2) == 0 -#endif - ) - return true; - } - return false; + return Index(path) != wxNOT_FOUND; } +#endif -wxString wxPathList::FindValidPath (const wxString& file) +wxString wxPathList::FindValidPath (const wxString& file) const { - wxExpandPath(wxFileFunctionsBuffer, file); - - wxChar buf[_MAXPATHLEN]; - wxStrcpy(buf, wxFileFunctionsBuffer); + // normalize the given string as it could be a path + a filename + // and not only a filename + wxFileName fn(file); + wxString strend; + + // NB: normalize without making absolute otherwise calling this function with + // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop + // below would only add to the paths of this list the 'c.txt' part when doing + // the existence checks... + // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return wxEmptyString; - wxChar *filename = wxIsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (wxChar *)buf; + wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); + if (fn.IsAbsolute()) + strend = fn.GetFullName(); // search for the file name and ignore the path part + else + strend = fn.GetFullPath(); - for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext()) + for (size_t i=0; iGetData()); - wxStrcpy (wxFileFunctionsBuffer, path); - wxChar ch = wxFileFunctionsBuffer[wxStrlen(wxFileFunctionsBuffer)-1]; - if (ch != wxT('\\') && ch != wxT('/')) - wxStrcat (wxFileFunctionsBuffer, wxT("/")); - wxStrcat (wxFileFunctionsBuffer, filename); -#ifdef __WINDOWS__ - wxUnix2DosFilename (wxFileFunctionsBuffer); -#endif - if (wxFileExists (wxFileFunctionsBuffer)) - { - return wxString(wxFileFunctionsBuffer); // Found! - } - } // for() + wxString strstart = Item(i); + if (!strstart.IsEmpty() && strstart.Last() != wxFileName::GetPathSeparator()) + strstart += wxFileName::GetPathSeparator(); + + if (wxFileExists(strstart + strend)) + return strstart + strend; // Found! + } - return wxEmptyString; // Not found + return wxEmptyString; // Not found } -wxString wxPathList::FindAbsoluteValidPath (const wxString& file) +wxString wxPathList::FindAbsoluteValidPath (const wxString& file) const { wxString f = FindValidPath(file); if ( f.empty() || wxIsAbsolutePath(f) ) @@ -287,6 +292,24 @@ wxString wxPathList::FindAbsoluteValidPath (const wxString& file) return buf; } +// ---------------------------------------------------------------------------- +// miscellaneous global functions (TOFIX!) +// ---------------------------------------------------------------------------- + +static inline wxChar* MYcopystring(const wxString& s) +{ + wxChar* copy = new wxChar[s.length() + 1]; + return wxStrcpy(copy, s.c_str()); +} + +template +static inline CharType* MYcopystring(const CharType* s) +{ + CharType* copy = new CharType[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + + bool wxFileExists (const wxString& filename) { @@ -295,7 +318,7 @@ wxFileExists (const wxString& filename) #elif defined(__WIN32__) && !defined(__WXMICROWIN__) // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them - DWORD ret = ::GetFileAttributes(filename); + DWORD ret = ::GetFileAttributes(filename.fn_str()); return (ret != (DWORD)-1) && !(ret & FILE_ATTRIBUTE_DIRECTORY); #else // !__WIN32__ @@ -354,7 +377,8 @@ wxIsAbsolutePath (const wxString& filename) * */ -void wxStripExtension(wxChar *buffer) +template +static void wxDoStripExtension(T *buffer) { int len = wxStrlen(buffer); int i = len-1; @@ -369,6 +393,9 @@ void wxStripExtension(wxChar *buffer) } } +void wxStripExtension(char *buffer) { wxDoStripExtension(buffer); } +void wxStripExtension(wchar_t *buffer) { wxDoStripExtension(buffer); } + void wxStripExtension(wxString& buffer) { //RN: Be careful about the handling the case where @@ -384,17 +411,18 @@ void wxStripExtension(wxString& buffer) } // Destructive removal of /./ and /../ stuff -wxChar *wxRealPath (wxChar *path) +template +static CharType *wxDoRealPath (CharType *path) { #ifdef __WXMSW__ - static const wxChar SEP = wxT('\\'); + static const CharType SEP = wxT('\\'); wxUnix2DosFilename(path); #else - static const wxChar SEP = wxT('/'); + static const CharType SEP = wxT('/'); #endif if (path[0] && path[1]) { /* MATTHEW: special case "/./x" */ - wxChar *p; + CharType *p; if (path[2] == SEP && path[1] == wxT('.')) p = &path[0]; else @@ -405,7 +433,7 @@ wxChar *wxRealPath (wxChar *path) { if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) { - wxChar *q; + CharType *q; for (q = p - 1; q >= path && *q != SEP; q--) { // Empty @@ -439,6 +467,16 @@ wxChar *wxRealPath (wxChar *path) return path; } +char *wxRealPath(char *path) +{ + return wxDoRealPath(path); +} + +wchar_t *wxRealPath(wchar_t *path) +{ + return wxDoRealPath(path); +} + wxString wxRealPath(const wxString& path) { wxChar *buf1=MYcopystring(path); @@ -496,38 +534,39 @@ wxChar *wxCopyAbsolutePath(const wxString& filename) /* input name in name, pathname output to buf. */ -wxChar *wxExpandPath(wxChar *buf, const wxChar *name) +template +static CharType *wxDoExpandPath(CharType *buf, const wxString& name) { - register wxChar *d, *s, *nm; - wxChar lnm[_MAXPATHLEN]; + register CharType *d, *s, *nm; + CharType lnm[_MAXPATHLEN]; int q; // Some compilers don't like this line. -// const wxChar trimchars[] = wxT("\n \t"); +// const CharType trimchars[] = wxT("\n \t"); - wxChar trimchars[4]; + CharType trimchars[4]; trimchars[0] = wxT('\n'); trimchars[1] = wxT(' '); trimchars[2] = wxT('\t'); trimchars[3] = 0; #ifdef __WXMSW__ - const wxChar SEP = wxT('\\'); + const CharType SEP = wxT('\\'); #else - const wxChar SEP = wxT('/'); + const CharType SEP = wxT('/'); #endif buf[0] = wxT('\0'); - if (name == NULL || *name == wxT('\0')) + if (name.empty()) return buf; - nm = MYcopystring(name); // Make a scratch copy - wxChar *nm_tmp = nm; + nm = MYcopystring((const CharType*)name.c_str()); // Make a scratch copy + CharType *nm_tmp = nm; /* Skip leading whitespace and cr */ - while (wxStrchr((wxChar *)trimchars, *nm) != NULL) + while (wxStrchr(trimchars, *nm) != NULL) nm++; /* And strip off trailing whitespace and cr */ s = nm + (q = wxStrlen(nm)) - 1; - while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) + while (q-- && wxStrchr(trimchars, *s) != NULL) *s = wxT('\0'); s = nm; @@ -575,9 +614,9 @@ wxChar *wxExpandPath(wxChar *buf, const wxChar *name) if (*s++ == wxT('$')) #endif { - register wxChar *start = d; + register CharType *start = d; register int braces = (*s == wxT('{') || *s == wxT('(')); - register wxChar *value; + register CharType *value; while ((*d++ = *s) != 0) if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) break; @@ -601,21 +640,22 @@ wxChar *wxExpandPath(wxChar *buf, const wxChar *name) } /* Expand ~ and ~user */ + wxString homepath; nm = lnm; if (nm[0] == wxT('~') && !q) { /* prefix ~ */ if (nm[1] == SEP || nm[1] == 0) { /* ~/filename */ - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { + homepath = wxGetUserHome(wxEmptyString); + if (!homepath.empty()) { + s = (CharType*)(const CharType*)homepath.c_str(); if (*++nm) nm++; } } else { /* ~user/filename */ - register wxChar *nnm; - register wxChar *home; + register CharType *nnm; for (s = nm; *s && *s != SEP; s++) { // Empty @@ -624,8 +664,8 @@ wxChar *wxExpandPath(wxChar *buf, const wxChar *name) was_sep = (*s == SEP); nnm = *s ? s + 1 : s; *s = 0; - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) + homepath = wxGetUserHome(wxString(nm + 1)); + if (homepath.empty()) { if (was_sep) /* replace only if it was there: */ *s = SEP; @@ -634,7 +674,7 @@ wxChar *wxExpandPath(wxChar *buf, const wxChar *name) else { nm = nnm; - s = home; + s = (CharType*)(const CharType*)homepath.c_str(); } } } @@ -658,6 +698,17 @@ wxChar *wxExpandPath(wxChar *buf, const wxChar *name) return wxRealPath(buf); } +char *wxExpandPath(char *buf, const wxString& name) +{ + return wxDoExpandPath(buf, name); +} + +wchar_t *wxExpandPath(wchar_t *buf, const wxString& name) +{ + return wxDoExpandPath(buf, name); +} + + /* Contract Paths to be build upon an environment variable component: @@ -675,22 +726,22 @@ wxContractPath (const wxString& filename, if (filename.empty()) return (wxChar *) NULL; - wxStrcpy (dest, WXSTRINGCAST filename); + wxStrcpy (dest, filename); #ifdef __WXMSW__ wxUnix2DosFilename(dest); #endif // Handle environment - const wxChar *val; + wxString val; #ifndef __WXWINCE__ wxChar *tcp; - if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && + if (!envname.empty() && !(val = wxGetenv (envname)).empty() && (tcp = wxStrstr (dest, val)) != NULL) { - wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); + wxStrcpy (wxFileFunctionsBuffer, tcp + val.length()); *tcp++ = wxT('$'); *tcp++ = wxT('{'); - wxStrcpy (tcp, WXSTRINGCAST envname); + wxStrcpy (tcp, envname); wxStrcat (tcp, wxT("}")); wxStrcat (tcp, wxFileFunctionsBuffer); } @@ -698,10 +749,10 @@ wxContractPath (const wxString& filename, // Handle User's home (ignore root homes!) val = wxGetUserHome (user); - if (!val) + if (val.empty()) return dest; - const size_t len = wxStrlen(val); + const size_t len = val.length(); if (len <= 2) return dest; @@ -709,7 +760,7 @@ wxContractPath (const wxString& filename, { wxStrcpy(wxFileFunctionsBuffer, wxT("~")); if (!user.empty()) - wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); + wxStrcat(wxFileFunctionsBuffer, user); wxStrcat(wxFileFunctionsBuffer, dest + len); wxStrcpy (dest, wxFileFunctionsBuffer); } @@ -805,7 +856,7 @@ wxString wxPathOnly (const wxString& path) wxChar buf[_MAXPATHLEN]; // Local copy - wxStrcpy (buf, WXSTRINGCAST path); + wxStrcpy(buf, path); int l = path.length(); int i = l - 1; @@ -881,13 +932,19 @@ wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathCompon } CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); CFRelease( fullURLRef ) ; - return wxMacCFStringHolder(cfString).AsString(wxLocale::GetSystemEncoding()); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); + CFRelease( cfString ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString(); } OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) { OSStatus err = noErr ; - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, wxMacCFStringHolder(path ,wxLocale::GetSystemEncoding() ) , kDefaultPathStyle, false); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); + CFRelease( cfMutableString ); if ( NULL != url ) { if ( CFURLGetFSRef(url, fsRef) == false ) @@ -906,9 +963,14 @@ wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, uniname->unicode, uniname->length ); - return wxMacCFStringHolder(cfname).AsString() ; + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); + CFRelease( cfname ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString() ; } +#ifndef __LP64__ + wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) { FSRef fsRef ; @@ -926,11 +988,12 @@ void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) wxMacPathToFSRef( path , &fsRef ) ; err = FSRefMakeFSSpec( &fsRef , spec ) ; } +#endif #endif // __WXMAC__ -void -wxDos2UnixFilename (wxChar *s) +template +static void wxDoDos2UnixFilename(T *s) { if (s) while (*s) @@ -939,17 +1002,21 @@ wxDos2UnixFilename (wxChar *s) *s = _T('/'); #ifdef __WXMSW__ else - *s = (wxChar)wxTolower (*s); // Case INDEPENDENT + *s = wxTolower(*s); // Case INDEPENDENT #endif s++; } } -void +void wxDos2UnixFilename(char *s) { wxDoDos2UnixFilename(s); } +void wxDos2UnixFilename(wchar_t *s) { wxDoDos2UnixFilename(s); } + +template +static void #if defined(__WXMSW__) || defined(__OS2__) -wxUnix2DosFilename (wxChar *s) +wxDoUnix2DosFilename(T *s) #else -wxUnix2DosFilename (wxChar *WXUNUSED(s) ) +wxDoUnix2DosFilename(T *WXUNUSED(s) ) #endif { // Yes, I really mean this to happen under DOS only! JACS @@ -964,6 +1031,9 @@ wxUnix2DosFilename (wxChar *WXUNUSED(s) ) #endif } +void wxUnix2DosFilename(char *s) { wxDoUnix2DosFilename(s); } +void wxUnix2DosFilename(wchar_t *s) { wxDoUnix2DosFilename(s); } + // Concatenate two files to form third bool wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) @@ -1002,6 +1072,51 @@ wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& fil #endif } +// helper of generic implementation of wxCopyFile() +#if !(defined(__WIN32__) || defined(__OS2__) || defined(__PALMOS__)) && \ + wxUSE_FILE + +static bool +wxDoCopyFile(wxFile& fileIn, + const wxStructStat& fbuf, + const wxString& filenameDst, + bool overwrite) +{ + // reset the umask as we want to create the file with exactly the same + // permissions as the original one + wxCHANGE_UMASK(0); + + // create file2 with the same permissions than file1 and open it for + // writing + + wxFile fileOut; + if ( !fileOut.Create(filenameDst, overwrite, fbuf.st_mode & 0777) ) + return false; + + // copy contents of file1 to file2 + char buf[4096]; + for ( ;; ) + { + ssize_t count = fileIn.Read(buf, WXSIZEOF(buf)); + if ( count == wxInvalidOffset ) + return false; + + // end of file? + if ( !count ) + break; + + if ( fileOut.Write(buf, count) < (size_t)count ) + return false; + } + + // we can expect fileIn to be closed successfully, but we should ensure + // that fileOut was closed as some write errors (disk full) might not be + // detected before doing this + return fileIn.Close() && fileOut.Close(); +} + +#endif // generic implementation of wxCopyFile + // Copy files bool wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) @@ -1011,7 +1126,7 @@ wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) // instead of our code if available // // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite - if ( !::CopyFile(file1, file2, !overwrite) ) + if ( !::CopyFile(file1.fn_str(), file2.fn_str(), !overwrite) ) { wxLogSysError(_("Failed to copy the file '%s' to '%s'"), file1.c_str(), file2.c_str()); @@ -1019,7 +1134,7 @@ wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) return false; } #elif defined(__OS2__) - if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) + if ( ::DosCopy(file1.c_str(), file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) return false; #elif defined(__PALMOS__) // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ @@ -1051,39 +1166,49 @@ wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) return false; } - // reset the umask as we want to create the file with exactly the same - // permissions as the original one - wxCHANGE_UMASK(0); - - // create file2 with the same permissions than file1 and open it for - // writing + wxDoCopyFile(fileIn, fbuf, file2, overwrite); - wxFile fileOut; - if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) - return false; +#if defined(__WXMAC__) || defined(__WXCOCOA__) + // copy the resource fork of the file too if it's present + wxString pathRsrcOut; + wxFile fileRsrcIn; - // copy contents of file1 to file2 - char buf[4096]; - size_t count; - for ( ;; ) { - count = fileIn.Read(buf, WXSIZEOF(buf)); - if ( fileIn.Error() ) - return false; + // suppress error messages from this block as resource forks don't have + // to exist + wxLogNull noLog; + + // it's not enough to check for file existence: it always does on HFS + // but is empty for files without resources + if ( fileRsrcIn.Open(file1 + wxT("/..namedfork/rsrc")) && + fileRsrcIn.Length() > 0 ) + { + // we must be using HFS or another filesystem with resource fork + // support, suppose that destination file system also is HFS[-like] + pathRsrcOut = file2 + wxT("/..namedfork/rsrc"); + } + else // check if we have resource fork in separate file (non-HFS case) + { + wxFileName fnRsrc(file1); + fnRsrc.SetName(wxT("._") + fnRsrc.GetName()); - // end of file? - if ( !count ) - break; + fileRsrcIn.Close(); + if ( fileRsrcIn.Open( fnRsrc.GetFullPath() ) ) + { + fnRsrc = file2; + fnRsrc.SetName(wxT("._") + fnRsrc.GetName()); - if ( fileOut.Write(buf, count) < count ) - return false; + pathRsrcOut = fnRsrc.GetFullPath(); + } + } } - // we can expect fileIn to be closed successfully, but we should ensure - // that fileOut was closed as some write errors (disk full) might not be - // detected before doing this - if ( !fileIn.Close() || !fileOut.Close() ) - return false; + if ( !pathRsrcOut.empty() ) + { + if ( !wxDoCopyFile(fileRsrcIn, fbuf, pathRsrcOut, overwrite) ) + return false; + } +#endif // wxMac || wxCocoa #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) // no chmod in VA. Should be some permission API for HPFS386 partitions @@ -1148,7 +1273,7 @@ bool wxRemoveFile(const wxString& file) || (defined(__MWERKS__) && defined(__MSL__)) int res = wxRemove(file); #elif defined(__WXMAC__) - int res = unlink(wxFNCONV(file)); + int res = unlink(file.fn_str()); #elif defined(__WXPALMOS__) int res = 1; // TODO with VFSFileDelete() @@ -1164,7 +1289,7 @@ bool wxMkdir(const wxString& dir, int perm) #if defined(__WXPALMOS__) return false; #elif defined(__WXMAC__) && !defined(__UNIX__) - return (mkdir( wxFNCONV(dir) , 0 ) == 0); + return (mkdir(dir.fn_str() , 0 ) == 0); #else // !Mac const wxChar *dirname = dir.c_str(); @@ -1212,9 +1337,9 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) #if defined(__VMS__) return false; //to be changed since rmdir exists in VMS7.x #elif defined(__OS2__) - return (::DosDeleteDir((PSZ)dir.c_str()) == 0); + return (::DosDeleteDir(dir.c_str()) == 0); #elif defined(__WXWINCE__) - return (CreateDirectory(dir, NULL) != 0); + return (RemoveDirectory(dir) != 0); #elif defined(__WXPALMOS__) // TODO with VFSFileRename() return false; @@ -1224,14 +1349,14 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) } // does the path exists? (may have or not '/' or '\\' at the end) -bool wxDirExists(const wxChar *pszPathName) +bool wxDirExists(const wxString& pathName) { - wxString strPath(pszPathName); + wxString strPath(pathName); #if defined(__WINDOWS__) || defined(__OS2__) // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, // so remove all trailing backslashes from the path - but don't do this for - // the pathes "d:\" (which are different from "d:") nor for just "\" + // the paths "d:\" (which are different from "d:") nor for just "\" while ( wxEndsWithPathSeparator(strPath) ) { size_t len = strPath.length(); @@ -1252,7 +1377,7 @@ bool wxDirExists(const wxChar *pszPathName) return false; #elif defined(__WIN32__) && !defined(__WXMICROWIN__) // stat() can't cope with network paths - DWORD ret = ::GetFileAttributes(strPath); + DWORD ret = ::GetFileAttributes(strPath.fn_str()); return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); #elif defined(__OS2__) @@ -1270,7 +1395,7 @@ bool wxDirExists(const wxChar *pszPathName) return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); #else // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only - return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); + return wxStat(strPath.c_str(), &st) == 0 && (st.st_mode == S_IFDIR); #endif #endif // __WIN32__/!__WIN32__ @@ -1279,9 +1404,8 @@ bool wxDirExists(const wxChar *pszPathName) // Get a temporary filename, opening and closing the file. wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) { -#if wxUSE_FILE - wxString filename = wxFileName::CreateTempFileName(prefix); - if ( filename.empty() ) + wxString filename; + if ( !wxGetTempFileName(prefix, filename) ) return NULL; if ( buf ) @@ -1290,19 +1414,20 @@ wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) buf = MYcopystring(filename); return buf; -#else - wxUnusedVar(prefix); - wxUnusedVar(buf); - // wxFileName::CreateTempFileName needs wxFile class enabled - return NULL; -#endif } bool wxGetTempFileName(const wxString& prefix, wxString& buf) { - buf = wxGetTempFileName(prefix); +#if wxUSE_FILE + buf = wxFileName::CreateTempFileName(prefix); return !buf.empty(); +#else // !wxUSE_FILE + wxUnusedVar(prefix); + wxUnusedVar(buf); + + return false; +#endif // wxUSE_FILE/!wxUSE_FILE } // Get first file name matching given wild card. @@ -1310,7 +1435,7 @@ bool wxGetTempFileName(const wxString& prefix, wxString& buf) static wxDir *gs_dir = NULL; static wxString gs_dirPath; -wxString wxFindFirstFile(const wxChar *spec, int flags) +wxString wxFindFirstFile(const wxString& spec, int flags) { wxSplitPath(spec, &gs_dirPath, NULL, NULL); if ( gs_dirPath.empty() ) @@ -1337,7 +1462,7 @@ wxString wxFindFirstFile(const wxChar *spec, int flags) } wxString result; - gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); + gs_dir->GetFirst(&result, wxFileNameFromPath(spec), dirFlags); if ( result.empty() ) { wxDELETE(gs_dir); @@ -1402,7 +1527,7 @@ wxChar *wxDoGetCwd(wxChar *buf, int sz) #ifdef HAVE_WGETCWD #if wxUSE_UNICODE_MSLU - if ( wxGetOsVersion() != wxWIN95 ) + if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) #else char *cbuf = NULL; // never really used because needsANSI will always be false #endif @@ -1519,7 +1644,15 @@ wxString wxGetCwd() bool wxSetWorkingDirectory(const wxString& d) { #if defined(__OS2__) - return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); + if (d[1] == ':') + { + ::DosSetDefaultDisk(wxToupper(d[0]) - _T('A') + 1); + // do not call DosSetCurrentDir when just changing drive, + // since it requires e.g. "d:." instead of "d:"! + if (d.length() == 2) + return true; + } + return (::DosSetCurrentDir(d.c_str()) == 0); #elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); #elif defined(__WINDOWS__) @@ -1530,7 +1663,7 @@ bool wxSetWorkingDirectory(const wxString& d) wxUnusedVar(d); return false; #else - return (bool)(SetCurrentDirectory(d) != 0); + return (bool)(SetCurrentDirectory(d.fn_str()) != 0); #endif #else // Must change drive, too. @@ -1576,66 +1709,54 @@ wxString wxGetOSDirectory() #endif } -bool wxEndsWithPathSeparator(const wxChar *pszFileName) +bool wxEndsWithPathSeparator(const wxString& filename) { - size_t len = wxStrlen(pszFileName); - - return len && wxIsPathSeparator(pszFileName[len - 1]); + return !filename.empty() && wxIsPathSeparator(filename.Last()); } // find a file in a list of directories, returns false if not found -bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) +bool wxFindFileInPath(wxString *pStr, const wxString& szPath, const wxString& szFile) { // we assume that it's not empty - wxCHECK_MSG( !wxIsEmpty(pszFile), false, + wxCHECK_MSG( !szFile.empty(), false, _T("empty file name in wxFindFileInPath")); // skip path separator in the beginning of the file name if present - if ( wxIsPathSeparator(*pszFile) ) - pszFile++; - - // copy the path (strtok will modify it) - wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; - wxStrcpy(szPath, pszPath); - - wxString strFile; - wxChar *pc, *save_ptr; - for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); - pc != NULL; - pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) + wxString szFile2; + if ( wxIsPathSeparator(szFile[0u]) ) + szFile2 = szFile.Mid(1); + else + szFile2 = szFile; + + wxStringTokenizer tkn(szPath, wxPATH_SEP); + + while ( tkn.HasMoreTokens() ) { - // search for the file in this directory - strFile = pc; - if ( !wxEndsWithPathSeparator(pc) ) + wxString strFile = tkn.GetNextToken(); + if ( !wxEndsWithPathSeparator(strFile) ) strFile += wxFILE_SEP_PATH; - strFile += pszFile; + strFile += szFile2; - if ( wxFileExists(strFile) ) { + if ( wxFileExists(strFile) ) + { *pStr = strFile; - break; + return true; } } - // suppress warning about unused variable save_ptr when wxStrtok() is a - // macro which throws away its third argument - save_ptr = pc; - - delete [] szPath; - - return pc != NULL; // if true => we breaked from the loop + return false; } -void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, +void WXDLLEXPORT wxSplitPath(const wxString& fileName, wxString *pstrPath, wxString *pstrName, wxString *pstrExt) { - // it can be empty, but it shouldn't be NULL - wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); - - wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); + wxFileName::SplitPath(fileName, pstrPath, pstrName, pstrExt); } +#if wxUSE_DATETIME + time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) { wxDateTime mtime; @@ -1645,6 +1766,8 @@ time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) return mtime.GetTicks(); } +#endif // wxUSE_DATETIME + // Parses the filterStr, returning the number of filters. // Returns 0 if none or if there's a problem. @@ -1757,6 +1880,152 @@ int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, return filters.GetCount(); } +#if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__)) +static bool wxCheckWin32Permission(const wxString& path, DWORD access) +{ + // quoting the MSDN: "To obtain a handle to a directory, call the + // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this + // doesn't work under Win9x/ME but then it's not needed there anyhow + bool isdir = wxDirExists(path); + if ( isdir && wxGetOsVersion() == wxOS_WINDOWS_9X ) + { + // FAT directories always allow all access, even if they have the + // readonly flag set + return true; + } + + HANDLE h = ::CreateFile + ( + path.wx_str(), + access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + isdir ? FILE_FLAG_BACKUP_SEMANTICS : 0, + NULL + ); + if ( h != INVALID_HANDLE_VALUE ) + CloseHandle(h); + + return h != INVALID_HANDLE_VALUE; +} +#endif // __WINDOWS__ + +bool wxIsWritable(const wxString &path) +{ +#if defined( __UNIX__ ) || defined(__OS2__) + // access() will take in count also symbolic links + return access(path.fn_str(), W_OK) == 0; +#elif defined( __WINDOWS__ ) + return wxCheckWin32Permission(path, GENERIC_WRITE); +#else + wxUnusedVar(path); + // TODO + return false; +#endif +} + +bool wxIsReadable(const wxString &path) +{ +#if defined( __UNIX__ ) || defined(__OS2__) + // access() will take in count also symbolic links + return access(path.fn_str(), R_OK) == 0; +#elif defined( __WINDOWS__ ) + return wxCheckWin32Permission(path, GENERIC_READ); +#else + wxUnusedVar(path); + // TODO + return false; +#endif +} + +bool wxIsExecutable(const wxString &path) +{ +#if defined( __UNIX__ ) || defined(__OS2__) + // access() will take in count also symbolic links + return access(path.fn_str(), X_OK) == 0; +#elif defined( __WINDOWS__ ) + return wxCheckWin32Permission(path, GENERIC_EXECUTE); +#else + wxUnusedVar(path); + // TODO + return false; +#endif +} + +// Return the type of an open file +// +// Some file types on some platforms seem seekable but in fact are not. +// The main use of this function is to allow such cases to be detected +// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK). +// +// This is important for the archive streams, which benefit greatly from +// being able to seek on a stream, but which will produce corrupt archives +// if they unknowingly seek on a non-seekable stream. +// +// wxFILE_KIND_DISK is a good catch all return value, since other values +// disable features of the archive streams. Some other value must be returned +// for a file type that appears seekable but isn't. +// +// Known examples: +// * Pipes on Windows +// * Files on VMS with a record format other than StreamLF +// +wxFileKind wxGetFileKind(int fd) +{ +#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle + switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE) + { + case FILE_TYPE_CHAR: + return wxFILE_KIND_TERMINAL; + case FILE_TYPE_DISK: + return wxFILE_KIND_DISK; + case FILE_TYPE_PIPE: + return wxFILE_KIND_PIPE; + } + + return wxFILE_KIND_UNKNOWN; + +#elif defined(__UNIX__) + if (isatty(fd)) + return wxFILE_KIND_TERMINAL; + + struct stat st; + fstat(fd, &st); + + if (S_ISFIFO(st.st_mode)) + return wxFILE_KIND_PIPE; + if (!S_ISREG(st.st_mode)) + return wxFILE_KIND_UNKNOWN; + + #if defined(__VMS__) + if (st.st_fab_rfm != FAB$C_STMLF) + return wxFILE_KIND_UNKNOWN; + #endif + + return wxFILE_KIND_DISK; + +#else + #define wxFILEKIND_STUB + (void)fd; + return wxFILE_KIND_DISK; +#endif +} + +wxFileKind wxGetFileKind(FILE *fp) +{ + // Note: The watcom rtl dll doesn't have fileno (the static lib does). + // Should be fixed in version 1.4. +#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4) + (void)fp; + return wxFILE_KIND_DISK; +#elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__) + return fp ? wxGetFileKind(_fileno(fp)) : wxFILE_KIND_UNKNOWN; +#else + return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN; +#endif +} + //------------------------------------------------------------------------ // wild character routines @@ -1764,17 +2033,19 @@ int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, bool wxIsWild( const wxString& pattern ) { - wxString tmp = pattern; - wxChar *pat = WXSTRINGCAST(tmp); - while (*pat) + for ( wxString::const_iterator p = pattern.begin(); p != pattern.end(); ++p ) { - switch (*pat++) + switch ( (*p).GetValue() ) { - case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): - return true; - case wxT('\\'): - if (!*pat++) - return false; + case wxT('?'): + case wxT('*'): + case wxT('['): + case wxT('{'): + return true; + + case wxT('\\'): + if ( ++p == pattern.end() ) + return false; } } return false; @@ -1889,77 +2160,6 @@ bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) } } -// Return the type of an open file -// -// Some file types on some platforms seem seekable but in fact are not. -// The main use of this function is to allow such cases to be detected -// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK). -// -// This is important for the archive streams, which benefit greatly from -// being able to seek on a stream, but which will produce corrupt archives -// if they unknowingly seek on a non-seekable stream. -// -// wxFILE_KIND_DISK is a good catch all return value, since other values -// disable features of the archive streams. Some other value must be returned -// for a file type that appears seekable but isn't. -// -// Known examples: -// * Pipes on Windows -// * Files on VMS with a record format other than StreamLF -// -wxFileKind wxGetFileKind(int fd) -{ -#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle - switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE) - { - case FILE_TYPE_CHAR: - return wxFILE_KIND_TERMINAL; - case FILE_TYPE_DISK: - return wxFILE_KIND_DISK; - case FILE_TYPE_PIPE: - return wxFILE_KIND_PIPE; - } - - return wxFILE_KIND_UNKNOWN; - -#elif defined(__UNIX__) - if (isatty(fd)) - return wxFILE_KIND_TERMINAL; - - struct stat st; - fstat(fd, &st); - - if (S_ISFIFO(st.st_mode)) - return wxFILE_KIND_PIPE; - if (!S_ISREG(st.st_mode)) - return wxFILE_KIND_UNKNOWN; - - #if defined(__VMS__) - if (st.st_fab_rfm != FAB$C_STMLF) - return wxFILE_KIND_UNKNOWN; - #endif - - return wxFILE_KIND_DISK; - -#else - #define wxFILEKIND_STUB - (void)fd; - return wxFILE_KIND_DISK; -#endif -} - -wxFileKind wxGetFileKind(FILE *fp) -{ - // Note: The watcom rtl dll doesn't have fileno (the static lib does). - // Should be fixed in version 1.4. -#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4) - (void)fp; - return wxFILE_KIND_DISK; -#else - return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN; -#endif -} - #ifdef __VISUALC__ #pragma warning(default:4706) // assignment within conditional expression #endif // VC++