]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/filefn.cpp
Added wxFileName::GetModificationTime()
[wxWidgets.git] / src / common / filefn.cpp
index 4adda9147010291762f87cec893b441e47d71a7c..da2ce56b6f787fc418c5afd0af10df56c6a47c3b 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "wx/utils.h"
 #include "wx/intl.h"
+#include "wx/file.h"
+#include "wx/filename.h"
 
 // there are just too many of those...
 #ifdef __VISUALC__
@@ -55,6 +57,7 @@
 #else
     #include <stat.h>
     #include <unistd.h>
+    #include <unix.h>
 #endif
 
 #ifdef __UNIX__
@@ -70,6 +73,7 @@
 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
     #include <direct.h>
     #include <dos.h>
+    #include <io.h>
 #endif // __WINDOWS__
 #endif // native Win compiler
 
 #endif
 
 #ifdef __WINDOWS__
-    #include "windows.h"
+    #include <windows.h>
 #endif
 
 // ----------------------------------------------------------------------------
 
 extern wxChar *wxBuffer;
 
-#ifdef __WXMAC__
-
-#include "morefile.h"
-#include "moreextr.h"
-#include "fullpath.h"
-#include "fspcompa.h"
+#if defined(__WXMAC__) && !defined(__UNIX__)
+    #include "morefile.h"
+    #include "moreextr.h"
+    #include "fullpath.h"
+    #include "fspcompa.h"
 #endif
 
-    IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
+IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
 
 // ----------------------------------------------------------------------------
 // private globals
@@ -134,6 +137,17 @@ static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN];
 const off_t wxInvalidOffset = (off_t)-1;
 #endif
 
+// ----------------------------------------------------------------------------
+// macros
+// ----------------------------------------------------------------------------
+
+// we need to translate Mac filenames before passing them to OS functions
+#ifdef __MAC__
+    #define OS_FILENAME(s) (wxUnix2MacFilename(s))
+#else
+    #define OS_FILENAME(s) (s.fn_str())
+#endif
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -262,37 +276,16 @@ bool
 wxFileExists (const wxString& filename)
 {
 #ifdef __GNUWIN32__ // (fix a B20 bug)
-  if (GetFileAttributes(filename) == 0xFFFFFFFF)
-    return FALSE;
-  else
-    return TRUE;
-#elif defined(__WXMAC__)
-          struct stat stbuf;
-        if (filename && stat (wxUnix2MacFilename(filename), &stbuf) == 0 )
-          return TRUE;
-    return FALSE ;
+    return GetFileAttributes(filename) != 0xFFFFFFFF;
 #else
+    wxStructStat stbuf;
+    if ( !filename.empty() && wxStat (OS_FILENAME(filename), &stbuf) == 0 )
+        return TRUE;
 
-  wxStructStat stbuf;
-  if ((filename != wxT("")) && wxStat (wxFNSTRINGCAST filename.fn_str(), &stbuf) == 0)
-    return TRUE;
-
-  return FALSE;
+    return FALSE;
 #endif
 }
 
