1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     File- and directory-related functions 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) 1998 Julian Smart 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "filefn.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  35 #include "wx/filename.h" 
  38 // there are just too many of those... 
  40     #pragma warning(disable:4706)   // assignment within conditional expression 
  47 #if !defined(__WATCOMC__) 
  48     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  56     #include <sys/types.h> 
  71     #include "wx/os2/private.h" 
  73 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
  74 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__) 
  79 #endif // native Win compiler 
  95         #include <sys/unistd.h> 
  99 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
 100                     // this (3.1 I believe) and how to test for it. 
 101                     // If this works for Borland 4.0 as well, then no worries. 
 110 #include "wx/setup.h" 
 113 // No, Cygwin doesn't appear to have fnmatch.h after all. 
 114 #if defined(HAVE_FNMATCH_H) 
 122 // ---------------------------------------------------------------------------- 
 124 // ---------------------------------------------------------------------------- 
 126 #define _MAXPATHLEN 500 
 128 extern wxChar 
*wxBuffer
; 
 131 #    include "MoreFiles.h" 
 132 #    include "MoreFilesExtras.h" 
 133 #    include "FullPath.h" 
 134 #    include "FSpCompat.h" 
 137 IMPLEMENT_DYNAMIC_CLASS(wxPathList
, wxStringList
) 
 139 // ---------------------------------------------------------------------------- 
 141 // ---------------------------------------------------------------------------- 
 143 static wxChar wxFileFunctionsBuffer
[4*_MAXPATHLEN
]; 
 145 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
 147 // VisualAge C++ V4.0 cannot have any external linkage const decs 
 148 // in headers included by more than one primary source 
 150 const off_t wxInvalidOffset 
= (off_t
)-1; 
 153 // ---------------------------------------------------------------------------- 
 155 // ---------------------------------------------------------------------------- 
 157 // we need to translate Mac filenames before passing them to OS functions 
 158 #define OS_FILENAME(s) (s.fn_str()) 
 160 // ============================================================================ 
 162 // ============================================================================ 
 164 void wxPathList::Add (const wxString
& path
) 
 166     wxStringList::Add (WXSTRINGCAST path
); 
 169 // Add paths e.g. from the PATH environment variable 
 170 void wxPathList::AddEnvList (const wxString
& envVariable
) 
 172   static const wxChar PATH_TOKS
[] = 
 174         wxT(" ;"); // Don't seperate with colon in DOS (used for drive) 
 179   wxChar 
*val 
= wxGetenv (WXSTRINGCAST envVariable
); 
 182       wxChar 
*s 
= copystring (val
); 
 183       wxChar 
*save_ptr
, *token 
= wxStrtok (s
, PATH_TOKS
, &save_ptr
); 
 187           Add (copystring (token
)); 
 190               if ((token 
= wxStrtok ((wxChar 
*) NULL
, PATH_TOKS
, &save_ptr
)) != NULL
) 
 191                   Add (wxString(token
)); 
 195       // suppress warning about unused variable save_ptr when wxStrtok() is a 
 196       // macro which throws away its third argument 
 203 // Given a full filename (with path), ensure that that file can 
 204 // be accessed again USING FILENAME ONLY by adding the path 
 205 // to the list if not already there. 
 206 void wxPathList::EnsureFileAccessible (const wxString
& path
) 
 208     wxString 
path_only(wxPathOnly(path
)); 
 209     if ( !path_only
.IsEmpty() ) 
 211         if ( !Member(path_only
) ) 
 216 bool wxPathList::Member (const wxString
& path
) 
 218   for (wxNode 
* node 
= First (); node 
!= NULL
; node 
= node
->Next ()) 
 220       wxString 
path2((wxChar 
*) node
->Data ()); 
 222 #if defined(__WINDOWS__) || defined(__VMS__) || defined (__WXMAC__) 
 224           path
.CompareTo (path2
, wxString::ignoreCase
) == 0 
 226       // Case sensitive File System 
 227           path
.CompareTo (path2
) == 0 
 235 wxString 
wxPathList::FindValidPath (const wxString
& file
) 
 237   if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer
, file
))) 
 238     return wxString(wxFileFunctionsBuffer
); 
 240   wxChar buf
[_MAXPATHLEN
]; 
 241   wxStrcpy(buf
, wxFileFunctionsBuffer
); 
 243   wxChar 
*filename 
= (wxChar
*) NULL
; /* shut up buggy egcs warning */ 
 244   filename 
= IsAbsolutePath (buf
) ? wxFileNameFromPath (buf
) : (wxChar 
*)buf
; 
 246   for (wxNode 
* node 
= First (); node
; node 
= node
->Next ()) 
 248       wxChar 
*path 
= (wxChar 
*) node
->Data (); 
 249       wxStrcpy (wxFileFunctionsBuffer
, path
); 
 250       wxChar ch 
