X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/739cb14a31adcd3af2cf3ef14677e5ea32af24ca..8856768e6eb5ee28b3cab2f63baa2a9713d5b69b:/src/common/filefn.cpp diff --git a/src/common/filefn.cpp b/src/common/filefn.cpp index 5824391e0f..d690e66d9d 100644 --- a/src/common/filefn.cpp +++ b/src/common/filefn.cpp @@ -24,16 +24,20 @@ #pragma hdrstop #endif +#include "wx/filefn.h" + #ifndef WX_PRECOMP #include "wx/intl.h" #include "wx/log.h" #include "wx/utils.h" #endif -#include "wx/file.h" // This does include filefn.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,13 +117,17 @@ 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 // ============================================================================ +// ---------------------------------------------------------------------------- +// wrappers around standard POSIX functions +// ---------------------------------------------------------------------------- + #ifdef wxNEED_WX_UNISTD_H WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) @@ -127,6 +135,11 @@ WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) return stat( wxConvFile.cWX2MB( file_name ), buf ); } +WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) +{ + return lstat( wxConvFile.cWX2MB( file_name ), buf ); +} + WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) { return access( wxConvFile.cWX2MB( pathname ), mode ); @@ -137,30 +150,37 @@ WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) return open( wxConvFile.cWX2MB( pathname ), flags, mode ); } -#endif - // wxNEED_WX_UNISTD_H +#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 +188,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 +213,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 +276,23 @@ 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()); +} + +static inline wxChar* MYcopystring(const wxChar* s) +{ + wxChar* copy = new wxChar[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + + bool wxFileExists (const wxString& filename) { @@ -883,15 +889,15 @@ wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathCompon CFRelease( fullURLRef ) ; CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); CFRelease( cfString ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); - return wxMacCFStringHolder(cfMutableString).AsString(wxLocale::GetSystemEncoding()); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString(); } OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) { OSStatus err = noErr ; - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path ,wxLocale::GetSystemEncoding() ) ) ; - CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); CFRelease( cfMutableString ); if ( NULL != url ) @@ -914,10 +920,12 @@ wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) uniname->length ); CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); CFRelease( cfname ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); return wxMacCFStringHolder(cfMutableString).AsString() ; } +#ifndef __LP64__ + wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) { FSRef fsRef ; @@ -935,6 +943,7 @@ void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) wxMacPathToFSRef( path , &fsRef ) ; err = FSRefMakeFSSpec( &fsRef , spec ) ; } +#endif #endif // __WXMAC__ @@ -1240,7 +1249,7 @@ bool wxDirExists(const wxChar *pszPathName) #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(); @@ -1288,9 +1297,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 ) @@ -1299,19 +1307,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. @@ -1411,7 +1420,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 @@ -1645,6 +1654,8 @@ void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); } +#if wxUSE_DATETIME + time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) { wxDateTime mtime; @@ -1654,6 +1665,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. @@ -1766,6 +1779,152 @@ int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, return filters.GetCount(); } +#if defined( __WINDOWS__ ) +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.c_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(wxConvFile.cWX2MB(path), 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(wxConvFile.cWX2MB(path), 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(wxConvFile.cWX2MB(path), 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__) + return fp ? wxGetFileKind(_fileno(fp)) : wxFILE_KIND_UNKNOWN; +#else + return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN; +#endif +} + //------------------------------------------------------------------------ // wild character routines @@ -1898,77 +2057,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++