-/* Vadim's alternative implementation
-
-// does the file exist?
-bool wxFileExists(const char *pszFileName)
-{
-  struct stat st;
-  return !access(pszFileName, 0) &&
-         !stat(pszFileName, &st) &&
-         (st.st_mode & S_IFREG);
-}
-*/
-
 bool
 wxIsAbsolutePath (const wxString& filename)
 {
@@ -745,10 +738,10 @@ wxPathOnly (wxChar *path)
         {
           done = TRUE;
 #ifdef __VMS__
-          if ( path[i] == wxT(']') )
-            buf[i+1] = 0;
-          else
-#endif      
+           if ( path[i] == wxT(']') )
+             buf[i+1] = 0;
+           else
+#endif
           buf[i] = 0;
 
           return buf;
@@ -794,10 +787,10 @@ wxString wxPathOnly (const wxString& path)
         {
           done = TRUE;
 #ifdef __VMS__
-          if ( path[i] == wxT(']') )
-            buf[i+1] = 0;
-          else
-#endif      
+           if ( path[i] == wxT(']') )
+             buf[i+1] = 0;
+           else
+#endif
           buf[i] = 0;
 
           return wxString(buf);
@@ -824,7 +817,7 @@ wxString wxPathOnly (const wxString& path)
 // and back again - or we get nasty problems with delimiters.
 // Also, convert to lower case, since case is significant in UNIX.
 
-#ifdef __WXMAC__
+#if defined(__WXMAC__) && !defined(__UNIX__)
 
 static char sMacFileNameConversion[ 1000 ] ;
 
@@ -966,21 +959,17 @@ wxUnix2DosFilename (wxChar *WXUNUSED(s) )
 bool
 wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
 {
-  wxChar *outfile = wxGetTempFileName("cat");
+  wxString outfile;
+  if ( !wxGetTempFileName("cat", outfile) )
+      return FALSE;
 
   FILE *fp1 = (FILE *) NULL;
   FILE *fp2 = (FILE *) NULL;
   FILE *fp3 = (FILE *) NULL;
   // Open the inputs and outputs
-#ifdef __WXMAC__
-  if ((fp1 = fopen (wxUnix2MacFilename( file1 ), "rb")) == NULL ||
-      (fp2 = fopen (wxUnix2MacFilename( file2 ), "rb")) == NULL ||
-      (fp3 = fopen (wxUnix2MacFilename( outfile ), "wb")) == NULL)
-#else
-  if ((fp1 = wxFopen (WXSTRINGCAST file1, wxT("rb"))) == NULL ||
-      (fp2 = wxFopen (WXSTRINGCAST file2, wxT("rb"))) == NULL ||
-      (fp3 = wxFopen (outfile, wxT("wb"))) == NULL)
-#endif
+  if ((fp1 = fopen (OS_FILENAME( file1 ), "rb")) == NULL ||
+      (fp2 = fopen (OS_FILENAME( file2 ), "rb")) == NULL ||
+      (fp3 = fopen (OS_FILENAME( outfile ), "wb")) == NULL)
     {
       if (fp1)
         fclose (fp1);
@@ -1002,51 +991,101 @@ wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& fil
 
   fclose (fp3);
   bool result = wxRenameFile(outfile, file3);
-  delete[] outfile;
   return result;
 }
 
 // Copy files
 bool
-wxCopyFile (const wxString& file1, const wxString& file2)
+wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
 {
-  FILE *fd1;
-  FILE *fd2;
-  int ch;
+#if defined(__WIN32__)
+    // CopyFile() copies file attributes and modification time too, so use it
+    // instead of our code if available
+    //
+    // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite
+    return ::CopyFile(file1, file2, !overwrite);
+#else // !Win32
+    wxStructStat fbuf;
 
-#ifdef __WXMAC__
-  if ((fd1 = fopen (wxUnix2MacFilename( file1 ), "rb")) == NULL)
-    return FALSE;
-  if ((fd2 = fopen (wxUnix2MacFilename( file2 ), "wb")) == NULL)
-#else
-  if ((fd1 = wxFopen (WXSTRINGCAST file1, wxT("rb"))) == NULL)
-    return FALSE;
-  if ((fd2 = wxFopen (WXSTRINGCAST file2, wxT("wb"))) == NULL)
-#endif
+    // get permissions of file1
+    if ( wxStat(OS_FILENAME(file1), &fbuf) != 0 )
     {
-      fclose (fd1);
-      return FALSE;
+        // the file probably doesn't exist or we haven't the rights to read
+        // from it anyhow
+        wxLogSysError(_("Impossible to get permissions for file '%s'"),
+                      file1.c_str());
+        return FALSE;
     }
 
-  while ((ch = getc (fd1)) != EOF)
-    (void) putc (ch, fd2);
+    // open file1 for reading
+    wxFile fileIn(file1, wxFile::read);
+    if ( !fileIn.IsOpened() )
+        return FALSE;
 
-  fclose (fd1);
-  fclose (fd2);
-  return TRUE;
+    // remove file2, if it exists. This is needed for creating
+    // file2 with the correct permissions in the next step
+    if ( wxFileExists(file2)  && (!overwrite || !wxRemoveFile(file2)))
+    {
+        wxLogSysError(_("Impossible to overwrite the file '%s'"),
+                      file2.c_str());
+        return FALSE;
+    }
+
+#ifdef __UNIX__
+    // reset the umask as we want to create the file with exactly the same
+    // permissions as the original one
+    mode_t oldUmask = umask( 0 );
+#endif // __UNIX__
+
+    // create file2 with the same permissions than file1 and open it for
+    // writing
+    wxFile fileOut;
+    if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) )
+        return FALSE;
+
+#ifdef __UNIX__
+    /// restore the old umask
+    umask(oldUmask);
+#endif // __UNIX__
+
+    // copy contents of file1 to file2
+    char buf[4096];
+    size_t count;
+    for ( ;; )
+    {
+        count = fileIn.Read(buf, WXSIZEOF(buf));
+        if ( fileIn.Error() )
+            return FALSE;
+
+        // end of file?
+        if ( !count )
+            break;
+
+        if ( fileOut.Write(buf, count) < count )
+            return FALSE;
+    }
+
+#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
+    // no chmod in VA.  SHould be some permission API for HPFS386 partitions however
+    if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 )
+    {
+        wxLogSysError(_("Impossible to set permissions for the file '%s'"),
+                      file2.c_str());
+        return FALSE;
+    }
+#endif // OS/2 || Mac
+
+    return TRUE;
+#endif // __WXMSW__ && __WIN32__
 }
 
 bool
 wxRenameFile (const wxString& file1, const wxString& file2)
 {
-#ifdef __WXMAC__
-  if (0 == rename (wxUnix2MacFilename( file1 ), wxUnix2MacFilename( file2 )))
-    return TRUE;
-#else
   // Normal system call
-  if (0 == wxRename (wxCSTRINGCAST file1, wxCSTRINGCAST file2))
+  if ( wxRename (file1, file2) == 0 )
     return TRUE;
-#endif
+
   // Try to copy
   if (wxCopyFile(file1, file2)) {
     wxRemoveFile(file1);
@@ -1059,18 +1098,17 @@ wxRenameFile (const wxString& file1, const wxString& file2)
 bool wxRemoveFile(const wxString& file)
 {
 #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__WATCOMC__)
-  int flag = wxRemove(file);
-#elif defined( __WXMAC__ )
-  int flag = unlink(wxUnix2MacFilename( file ));
+  int res = wxRemove(file);
 #else
-  int flag = unlink(wxFNSTRINGCAST file.fn_str());
+  int res = unlink(OS_FILENAME(file));
 #endif
-  return (flag == 0) ;
+
+  return res == 0;
 }
 
 bool wxMkdir(const wxString& dir, int perm)
 {
-#if defined( __WXMAC__ )
+#if defined(__WXMAC__) && !defined(__UNIX__)
   return (mkdir(wxUnix2MacFilename( dir ) , 0 ) == 0);
 #else // !Mac
     const wxChar *dirname = dir.c_str();
@@ -1098,8 +1136,6 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
 {
 #ifdef __VMS__
   return FALSE; //to be changed since rmdir exists in VMS7.x
-#elif defined( __WXMAC__ )
-  return (rmdir(wxUnix2MacFilename( dir )) == 0);
 #elif defined(__WXPM__)
   return (::DosDeleteDir((PSZ)dir.c_str()) == 0);
 #else
@@ -1107,58 +1143,12 @@ bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
 #ifdef __SALFORDC__
   return FALSE; // What to do?
 #else
-  return (wxRmDir(wxFNSTRINGCAST dir.fn_str()) == 0);
-#endif
-
-#endif
-}
-
-#if 0
-bool wxDirExists(const wxString& dir)
-{
-#ifdef __VMS__
-  return FALSE; //To be changed since stat exists in VMS7.x
-#elif !defined(__WXMSW__)
-  struct stat sbuf;
-  return (stat(dir.fn_str(), &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE;
-#else
-
-  /* MATTHEW: [6] Always use same code for Win32, call FindClose */
-#if defined(__WIN32__)
-  WIN32_FIND_DATA fileInfo;
-#else
-#ifdef __BORLANDC__
-  struct ffblk fileInfo;
-#else
-  struct find_t fileInfo;
-#endif
-#endif
-
-#if defined(__WIN32__)
-        HANDLE h = FindFirstFile((LPTSTR) WXSTRINGCAST dir,(LPWIN32_FIND_DATA)&fileInfo);
-
-        if (h==INVALID_HANDLE_VALUE)
-         return FALSE;
-        else {
-         FindClose(h);
-         return ((fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
-        }
-#else
-  // In Borland findfirst has a different argument
-  // ordering from _dos_findfirst. But _dos_findfirst
-  // _should_ be ok in both MS and Borland... why not?
-#ifdef __BORLANDC__
-  return ((findfirst(WXSTRINGCAST dir, &fileInfo, _A_SUBDIR) == 0  && (fileInfo.ff_attrib & _A_SUBDIR) != 0));
-#else
-  return (((_dos_findfirst(WXSTRINGCAST dir, _A_SUBDIR, &fileInfo) == 0) && (fileInfo.attrib & _A_SUBDIR)) != 0);
-#endif
+  return (wxRmDir(OS_FILENAME(dir)) == 0);
 #endif
 
 #endif
 }
 
-#endif
-
 // does the path exists? (may have or not '/' or '\\' at the end)
 bool wxPathExists(const wxChar *pszPathName)
 {
@@ -1266,7 +1256,7 @@ wxString wxFindFirstFile(const wxChar *spec, int flags)
 #ifdef __VMS
    wxChar *specvms = NULL;
 #endif
-   
+
 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
     if (gs_dirStream)
         closedir(gs_dirStream); // edz 941103: better housekeping
@@ -1283,10 +1273,10 @@ wxString wxFindFirstFile(const wxChar *spec, int flags)
     if ( !path && gs_strFileSpec[0u] == wxT('/') )
 #ifdef __VMS
      {
-       wxStrcpy( specvms , wxT( "[000000]" ) );
-       gs_strFileSpec = specvms;
-       wxString path_vms(wxPathOnly(gs_strFileSpec));
-       path = path_vms;
+        wxStrcpy( specvms , wxT( "[000000]" ) );
+        gs_strFileSpec = specvms;
+        wxString path_vms(wxPathOnly(gs_strFileSpec));
+        path = path_vms;
      }
 #else
      path = wxT('/');
@@ -1295,15 +1285,15 @@ wxString wxFindFirstFile(const wxChar *spec, int flags)
     if ( !path )
 #ifdef __VMS
      {
-       wxStrcpy( specvms , wxT( "[]" ) );
-       gs_strFileSpec = specvms;
-       wxString path_vms1(wxPathOnly(gs_strFileSpec));
-       path = path_vms1;
+        wxStrcpy( specvms , wxT( "[]" ) );
+        gs_strFileSpec = specvms;
+        wxString path_vms1(wxPathOnly(gs_strFileSpec));
+        path = path_vms1;
      }
 #else
      path = wxT('.');
 #endif
-   
+
     gs_dirStream = opendir(path.fn_str());
     if ( !gs_dirStream )
     {
@@ -1683,7 +1673,7 @@ wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
   char *cbuf = new char[sz+1];
 #ifdef _MSC_VER
   if (_getcwd(cbuf, sz) == NULL) {
-#elif defined( __WXMAC__)
+#elif defined(__WXMAC__) && !defined(__UNIX__)
     enum
     {
         SFSaveDisk = 0x214, CurDirStore = 0x398
@@ -1701,17 +1691,41 @@ wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
 #else // wxUnicode
 #ifdef _MSC_VER
   if (_getcwd(buf, sz) == NULL) {
-#elif defined( __WXMAC__)
-    enum
-    {
-        SFSaveDisk = 0x214, CurDirStore = 0x398
-    };
-    FSSpec cwdSpec ;
-
-    FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
-    wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
-    strcpy( buf , res ) ;
-    if (0) {
+#elif defined(__WXMAC__) && !defined(__UNIX__)
+       FSSpec cwdSpec ;
+       FCBPBRec pb;
+       OSErr error;
+       Str255  fileName ;
+       pb.ioNamePtr = (StringPtr) &fileName;
+       pb.ioVRefNum = 0;
+       pb.ioRefNum = LMGetCurApRefNum();
+       pb.ioFCBIndx = 0;
+       error = PBGetFCBInfoSync(&pb);
+       if ( error == noErr ) 
+       {
+               cwdSpec.vRefNum = pb.ioFCBVRefNum;
+               cwdSpec.parID = pb.ioFCBParID;
+               cwdSpec.name[0] = 0 ;
+               wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
+               
+               strcpy( buf , res ) ;
+               buf[res.length()-1]=0 ;
+       }
+       else
+               buf[0] = 0 ;
+       /*
+       this version will not always give back the application directory on mac
+       enum 
+       { 
+               SFSaveDisk = 0x214, CurDirStore = 0x398 
+       };
+       FSSpec cwdSpec ;
+       
+       FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
+       wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
+       strcpy( buf , res ) ;
+       */
+       if (0) {
 #elif(__VISAGECPP__)
     APIRET rc;
     rc = ::DosQueryCurrentDir( 0 // current drive
@@ -1855,56 +1869,7 @@ void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName,
     // it can be empty, but it shouldn't be NULL
     wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") );
 
-    const wxChar *pDot = wxStrrchr(pszFileName, wxFILE_SEP_EXT);
-
-#ifdef __WXMSW__
-    // under Windows we understand both separators
-    const wxChar *pSepUnix = wxStrrchr(pszFileName, wxFILE_SEP_PATH_UNIX);
-    const wxChar *pSepDos = wxStrrchr(pszFileName, wxFILE_SEP_PATH_DOS);
-    const wxChar *pLastSeparator = pSepUnix > pSepDos ? pSepUnix : pSepDos;
-#else // assume Unix
-    const wxChar *pLastSeparator = wxStrrchr(pszFileName, wxFILE_SEP_PATH_UNIX);
-
-    if ( pDot )
-    {
-        if ( (pDot == pszFileName) || (*(pDot - 1) == wxFILE_SEP_PATH_UNIX) )
-        {
-            // under Unix, dot may be (and commonly is) the first character of the
-            // filename, don't treat the entire filename as extension in this case
-            pDot = NULL;
-        }
-    }
-#endif // MSW/Unix
-
-    if ( pDot && (pDot < pLastSeparator) )
-    {
-        // the dot is part of the path, not the start of the extension
-        pDot = NULL;
-    }
-
-    if ( pstrPath )
-    {
-        if ( pLastSeparator )
-            *pstrPath = wxString(pszFileName, pLastSeparator - pszFileName);
-        else
-            pstrPath->Empty();
-    }
-
-    if ( pstrName )
-    {
-        const wxChar *start = pLastSeparator ? pLastSeparator + 1 : pszFileName;
-        const wxChar *end = pDot ? pDot : pszFileName + wxStrlen(pszFileName);
-
-        *pstrName = wxString(start, end - start);
-    }
-
-    if ( pstrExt )
-    {
-        if ( pDot )
-            *pstrExt = wxString(pDot + 1);
-        else
-            pstrExt->Empty();
-    }
+    wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt);
 }
 
 time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)