= wxFileFunctionsBuffer
[wxStrlen(wxFileFunctionsBuffer
)-1]; 
 251       if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 252         wxStrcat (wxFileFunctionsBuffer
, wxT("/")); 
 253       wxStrcat (wxFileFunctionsBuffer
, filename
); 
 255       Unix2DosFilename (wxFileFunctionsBuffer
); 
 257       if (wxFileExists (wxFileFunctionsBuffer
)) 
 259         return wxString(wxFileFunctionsBuffer
);        // Found! 
 263   return wxString(wxT(""));                    // Not found 
 266 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) 
 268     wxString f 
= FindValidPath(file
); 
 269     if ( wxIsAbsolutePath(f
) ) 
 273     wxGetWorkingDirectory(buf
.GetWriteBuf(_MAXPATHLEN
), _MAXPATHLEN 
- 1); 
 275     if ( !wxEndsWithPathSeparator(buf
) ) 
 277         buf 
+= wxFILE_SEP_PATH
; 
 285 wxFileExists (const wxString
& filename
) 
 287 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 288     // GetFileAttributes can copy with network paths 
 289     DWORD ret 
= GetFileAttributes(filename
); 
 290     DWORD isDir 
= (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 291     return ((ret 
!= 0xffffffff) && (isDir 
== 0)); 
 294     if ( !filename
.empty() && wxStat (OS_FILENAME(filename
), &stbuf
) == 0 ) 
 302 wxIsAbsolutePath (const wxString
& filename
) 
 304     if (filename 
!= wxT("")) 
 306 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 307         // Classic or Carbon CodeWarrior like 
 308         // Carbon with Apple DevTools is Unix like 
 310         // This seems wrong to me, but there is no fix. since 
 311         // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt" 
 312         // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR. 
 313         if (filename
.Find(':') != wxNOT_FOUND 
&& filename
[0] != ':') 
 316         // Unix like or Windows 
 317         if (filename
[0] == wxT('/')) 
 321         if ((filename
[0] == wxT('[') && filename
[1] != wxT('.'))) 
 326         if (filename
[0] == wxT('\\') || (wxIsalpha (filename
[0]) && filename
[1] == wxT(':'))) 
 334  * Strip off any extension (dot something) from end of file, 
 335  * IF one exists. Inserts zero into buffer. 
 339 void wxStripExtension(wxChar 
*buffer
) 
 341   int len 
= wxStrlen(buffer
); 
 345     if (buffer
[i
] == wxT('.')) 
 354 void wxStripExtension(wxString
& buffer
) 
 356   size_t len 
= buffer
.Length(); 
 360     if (buffer
.GetChar(i
) == wxT('.')) 
 362       buffer 
= buffer
.Left(i
); 
 369 // Destructive removal of /./ and /../ stuff 
 370 wxChar 
*wxRealPath (wxChar 
*path
) 
 373   static const wxChar SEP 
= wxT('\\'); 
 374   Unix2DosFilename(path
); 
 376   static const wxChar SEP 
= wxT('/'); 
 378   if (path
[0] && path
[1]) { 
 379     /* MATTHEW: special case "/./x" */ 
 381     if (path
[2] == SEP 
&& path
[1] == wxT('.')) 
 389             if (p
[1] == wxT('.') && p
[2] == wxT('.') && (p
[3] == SEP 
|| p
[3] == wxT('\0'))) 
 392                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--); 
 393                 if (q
[0] == SEP 
&& (q
[1] != wxT('.') || q
[2] != wxT('.') || q
[3] != SEP
) 
 394                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 397                     if (path
[0] == wxT('\0')) 
 403                     /* Check that path[2] is NULL! */ 
 404                     else if (path
[1] == wxT(':') && !path
[2]) 
 413             else if (p
[1] == wxT('.') && (p
[2] == SEP 
|| p
[2] == wxT('\0'))) 
 422 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 424   if (filename 
== wxT("")) 
 425     return (wxChar 
*) NULL
; 
 427   if (! IsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer
, filename
))) { 
 428     wxChar  buf
[_MAXPATHLEN
]; 
 430     wxGetWorkingDirectory(buf
, WXSIZEOF(buf
)); 
 431     wxChar ch 
= buf
[wxStrlen(buf
) - 1]; 
 433     if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 434         wxStrcat(buf
, wxT("\\")); 
 437         wxStrcat(buf
, wxT("/")); 
 439     wxStrcat(buf
, wxFileFunctionsBuffer
); 
 440     return copystring( wxRealPath(buf
) ); 
 442   return copystring( wxFileFunctionsBuffer 
); 
 448    ~user/ => user's home dir 
 449    If the environment variable a = "foo" and b = "bar" then: 
 466 /* input name in name, pathname output to buf. */ 
 468 wxChar 
*wxExpandPath(wxChar 
*buf
, const wxChar 
*name
) 
 470     register wxChar 
*d
, *s
, *nm
; 
 471     wxChar          lnm
[_MAXPATHLEN
]; 
 474     // Some compilers don't like this line. 
 475 //    const wxChar    trimchars[] = wxT("\n \t"); 
 478     trimchars
[0] = wxT('\n'); 
 479     trimchars
[1] = wxT(' '); 
 480     trimchars
[2] = wxT('\t'); 
 484      const wxChar     SEP 
= wxT('\\'); 
 486      const wxChar     SEP 
= wxT('/'); 
 489     if (name 
== NULL 
|| *name 
== wxT('\0')) 
 491     nm 
= copystring(name
); // Make a scratch copy 
 494     /* Skip leading whitespace and cr */ 
 495     while (wxStrchr((wxChar 
*)trimchars
, *nm
) != NULL
) 
 497     /* And strip off trailing whitespace and cr */ 
 498     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 499     while (q
-- && wxStrchr((wxChar 
*)trimchars
, *s
) != NULL
) 
 507     q 
= nm
[0] == wxT('\\') && nm
[1] == wxT('~'); 
 510     /* Expand inline environment variables */ 
 528     while ((*d
++ = *s
) != 0) { 
 530         if (*s 
== wxT('\\')) { 
 531             if ((*(d 
- 1) = *++s
)) { 
 540         if (*s
++ == wxT('$') && (*s 
== wxT('{') || *s 
== wxT(')'))) 
 542         if (*s
++ == wxT('$')) 
 545             register wxChar  
*start 
= d
; 
 546             register int     braces 
= (*s 
== wxT('{') || *s 
== wxT('(')); 
 547             register wxChar  
*value
; 
 548             while ((*d
++ = *s
) != 0) 
 549                 if (braces 
? (*s 
== wxT('}') || *s 
== wxT(')')) : !(wxIsalnum(*s
) || *s 
== wxT('_')) ) 
 554             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 556                 for ((d 
= start 
- 1); (*d
++ = *value
++) != 0;); 
 564     /* Expand ~ and ~user */ 
 567     if (nm
[0] == wxT('~') && !q
) 
 570         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 572         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 573             if ((s 
= WXSTRINGCAST 
wxGetUserHome(wxT(""))) != NULL
) { 
 578         {                /* ~user/filename */ 
 579             register wxChar  
*nnm
; 
 580             register wxChar  
*home
; 
 581             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++); 
 582             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 583             was_sep 
= (*s 
== SEP
); 
 584             nnm 
= *s 
? s 
+ 1 : s
; 
 586         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 587             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 588                if (was_sep
) /* replace only if it was there: */ 
 599     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 601         while (wxT('\0') != (*d
++ = *s
++)) 
 604         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 608     while ((*d
++ = *s
++) != 0); 
 609     delete[] nm_tmp
; // clean up alloc 
 610     /* Now clean up the buffer */ 
 611     return wxRealPath(buf
); 
 614 /* Contract Paths to be build upon an environment variable 
 617    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 619    The call wxExpandPath can convert these back! 
 622 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 624   static wxChar dest
[_MAXPATHLEN
]; 
 626   if (filename 
== wxT("")) 
 627     return (wxChar 
*) NULL
; 
 629   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 631   Unix2DosFilename(dest
); 
 634   // Handle environment 
 635   const wxChar 
*val 
= (const wxChar 
*) NULL
; 
 636   wxChar 
*tcp 
= (wxChar 
*) NULL
; 
 637   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 638      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 640         wxStrcpy (wxFileFunctionsBuffer
, tcp 
+ wxStrlen (val
)); 
 643         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 644         wxStrcat (tcp
, wxT("}")); 
 645         wxStrcat (tcp
, wxFileFunctionsBuffer
); 
 648   // Handle User's home (ignore root homes!) 
 650   if ((val 
= wxGetUserHome (user
)) != NULL 
&& 
 651       (len 
= wxStrlen(val
)) > 2 && 
 652       wxStrncmp(dest
, val
, len
) == 0) 
 654       wxStrcpy(wxFileFunctionsBuffer
, wxT("~")); 
 656              wxStrcat(wxFileFunctionsBuffer
, (const wxChar
*) user
); 
 658 //      strcat(wxFileFunctionsBuffer, "\\"); 
 660 //      strcat(wxFileFunctionsBuffer, "/"); 
 662       wxStrcat(wxFileFunctionsBuffer
, dest 
+ len
); 
 663       wxStrcpy (dest
, wxFileFunctionsBuffer
); 
 669 // Return just the filename, not the path 
 671 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 675         register wxChar 
*tcp
; 
 677         tcp 
= path 
+ wxStrlen (path
); 
 678         while (--tcp 
>= path
) 
 680 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 681             // Classic or Carbon CodeWarrior like 
 682             // Carbon with Apple DevTools is Unix like 
 683             if (*tcp 
== wxT(':')) 
 686             // Unix like or Windows 
 687             if (*tcp 
== wxT('/') || *tcp 
== wxT('\\')) 
 691             if (*tcp 
== wxT(':') || *tcp 
== wxT(']')) 
 695 #if defined(__WXMSW__) || defined(__WXPM__) 
 697         if (wxIsalpha (*path
) && *(path 
+ 1) == wxT(':')) 
 704 wxString 
wxFileNameFromPath (const wxString
& path1
) 
 706     if (path1 
!= wxT("")) 
 708         wxChar 
*path 
= WXSTRINGCAST path1 
; 
 709         register wxChar 
*tcp
; 
 711         tcp 
= path 
+ wxStrlen (path
); 
 712         while (--tcp 
>= path
) 
 714 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 715             // Classic or Carbon CodeWarrior like 
 716             // Carbon with Apple DevTools is Unix like 
 717             if (*tcp 
== wxT(':') ) 
 718                 return wxString(tcp 
+ 1); 
 720             // Unix like or Windows 
 721             if (*tcp 
== wxT('/') || *tcp 
== wxT('\\')) 
 722                 return wxString(tcp 
+ 1); 
 725             if (*tcp 
== wxT(':') || *tcp 
== wxT(']')) 
 726                 return wxString(tcp 
+ 1); 
 729 #if defined(__WXMSW__) || defined(__WXPM__) 
 731         if (wxIsalpha (*path
) && *(path 
+ 1) == wxT(':')) 
 732             return wxString(path 
+ 2); 
 735     // Yes, this should return the path, not an empty string, otherwise 
 736     // we get "thing.txt" -> "". 
 740 // Return just the directory, or NULL if no directory 
 742 wxPathOnly (wxChar 
*path
) 
 746         static wxChar buf
[_MAXPATHLEN
]; 
 749         wxStrcpy (buf
, path
); 
 751         int l 
= wxStrlen(path
); 
 754         // Search backward for a backward or forward slash 
 757 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 758             // Classic or Carbon CodeWarrior like 
 759             // Carbon with Apple DevTools is Unix like 
 760             if (path
[i
] == wxT(':') ) 
 766             // Unix like or Windows 
 767             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 774             if (path
[i
] == wxT(']')) 
 783 #if defined(__WXMSW__) || defined(__WXPM__) 
 784         // Try Drive specifier 
 785         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 787             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 794     return (wxChar 
*) NULL
; 
 797 // Return just the directory, or NULL if no directory 
 798 wxString 
wxPathOnly (const wxString
& path
) 
 802         wxChar buf
[_MAXPATHLEN
]; 
 805         wxStrcpy (buf
, WXSTRINGCAST path
); 
 807         int l 
= path
.Length(); 
 810         // Search backward for a backward or forward slash 
 813 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 814             // Classic or Carbon CodeWarrior like 
 815             // Carbon with Apple DevTools is Unix like 
 816             if (path
[i
] == wxT(':') ) 
 819                 return wxString(buf
); 
 822             // Unix like or Windows 
 823             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 826                 return wxString(buf
); 
 830             if (path
[i
] == wxT(']')) 
 833                 return wxString(buf
); 
 839 #if defined(__WXMSW__) || defined(__WXPM__) 
 840         // Try Drive specifier 
 841         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 843             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 846             return wxString(buf
); 
 850     return wxString(wxT("")); 
 853 // Utility for converting delimiters in DOS filenames to UNIX style 
 854 // and back again - or we get nasty problems with delimiters. 
 855 // Also, convert to lower case, since case is significant in UNIX. 
 857 #if defined(__WXMAC__) 
 858 wxString 
wxMacFSSpec2MacFilename( const FSSpec 
*spec 
) 
 862     char  thePath
[FILENAME_MAX
]; 
 864     // convert the FSSpec to an FSRef 
 865     (void) FSpMakeFSRef( spec
, &theRef 
); 
 866     // get the POSIX path associated with the FSRef 
 867     (void) FSRefMakePath( &theRef
, (UInt8 
*)thePath
, sizeof(thePath
) ); 
 869     // create path string for return value 
 870     wxString 
result( thePath 
) ; 
 875     // get length of path and allocate handle 
 876     FSpGetFullPath( spec 
, &length 
, &myPath 
) ; 
 877     ::SetHandleSize( myPath 
, length 
+ 1 ) ; 
 879     (*myPath
)[length
] = 0 ; 
 880     if ((length 
> 0) && ((*myPath
)[length
-1] == ':')) 
 881         (*myPath
)[length
-1] = 0 ; 
 883     // create path string for return value 
 884     wxString 
result( (char*) *myPath 
) ; 
 886     // free allocated handle 
 887     ::HUnlock( myPath 
) ; 
 888     ::DisposeHandle( myPath 
) ; 
 894 void wxMacFilename2FSSpec( const char *path 
, FSSpec 
*spec 
) 
 899     // get the FSRef associated with the POSIX path 
 900     (void) FSPathMakeRef((const UInt8 
*) path
, &theRef
, NULL
); 
 901     // convert the FSRef to an FSSpec 
 902     (void) FSGetCatalogInfo(&theRef
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 904     FSpLocationFromFullPath( strlen(path
) , path 
, spec 
) ; 
 909 // Mac file names are POSIX (Unix style) under Darwin 
 910 // therefore the conversion functions below are not needed 
 912 static char sMacFileNameConversion
[ 1000 ] ; 
 914 wxString 
wxMac2UnixFilename (const char *str
) 
 916     char *s 
= sMacFileNameConversion 
; 
 920         memmove( s
+1 , s 
,strlen( s 
) + 1) ; 
 931                 *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 935     return wxString(sMacFileNameConversion
) ; 
 938 wxString 
wxUnix2MacFilename (const char *str
) 
 940     char *s 
= sMacFileNameConversion 
; 
 946             // relative path , since it goes on with slash which is translated to a : 
 947             memmove( s 
, s
+1 ,strlen( s 
) ) ; 
 949         else if ( *s 
== '/' ) 
 951             // absolute path -> on mac just start with the drive name 
 952             memmove( s 
, s
+1 ,strlen( s 
) ) ; 
 956             wxASSERT_MSG( 1 , "unkown path beginning" ) ; 
 960             if (*s 
== '/' || *s 
== '\\') 
 962                 // convert any back-directory situations 
 963                 if ( *(s
+1) == '.' && *(s
+2) == '.' && ( (*(s
+3) == '/' || *(s
+3) == '\\') ) ) 
 966                     memmove( s
+1 , s
+3 ,strlen( s
+3 ) + 1 ) ; 
 974     return wxString (sMacFileNameConversion
) ; 
 977 wxString 
wxMacFSSpec2UnixFilename( const FSSpec 
*spec 
) 
 979     return wxMac2UnixFilename( wxMacFSSpec2MacFilename( spec
) ) ; 
 982 void wxUnixFilename2FSSpec( const char *path 
, FSSpec 
*spec 
) 
 984     wxString var 
= wxUnix2MacFilename( path 
) ; 
 985     wxMacFilename2FSSpec( var 
, spec 
) ; 
 987 #endif // ! __DARWIN__ 
 992 wxDos2UnixFilename (char *s
) 
1001           *s 
= wxTolower (*s
);        // Case INDEPENDENT 
1008 #if defined(__WXMSW__) || defined(__WXPM__) 
1009 wxUnix2DosFilename (wxChar 
*s
) 
1011 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
) ) 
1014 // Yes, I really mean this to happen under DOS only! JACS 
1015 #if defined(__WXMSW__) || defined(__WXPM__) 
1026 // Concatenate two files to form third 
1028 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
1031   if ( !wxGetTempFileName("cat", outfile
) ) 
1034   FILE *fp1 
= (FILE *) NULL
; 
1035   FILE *fp2 
= (FILE *) NULL
; 
1036   FILE *fp3 
= (FILE *) NULL
; 
1037   // Open the inputs and outputs 
1038   if ((fp1 
= wxFopen (OS_FILENAME( file1 
), wxT("rb"))) == NULL 
|| 
1039       (fp2 
= wxFopen (OS_FILENAME( file2 
), wxT("rb"))) == NULL 
|| 
1040       (fp3 
= wxFopen (OS_FILENAME( outfile 
), wxT("wb"))) == NULL
) 
1052   while ((ch 
= getc (fp1
)) != EOF
) 
1053     (void) putc (ch
, fp3
); 
1056   while ((ch 
= getc (fp2
)) != EOF
) 
1057     (void) putc (ch
, fp3
); 
1061   bool result 
= wxRenameFile(outfile
, file3
); 
1067 wxCopyFile (const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1069 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1070     // CopyFile() copies file attributes and modification time too, so use it 
1071     // instead of our code if available 
1073     // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite 
1074     return ::CopyFile(file1
, file2
, !overwrite
) != 0; 
1075 #elif defined(__WXPM__) 
1076     if (::DosCopy(file2
, file2
, overwrite 
? DCPY_EXISTING 
: 0) == 0) 
1083     // get permissions of file1 
1084     if ( wxStat(OS_FILENAME(file1
), &fbuf
) != 0 ) 
1086         // the file probably doesn't exist or we haven't the rights to read 
1088         wxLogSysError(_("Impossible to get permissions for file '%s'"), 
1093     // open file1 for reading 
1094     wxFile 
fileIn(file1
, wxFile::read
); 
1095     if ( !fileIn
.IsOpened() ) 
1098     // remove file2, if it exists. This is needed for creating 
1099     // file2 with the correct permissions in the next step 
1100     if ( wxFileExists(file2
)  && (!overwrite 
|| !wxRemoveFile(file2
))) 
1102         wxLogSysError(_("Impossible to overwrite the file '%s'"), 
1108     // reset the umask as we want to create the file with exactly the same 
1109     // permissions as the original one 
1110     mode_t oldUmask 
= umask( 0 ); 
1113     // create file2 with the same permissions than file1 and open it for 
1116     if ( !fileOut
.Create(file2
, overwrite
, fbuf
.st_mode 
& 0777) ) 
1120     /// restore the old umask 
1124     // copy contents of file1 to file2 
1129         count 
= fileIn
.Read(buf
, WXSIZEOF(buf
)); 
1130         if ( fileIn
.Error() ) 
1137         if ( fileOut
.Write(buf
, count
) < count 
) 
1141     // we can expect fileIn to be closed successfully, but we should ensure 
1142     // that fileOut was closed as some write errors (disk full) might not be 
1143     // detected before doing this 
1144     if ( !fileIn
.Close() || !fileOut
.Close() ) 
1147 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 
1148     // no chmod in VA.  Should be some permission API for HPFS386 partitions 
1150     if ( chmod(OS_FILENAME(file2
), fbuf
.st_mode
) != 0 ) 
1152         wxLogSysError(_("Impossible to set permissions for the file '%s'"), 
1156 #endif // OS/2 || Mac 
1159 #endif // __WXMSW__ && __WIN32__ 
1163 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
1165   // Normal system call 
1166   if ( wxRename (file1
, file2
) == 0 ) 
1170   if (wxCopyFile(file1
, file2
)) { 
1171     wxRemoveFile(file1
); 
1178 bool wxRemoveFile(const wxString
& file
) 
1180 #if defined(__VISUALC__) \ 
1181  || defined(__BORLANDC__) \ 
1182  || defined(__WATCOMC__) \ 
1183  || defined(__GNUWIN32__) 
1184   int res 
= wxRemove(file
); 
1186   int res 
= unlink(OS_FILENAME(file
)); 
1192 bool wxMkdir(const wxString
& dir
, int perm
) 
1194 #if defined(__WXMAC__) && !defined(__UNIX__) 
1195   return (mkdir( dir 
, 0 ) == 0); 
1197     const wxChar 
*dirname 
= dir
.c_str(); 
1199     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 
1200     // for the GNU compiler 
1201 #if (!(defined(__WXMSW__) || defined(__WXPM__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WXWINE__) || defined(__WXMICROWIN__) 
1202     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1203 #elif defined(__WXPM__) 
1204     if (::DosCreateDir((PSZ
)dirname
, NULL
) != 0) // enhance for EAB's?? 
1205 #elif defined(__DOS__) 
1206   #if defined(__WATCOMC__) 
1208     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1209   #elif defined(__DJGPP__) 
1210     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1212     #error "Unsupported DOS compiler!" 
1214 #else  // !MSW, !DOS and !OS/2 VAC++ 
1216     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1219         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1228 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1231   return FALSE
; //to be changed since rmdir exists in VMS7.x 
1232 #elif defined(__WXPM__) 
1233   return (::DosDeleteDir((PSZ
)dir
.c_str()) == 0); 
1237   return FALSE
; // What to do? 
1239   return (wxRmDir(OS_FILENAME(dir
)) == 0); 
1245 // does the path exists? (may have or not '/' or '\\' at the end) 
1246 bool wxPathExists(const wxChar 
*pszPathName
) 
1248     wxString 
strPath(pszPathName
); 
1250     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
1251     // so remove all trailing backslashes from the path - but don't do this for 
1252     // the pathes "d:\" (which are different from "d:") nor for just "\" 
1253     while ( wxEndsWithPathSeparator(strPath
) ) 
1255         size_t len 
= strPath
.length(); 
1256         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == _T(':')) ) 
1259         strPath
.Truncate(len 
- 1); 
1261 #endif // __WINDOWS__ 
1263 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1264     // Stat can't cope with network paths 
1265     DWORD ret 
= GetFileAttributes(strPath
.c_str()); 
1266     DWORD isDir 
= (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
1267     return ((ret 
!= 0xffffffff) && (isDir 
!= 0)); 
1271 #ifndef __VISAGECPP__ 
1272     return wxStat(wxFNSTRINGCAST strPath
.fn_str(), &st
) == 0 && 
1273         ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
1275     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
1276     return wxStat(wxFNSTRINGCAST strPath
.fn_str(), &st
) == 0 && 
1277         (st
.st_mode 
== S_IFDIR
); 
1283 // Get a temporary filename, opening and closing the file. 
1284 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1286     wxString filename 
= wxFileName::CreateTempFileName(prefix
); 
1287     if ( filename
.empty() ) 
1291         wxStrcpy(buf
, filename
); 
1293         buf 
= copystring(filename
); 
1298 bool wxGetTempFileName(const wxString
& prefix
, wxString
& buf
) 
1300     buf 
= wxFileName::CreateTempFileName(prefix
); 
1302     return !buf
.empty(); 
1305 // Get first file name matching given wild card. 
1307 static wxDir 
*gs_dir 
= NULL
; 
1308 static wxString gs_dirPath
; 
1310 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1312     gs_dirPath 
= wxPathOnly(spec
); 
1313     if ( gs_dirPath
.IsEmpty() ) 
1314         gs_dirPath 
= wxT("."); 
1315     if ( gs_dirPath
.Last() != wxFILE_SEP_PATH 
) 
1316         gs_dirPath 
<< wxFILE_SEP_PATH
; 
1320     gs_dir 
= new wxDir(gs_dirPath
); 
1322     if ( !gs_dir
->IsOpened() ) 
1324         wxLogSysError(_("Can not enumerate files '%s'"), spec
); 
1325         return wxEmptyString
; 
1331         case wxDIR
:  dirFlags 
= wxDIR_DIRS
; break; 
1332         case wxFILE
: dirFlags 
= wxDIR_FILES
; break; 
1333         default:     dirFlags 
= wxDIR_DIRS 
| wxDIR_FILES
; break; 
1337     gs_dir
->GetFirst(&result
, wxFileNameFromPath(spec
), dirFlags
); 
1338     if ( result
.IsEmpty() ) 
1344     return gs_dirPath 
+ result
; 
1347 wxString 
wxFindNextFile() 
1349     wxASSERT_MSG( gs_dir
, wxT("You must call wxFindFirstFile before!") ); 
1352     gs_dir
->GetNext(&result
); 
1354     if ( result
.IsEmpty() ) 
1360     return gs_dirPath 
+ result
; 
1364 // Get current working directory. 
1365 // If buf is NULL, allocates space using new, else 
1367 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1370     buf 
= new wxChar
[sz
+1]; 
1372   char *cbuf 
= new char[sz
+1]; 
1374   if (_getcwd(cbuf
, sz
) == NULL
) { 
1375 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1378         SFSaveDisk 
= 0x214, CurDirStore 
= 0x398 
1382     FSMakeFSSpec( - *(short *) SFSaveDisk 
, *(long *) CurDirStore 
, NULL 
, &cwdSpec 
) ; 
1383     wxString res 
= wxMacFSSpec2UnixFilename( &cwdSpec 
) ; 
1384     strcpy( buf 
, res 
) ; 
1387   if (getcwd(cbuf
, sz
) == NULL
) { 
1392   if (_getcwd(buf
, sz
) == NULL
) { 
1393 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1398     pb
.ioNamePtr 
= (StringPtr
) &fileName
; 
1400     pb
.ioRefNum 
= LMGetCurApRefNum(); 
1402     error 
= PBGetFCBInfoSync(&pb
); 
1403     if ( error 
== noErr 
) 
1405         cwdSpec
.vRefNum 
= pb
.ioFCBVRefNum
; 
1406         cwdSpec
.parID 
= pb
.ioFCBParID
; 
1407         cwdSpec
.name
[0] = 0 ; 
1408         wxString res 
= wxMacFSSpec2MacFilename( &cwdSpec 
) ; 
1410         strcpy( buf 
, res 
) ; 
1411         buf
[res
.length()]=0 ; 
1416     this version will not always give back the application directory on mac 
1419         SFSaveDisk = 0x214, CurDirStore = 0x398 
1423     FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ; 
1424     wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ; 
1425     strcpy( buf , res ) ; 
1428 #elif defined(__VISAGECPP__) || (defined (__OS2__) && defined (__WATCOMC__)) 
1430     rc 
= ::DosQueryCurrentDir( 0 // current drive 
1436   if (getcwd(buf
, sz
) == NULL
) { 
1444     wxConvFile
.MB2WC(buf
, cbuf
, sz
); 
1450   // VS: DJGPP is Unicodish and uses / instead of \ as path deliminer. We don't like that. 
1451   for (wxChar 
*ch 
= buf
; *ch
; ch
++) 
1452     if (*ch 
== wxT('/')) *ch 
= wxT('\\'); 
1460     static const size_t maxPathLen 
= 1024; 
1463     wxGetWorkingDirectory(str
.GetWriteBuf(maxPathLen
), maxPathLen
); 
1464     str
.UngetWriteBuf(); 
1469 bool wxSetWorkingDirectory(const wxString
& d
) 
1471 #if defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) 
1472   return (chdir(wxFNSTRINGCAST d
.fn_str()) == 0); 
1473 #elif defined(__WXPM__) 
1474   return (::DosSetCurrentDir((PSZ
)d
.c_str()) == 0); 
1475 #elif defined(__WINDOWS__) 
1478   return (bool)(SetCurrentDirectory(d
) != 0); 
1480   // Must change drive, too. 
1481   bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1484     wxChar firstChar 
= d
[0]; 
1488       firstChar 
= firstChar 
- 32; 
1490     // To a drive number 
1491     unsigned int driveNo 
= firstChar 
- 64; 
1494        unsigned int noDrives
; 
1495        _dos_setdrive(driveNo
, &noDrives
); 
1498   bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1506 // Get the OS directory if appropriate (such as the Windows directory). 
1507 // On non-Windows platform, probably just return the empty string. 
1508 wxString 
wxGetOSDirectory() 
1510 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1512     GetWindowsDirectory(buf
, 256); 
1513     return wxString(buf
); 
1515     return wxEmptyString
; 
1519 bool wxEndsWithPathSeparator(const wxChar 
*pszFileName
) 
1521   size_t len 
= wxStrlen(pszFileName
); 
1525     return wxIsPathSeparator(pszFileName
[len 
- 1]); 
1528 // find a file in a list of directories, returns false if not found 
1529 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1531     // we assume that it's not empty 
1532     wxCHECK_MSG( !wxIsEmpty(pszFile
), FALSE
, 
1533                  _T("empty file name in wxFindFileInPath")); 
1535     // skip path separator in the beginning of the file name if present 
1536     if ( wxIsPathSeparator(*pszFile
) ) 
1539     // copy the path (strtok will modify it) 
1540     wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1541     wxStrcpy(szPath
, pszPath
); 
1544     wxChar 
*pc
, *save_ptr
; 
1545     for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1547           pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1549         // search for the file in this directory 
1551         if ( !wxEndsWithPathSeparator(pc
) ) 
1552             strFile 
+= wxFILE_SEP_PATH
; 
1555         if ( FileExists(strFile
) ) { 
1561     // suppress warning about unused variable save_ptr when wxStrtok() is a 
1562     // macro which throws away its third argument 
1567     return pc 
!= NULL
;  // if true => we breaked from the loop 
1570 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1575     // it can be empty, but it shouldn't be NULL 
1576     wxCHECK_RET( pszFileName
, wxT("NULL file name in wxSplitPath") ); 
1578     wxFileName::SplitPath(pszFileName
, pstrPath
, pstrName
, pstrExt
); 
1581 time_t WXDLLEXPORT 
wxFileModificationTime(const wxString
& filename
) 
1585     wxStat(filename
.fn_str(), &buf
); 
1586     return buf
.st_mtime
; 
1590 //------------------------------------------------------------------------ 
1591 // wild character routines 
1592 //------------------------------------------------------------------------ 
1594 bool wxIsWild( const wxString
& pattern 
) 
1596   wxString tmp 
= pattern
; 
1597   wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
1600         case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): 
1610 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1612 #if defined(HAVE_FNMATCH_H) 
1614 // this probably won't work well for multibyte chars in Unicode mode? 
1616       return fnmatch(pat
.fn_str(), text
.fn_str(), FNM_PERIOD
) == 0; 
1618       return fnmatch(pat
.fn_str(), text
.fn_str(), 0) == 0; 
1622 // #pragma error Broken implementation of wxMatchWild() -- needs fixing! 
1625     * WARNING: this code is broken! 
1628   wxString tmp1 
= pat
; 
1629   wxChar 
*pattern 
= WXSTRINGCAST(tmp1
); 
1630   wxString tmp2 
= text
; 
1631   wxChar 
*str 
= WXSTRINGCAST(tmp2
); 
1634     bool done 
= FALSE
, ret_code
, ok
; 
1635     // Below is for vi fans 
1636     const wxChar OB 
= wxT('{'), CB 
= wxT('}'); 
1638     // dot_special means '.' only matches '.' 
1639     if (dot_special 
&& *str 
== wxT('.') && *pattern 
!= *str
) 
1642     while ((*pattern 
!= wxT('\0')) && (!done
) 
1643     && (((*str
==wxT('\0'))&&((*pattern
==OB
)||(*pattern
==wxT('*'))))||(*str
!=wxT('\0')))) { 
1647             if (*pattern 
!= wxT('\0')) 
1653             while ((*str
!=wxT('\0')) 
1654             && ((ret_code
=wxMatchWild(pattern
, str
++, FALSE
)) == 0)) 
1657                 while (*str 
!= wxT('\0')) 
1659                 while (*pattern 
!= wxT('\0')) 
1666             if ((*pattern 
== wxT('\0')) || (*pattern 
== wxT(']'))) { 
1670             if (*pattern 
== wxT('\\')) { 
1672                 if (*pattern 
== wxT('\0')) { 
1677             if (*(pattern 
+ 1) == wxT('-')) { 
1680                 if (*pattern 
== wxT(']')) { 
1684                 if (*pattern 
== wxT('\\')) { 
1686                     if (*pattern 
== wxT('\0')) { 
1691                 if ((*str 
< c
) || (*str 
> *pattern
)) { 
1695             } else if (*pattern 
!= *str
) { 
1700             while ((*pattern 
!= wxT(']')) && (*pattern 
!= wxT('\0'))) { 
1701                 if ((*pattern 
== wxT('\\')) && (*(pattern 
+ 1) != wxT('\0'))) 
1705             if (*pattern 
!= wxT('\0')) { 
1715             while ((*pattern 
!= CB
) && (*pattern 
!= wxT('\0'))) { 
1718                 while (ok 
&& (*cp 
!= wxT('\0')) && (*pattern 
!= wxT('\0')) 
1719                 &&  (*pattern 
!= wxT(',')) && (*pattern 
!= CB
)) { 
1720                     if (*pattern 
== wxT('\\')) 
1722                     ok 
= (*pattern
++ == *cp
++); 
1724                 if (*pattern 
== wxT('\0')) { 
1730                     while ((*pattern 
!= CB
) && (*pattern 
!= wxT('\0'))) { 
1731                         if (*++pattern 
== wxT('\\')) { 
1732                             if (*++pattern 
== CB
) 
1737                     while (*pattern
!=CB 
&& *pattern
!=wxT(',') && *pattern
!=wxT('\0')) { 
1738                         if (*++pattern 
== wxT('\\')) { 
1739                             if (*++pattern 
== CB 
|| *pattern 
== wxT(',')) 
1744                 if (*pattern 
!= wxT('\0')) 
1749             if (*str 
== *pattern
) { 
1756     while (*pattern 
== wxT('*')) 
1758     return ((*str 
== wxT('\0')) && (*pattern 
== wxT('\0'))); 
1764     #pragma warning(default:4706)   // assignment within conditional expression