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" 
  37 // there are just too many of those... 
  39     #pragma warning(disable:4706)   // assignment within conditional expression 
  46 #if !defined(__WATCOMC__) 
  47     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  55     #include <sys/types.h> 
  70     #include "wx/os2/private.h" 
  73 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__) 
  78 #endif // native Win compiler 
  82         #include <sys/unistd.h> 
  86 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
  87                     // this (3.1 I believe) and how to test for it. 
  88                     // If this works for Borland 4.0 as well, then no worries. 
 100 // No, Cygwin doesn't appear to have fnmatch.h after all. 
 101 #if defined(HAVE_FNMATCH_H) 
 109 // ---------------------------------------------------------------------------- 
 111 // ---------------------------------------------------------------------------- 
 113 #define _MAXPATHLEN 500 
 115 extern wxChar 
*wxBuffer
; 
 117 #if defined(__WXMAC__) && !defined(__UNIX__) 
 118     #include "morefile.h" 
 119     #include "moreextr.h" 
 120     #include "fullpath.h" 
 121     #include "fspcompa.h" 
 124 IMPLEMENT_DYNAMIC_CLASS(wxPathList
, wxStringList
) 
 126 // ---------------------------------------------------------------------------- 
 128 // ---------------------------------------------------------------------------- 
 130 static wxChar wxFileFunctionsBuffer
[4*_MAXPATHLEN
]; 
 132 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
 134 // VisualAge C++ V4.0 cannot have any external linkage const decs 
 135 // in headers included by more than one primary source 
 137 const off_t wxInvalidOffset 
= (off_t
)-1; 
 140 // ---------------------------------------------------------------------------- 
 142 // ---------------------------------------------------------------------------- 
 144 // we need to translate Mac filenames before passing them to OS functions 
 146     #define OS_FILENAME(s) (wxUnix2MacFilename(s)) 
 148     #define OS_FILENAME(s) (s.fn_str()) 
 151 // ============================================================================ 
 153 // ============================================================================ 
 155 void wxPathList::Add (const wxString
& path
) 
 157     wxStringList::Add (WXSTRINGCAST path
); 
 160 // Add paths e.g. from the PATH environment variable 
 161 void wxPathList::AddEnvList (const wxString
& envVariable
) 
 163   static const wxChar PATH_TOKS
[] = 
 165         wxT(" ;"); // Don't seperate with colon in DOS (used for drive) 
 170   wxChar 
*val 
= wxGetenv (WXSTRINGCAST envVariable
); 
 173       wxChar 
*s 
= copystring (val
); 
 174       wxChar 
*save_ptr
, *token 
= wxStrtok (s
, PATH_TOKS
, &save_ptr
); 
 178           Add (copystring (token
)); 
 181               if ((token 
= wxStrtok ((wxChar 
*) NULL
, PATH_TOKS
, &save_ptr
)) != NULL
) 
 182                   Add (wxString(token
)); 
 186       // suppress warning about unused variable save_ptr when wxStrtok() is a 
 187       // macro which throws away its third argument 
 194 // Given a full filename (with path), ensure that that file can 
 195 // be accessed again USING FILENAME ONLY by adding the path 
 196 // to the list if not already there. 
 197 void wxPathList::EnsureFileAccessible (const wxString
& path
) 
 199     wxString 
path_only(wxPathOnly(path
)); 
 200     if ( !path_only
.IsEmpty() ) 
 202         if ( !Member(path_only
) ) 
 207 bool wxPathList::Member (const wxString
& path
) 
 209   for (wxNode 
* node 
= First (); node 
!= NULL
; node 
= node
->Next ()) 
 211       wxString 
path2((wxChar 
*) node
->Data ()); 
 213 #if defined(__WINDOWS__) || defined(__VMS__) || defined (__WXMAC__) 
 215           path
.CompareTo (path2
, wxString::ignoreCase
) == 0 
 217       // Case sensitive File System 
 218           path
.CompareTo (path2
) == 0 
 226 wxString 
wxPathList::FindValidPath (const wxString
& file
) 
 228   if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer
, file
))) 
 229     return wxString(wxFileFunctionsBuffer
); 
 231   wxChar buf
[_MAXPATHLEN
]; 
 232   wxStrcpy(buf
, wxFileFunctionsBuffer
); 
 234   wxChar 
*filename 
= (wxChar
*) NULL
; /* shut up buggy egcs warning */ 
 235   filename 
= IsAbsolutePath (buf
) ? wxFileNameFromPath (buf
) : (wxChar 
*)buf
; 
 237   for (wxNode 
* node 
= First (); node
; node 
= node
->Next ()) 
 239       wxChar 
*path 
= (wxChar 
*) node
->Data (); 
 240       wxStrcpy (wxFileFunctionsBuffer
, path
); 
 241       wxChar ch 
= wxFileFunctionsBuffer
[wxStrlen(wxFileFunctionsBuffer
)-1]; 
 242       if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 243         wxStrcat (wxFileFunctionsBuffer
, wxT("/")); 
 244       wxStrcat (wxFileFunctionsBuffer
, filename
); 
 246       Unix2DosFilename (wxFileFunctionsBuffer
); 
 248       if (wxFileExists (wxFileFunctionsBuffer
)) 
 250         return wxString(wxFileFunctionsBuffer
);        // Found! 
 254   return wxString(wxT(""));                    // Not found 
 257 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) 
 259     wxString f 
= FindValidPath(file
); 
 260     if ( wxIsAbsolutePath(f
) ) 
 264     wxGetWorkingDirectory(buf
.GetWriteBuf(_MAXPATHLEN
), _MAXPATHLEN 
- 1); 
 266     if ( !wxEndsWithPathSeparator(buf
) ) 
 268         buf 
+= wxFILE_SEP_PATH
; 
 276 wxFileExists (const wxString
& filename
) 
 278 #ifdef __GNUWIN32__ // (fix a B20 bug) 
 279     return GetFileAttributes(filename
) != 0xFFFFFFFF; 
 282     if ( !filename
.empty() && wxStat (OS_FILENAME(filename
), &stbuf
) == 0 ) 
 290 wxIsAbsolutePath (const wxString
& filename
) 
 292   if (filename 
!= wxT("")) 
 294       if (filename
[0] == wxT('/') 
 296       || (filename
[0] == wxT('[') && filename
[1] != wxT('.')) 
 300       || filename
[0] == wxT('\\') || (wxIsalpha (filename
[0]) && filename
[1] == wxT(':')) 
 309  * Strip off any extension (dot something) from end of file, 
 310  * IF one exists. Inserts zero into buffer. 
 314 void wxStripExtension(wxChar 
*buffer
) 
 316   int len 
= wxStrlen(buffer
); 
 320     if (buffer
[i
] == wxT('.')) 
 329 void wxStripExtension(wxString
& buffer
) 
 331   size_t len 
= buffer
.Length(); 
 335     if (buffer
.GetChar(i
) == wxT('.')) 
 337       buffer 
= buffer
.Left(i
); 
 344 // Destructive removal of /./ and /../ stuff 
 345 wxChar 
*wxRealPath (wxChar 
*path
) 
 348   static const wxChar SEP 
= wxT('\\'); 
 349   Unix2DosFilename(path
); 
 351   static const wxChar SEP 
= wxT('/'); 
 353   if (path
[0] && path
[1]) { 
 354     /* MATTHEW: special case "/./x" */ 
 356     if (path
[2] == SEP 
&& path
[1] == wxT('.')) 
 364             if (p
[1] == wxT('.') && p
[2] == wxT('.') && (p
[3] == SEP 
|| p
[3] == wxT('\0'))) 
 367                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--); 
 368                 if (q
[0] == SEP 
&& (q
[1] != wxT('.') || q
[2] != wxT('.') || q
[3] != SEP
) 
 369                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 372                     if (path
[0] == wxT('\0')) 
 378                     /* Check that path[2] is NULL! */ 
 379                     else if (path
[1] == wxT(':') && !path
[2]) 
 388             else if (p
[1] == wxT('.') && (p
[2] == SEP 
|| p
[2] == wxT('\0'))) 
 397 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 399   if (filename 
== wxT("")) 
 400     return (wxChar 
*) NULL
; 
 402   if (! IsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer
, filename
))) { 
 403     wxChar  buf
[_MAXPATHLEN
]; 
 405     wxGetWorkingDirectory(buf
, WXSIZEOF(buf
)); 
 406     wxChar ch 
= buf
[wxStrlen(buf
) - 1]; 
 408     if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 409         wxStrcat(buf
, wxT("\\")); 
 412         wxStrcat(buf
, wxT("/")); 
 414     wxStrcat(buf
, wxFileFunctionsBuffer
); 
 415     return copystring( wxRealPath(buf
) ); 
 417   return copystring( wxFileFunctionsBuffer 
); 
 423    ~user/ => user's home dir 
 424    If the environment variable a = "foo" and b = "bar" then: 
 441 /* input name in name, pathname output to buf. */ 
 443 wxChar 
*wxExpandPath(wxChar 
*buf
, const wxChar 
*name
) 
 445     register wxChar 
*d
, *s
, *nm
; 
 446     wxChar          lnm
[_MAXPATHLEN
]; 
 449     // Some compilers don't like this line. 
 450 //    const wxChar    trimchars[] = wxT("\n \t"); 
 453     trimchars
[0] = wxT('\n'); 
 454     trimchars
[1] = wxT(' '); 
 455     trimchars
[2] = wxT('\t'); 
 459      const wxChar     SEP 
= wxT('\\'); 
 461      const wxChar     SEP 
= wxT('/'); 
 464     if (name 
== NULL 
|| *name 
== wxT('\0')) 
 466     nm 
= copystring(name
); // Make a scratch copy 
 469     /* Skip leading whitespace and cr */ 
 470     while (wxStrchr((wxChar 
*)trimchars
, *nm
) != NULL
) 
 472     /* And strip off trailing whitespace and cr */ 
 473     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 474     while (q
-- && wxStrchr((wxChar 
*)trimchars
, *s
) != NULL
) 
 482     q 
= nm
[0] == wxT('\\') && nm
[1] == wxT('~'); 
 485     /* Expand inline environment variables */ 
 503     while ((*d
++ = *s
)) { 
 505         if (*s 
== wxT('\\')) { 
 506             if ((*(d 
- 1) = *++s
)) { 
 515         if (*s
++ == wxT('$') && (*s 
== wxT('{') || *s 
== wxT(')'))) 
 517         if (*s
++ == wxT('$')) 
 520             register wxChar  
*start 
= d
; 
 521             register int     braces 
= (*s 
== wxT('{') || *s 
== wxT('(')); 
 522             register wxChar  
*value
; 
 524     // VA gives assignment in logical expr warning 
 530                 if (braces 
? (*s 
== wxT('}') || *s 
== wxT(')')) : !(wxIsalnum(*s
) || *s 
== wxT('_')) ) 
 535             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 538     // VA gives assignment in logical expr warning 
 539                 for ((d 
= start 
- 1); (*d
); *d
++ = *value
++); 
 541                 for ((d 
= start 
- 1); (*d
++ = *value
++);); 
 550     /* Expand ~ and ~user */ 
 553     if (nm
[0] == wxT('~') && !q
) 
 556         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 558         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 559             if ((s 
= WXSTRINGCAST 
wxGetUserHome(wxT(""))) != NULL
) { 
 564         {                /* ~user/filename */ 
 565             register wxChar  
*nnm
; 
 566             register wxChar  
*home
; 
 567             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++); 
 568             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 569             was_sep 
= (*s 
== SEP
); 
 570             nnm 
= *s 
? s 
+ 1 : s
; 
 572         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 573             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 574                if (was_sep
) /* replace only if it was there: */ 
 585     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 587         while (wxT('\0') != (*d
++ = *s
++)) 
 590         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 595     // VA gives assignment in logical expr warning 
 599     while ((*d
++ = *s
++)); 
 601     delete[] nm_tmp
; // clean up alloc 
 602     /* Now clean up the buffer */ 
 603     return wxRealPath(buf
); 
 606 /* Contract Paths to be build upon an environment variable 
 609    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 611    The call wxExpandPath can convert these back! 
 614 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 616   static wxChar dest
[_MAXPATHLEN
]; 
 618   if (filename 
== wxT("")) 
 619     return (wxChar 
*) NULL
; 
 621   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 623   Unix2DosFilename(dest
); 
 626   // Handle environment 
 627   const wxChar 
*val 
= (const wxChar 
*) NULL
; 
 628   wxChar 
*tcp 
= (wxChar 
*) NULL
; 
 629   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 630      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 632         wxStrcpy (wxFileFunctionsBuffer
, tcp 
+ wxStrlen (val
)); 
 635         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 636         wxStrcat (tcp
, wxT("}")); 
 637         wxStrcat (tcp
, wxFileFunctionsBuffer
); 
 640   // Handle User's home (ignore root homes!) 
 642   if ((val 
= wxGetUserHome (user
)) != NULL 
&& 
 643       (len 
= wxStrlen(val
)) > 2 && 
 644       wxStrncmp(dest
, val
, len
) == 0) 
 646       wxStrcpy(wxFileFunctionsBuffer
, wxT("~")); 
 648              wxStrcat(wxFileFunctionsBuffer
, (const wxChar
*) user
); 
 650 //      strcat(wxFileFunctionsBuffer, "\\"); 
 652 //      strcat(wxFileFunctionsBuffer, "/"); 
 654       wxStrcat(wxFileFunctionsBuffer
, dest 
+ len
); 
 655       wxStrcpy (dest
, wxFileFunctionsBuffer
); 
 661 // Return just the filename, not the path 
 663 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 667       register wxChar 
*tcp
; 
 669       tcp 
= path 
+ wxStrlen (path
); 
 670       while (--tcp 
>= path
) 
 672           if (*tcp 
== wxT('/') || *tcp 
== wxT('\\') 
 674      || *tcp 
== wxT(':') || *tcp 
== wxT(']')) 
 680 #if defined(__WXMSW__) || defined(__WXPM__) 
 681       if (wxIsalpha (*path
) && *(path 
+ 1) == wxT(':')) 
 688 wxString 
wxFileNameFromPath (const wxString
& path1
) 
 690   if (path1 
!= wxT("")) 
 693       wxChar 
*path 
= WXSTRINGCAST path1 
; 
 694       register wxChar 
*tcp
; 
 696       tcp 
= path 
+ wxStrlen (path
); 
 697       while (--tcp 
>= path
) 
 699             if (*tcp 
== wxT('/') || *tcp 
== wxT('\\') 
 701         || *tcp 
== wxT(':') || *tcp 
== wxT(']')) 
 705                 return wxString(tcp 
+ 1); 
 707 #if defined(__WXMSW__) || defined(__WXPM__) 
 708       if (wxIsalpha (*path
) && *(path 
+ 1) == wxT(':')) 
 709             return wxString(path 
+ 2); 
 712   // Yes, this should return the path, not an empty string, otherwise 
 713   // we get "thing.txt" -> "". 
 717 // Return just the directory, or NULL if no directory 
 719 wxPathOnly (wxChar 
*path
) 
 723       static wxChar buf
[_MAXPATHLEN
]; 
 726       wxStrcpy (buf
, path
); 
 728       int l 
= wxStrlen(path
); 
 733       // Search backward for a backward or forward slash 
 734       while (!done 
&& i 
> -1) 
 737         if (path
[i
] == wxT('/') || path
[i
] == wxT('\\') || path
[i
] == wxT(']')) 
 741            if ( path
[i
] == wxT(']') ) 
 752 #if defined(__WXMSW__) || defined(__WXPM__) 
 753       // Try Drive specifier 
 754       if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 756           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 764   return (wxChar 
*) NULL
; 
 767 // Return just the directory, or NULL if no directory 
 768 wxString 
wxPathOnly (const wxString
& path
) 
 772       wxChar buf
[_MAXPATHLEN
]; 
 775       wxStrcpy (buf
, WXSTRINGCAST path
); 
 777       int l 
= path
.Length(); 
 782       // Search backward for a backward or forward slash 
 783       while (!done 
&& i 
> -1) 
 786         if (path
[i
] == wxT('/') || path
[i
] == wxT('\\') || path
[i
] == wxT(']')) 
 790            if ( path
[i
] == wxT(']') ) 
 796           return wxString(buf
); 
 801 #if defined(__WXMSW__) || defined(__WXPM__) 
 802       // Try Drive specifier 
 803       if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 805           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 808           return wxString(buf
); 
 813   return wxString(wxT("")); 
 816 // Utility for converting delimiters in DOS filenames to UNIX style 
 817 // and back again - or we get nasty problems with delimiters. 
 818 // Also, convert to lower case, since case is significant in UNIX. 
 820 #if defined(__WXMAC__) && !defined(__UNIX__) 
 822 static char sMacFileNameConversion
[ 1000 ] ; 
 824 wxString 
wxMac2UnixFilename (const char *str
) 
 826     char *s 
= sMacFileNameConversion 
; 
 830     memmove( s
+1 , s 
,strlen( s 
) + 1) ; 
 841               *s 
= wxTolower (*s
);        // Case INDEPENDENT 
 845   return wxString (sMacFileNameConversion
) ; 
 848 wxString 
wxUnix2MacFilename (const char *str
) 
 850     char *s 
= sMacFileNameConversion 
; 
 856       // relative path , since it goes on with slash which is translated to a : 
 857       memmove( s 
, s
+1 ,strlen( s 
) ) ; 
 859     else if ( *s 
== '/' ) 
 861       // absolute path -> on mac just start with the drive name 
 862       memmove( s 
, s
+1 ,strlen( s 
) ) ; 
 866       wxASSERT_MSG( 1 , "unkown path beginning" ) ; 
 870       if (*s 
== '/' || *s 
== '\\') 
 872           // convert any back-directory situations 
 873           if ( *(s
+1) == '.' && *(s
+2) == '.' && ( (*(s
+3) == '/' || *(s
+3) == '\\') ) ) 
 876                 memmove( s
+1 , s
+3 ,strlen( s
+3 ) + 1 ) ; 
 885   return wxString (sMacFileNameConversion
) ; 
 888 wxString 
wxMacFSSpec2MacFilename( const FSSpec 
*spec 
) 
 893     FSpGetFullPath( spec 
, &length 
, &myPath 
) ; 
 894     ::SetHandleSize( myPath 
, length 
+ 1 ) ; 
 896     (*myPath
)[length
] = 0 ; 
 897     if ( length 
> 0 && (*myPath
)[length
-1] ==':' ) 
 898         (*myPath
)[length
-1] = 0 ; 
 900     wxString 
result(     (char*) *myPath 
) ; 
 901     ::HUnlock( myPath 
) ; 
 902     ::DisposeHandle( myPath 
) ; 
 906 wxString 
wxMacFSSpec2UnixFilename( const FSSpec 
*spec 
) 
 908     return wxMac2UnixFilename( wxMacFSSpec2MacFilename( spec
) ) ; 
 911 void wxMacFilename2FSSpec( const char *path 
, FSSpec 
*spec 
) 
 913     FSpLocationFromFullPath( strlen(path 
) , path 
, spec 
) ; 
 916 void wxUnixFilename2FSSpec( const char *path 
, FSSpec 
*spec 
) 
 918     wxString var 
= wxUnix2MacFilename( path 
) ; 
 919     wxMacFilename2FSSpec( var 
, spec 
) ; 
 924 wxDos2UnixFilename (char *s
) 
 933           *s 
= wxTolower (*s
);        // Case INDEPENDENT 
 940 #if defined(__WXMSW__) || defined(__WXPM__) 
 941 wxUnix2DosFilename (wxChar 
*s
) 
 943 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
) ) 
 946 // Yes, I really mean this to happen under DOS only! JACS 
 947 #if defined(__WXMSW__) || defined(__WXPM__) 
 958 // Concatenate two files to form third 
 960 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
 963   if ( !wxGetTempFileName("cat", outfile
) ) 
 966   FILE *fp1 
= (FILE *) NULL
; 
 967   FILE *fp2 
= (FILE *) NULL
; 
 968   FILE *fp3 
= (FILE *) NULL
; 
 969   // Open the inputs and outputs 
 970   if ((fp1 
= fopen (OS_FILENAME( file1 
), "rb")) == NULL 
|| 
 971       (fp2 
= fopen (OS_FILENAME( file2 
), "rb")) == NULL 
|| 
 972       (fp3 
= fopen (OS_FILENAME( outfile 
), "wb")) == NULL
) 
 984   while ((ch 
= getc (fp1
)) != EOF
) 
 985     (void) putc (ch
, fp3
); 
 988   while ((ch 
= getc (fp2
)) != EOF
) 
 989     (void) putc (ch
, fp3
); 
 993   bool result 
= wxRenameFile(outfile
, file3
); 
 999 wxCopyFile (const wxString
& file1
, const wxString
& file2
) 
1003     // get permissions of file1 
1004     if ( wxStat(OS_FILENAME(file1
), &fbuf
) != 0 ) 
1006         // the file probably doesn't exist or we haven't the rights to read 
1008         wxLogSysError(_("Impossible to get permissions for file '%s'"), 
1013     // open file1 for reading 
1014     wxFile 
fileIn(file1
, wxFile::read
); 
1015     if ( !fileIn
.IsOpened() ) 
1018     // remove file2, if it exists. This is needed for creating 
1019     // file2 with the correct permissions in the next step 
1020     if ( wxFileExists(file2
) && !wxRemoveFile(file2
) ) 
1022         wxLogSysError(_("Impossible to overwrite the file '%s'"), 
1028     // reset the umask as we want to create the file with exactly the same 
1029     // permissions as the original one 
1030     mode_t oldUmask 
= umask( 0 ); 
1033     // create file2 with the same permissions than file1 and open it for 
1036     if ( !fileOut
.Create(file2
, TRUE
, fbuf
.st_mode 
& 0777) ) 
1040     /// restore the old umask 
1044     // copy contents of file1 to file2 
1049         count 
= fileIn
.Read(buf
, WXSIZEOF(buf
)); 
1050         if ( fileIn
.Error() ) 
1057         if ( fileOut
.Write(buf
, count
) < count 
) 
1061 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 
1062 // no chmod in VA.  SHould be some permission API for HPFS386 partitions however 
1063     if ( chmod(OS_FILENAME(file2
), fbuf
.st_mode
) != 0 ) 
1065         wxLogSysError(_("Impossible to set permissions for the file '%s'"), 
1074 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
1076   // Normal system call 
1077   if ( wxRename (file1
, file2
) == 0 ) 
1081   if (wxCopyFile(file1
, file2
)) { 
1082     wxRemoveFile(file1
); 
1089 bool wxRemoveFile(const wxString
& file
) 
1091 #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__WATCOMC__) 
1092   int res 
= wxRemove(file
); 
1094   int res 
= unlink(OS_FILENAME(file
)); 
1100 bool wxMkdir(const wxString
& dir
, int perm
) 
1102 #if defined(__WXMAC__) && !defined(__UNIX__) 
1103   return (mkdir(wxUnix2MacFilename( dir 
) , 0 ) == 0); 
1105     const wxChar 
*dirname 
= dir
.c_str(); 
1107     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 
1108     // for the GNU compiler 
1109 #if (!(defined(__WXMSW__) || defined(__WXPM__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WXWINE__) 
1110     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1111 #elif defined(__WXPM__) 
1112     if (::DosCreateDir((PSZ
)dirname
, NULL
) != 0) // enhance for EAB's?? 
1113 #else  // !MSW and !OS/2 VAC++ 
1114     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1117         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1126 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1129   return FALSE
; //to be changed since rmdir exists in VMS7.x 
1130 #elif defined(__WXPM__) 
1131   return (::DosDeleteDir((PSZ
)dir
.c_str()) == 0); 
1135   return FALSE
; // What to do? 
1137   return (wxRmDir(OS_FILENAME(dir
)) == 0); 
1143 // does the path exists? (may have or not '/' or '\\' at the end) 
1144 bool wxPathExists(const wxChar 
*pszPathName
) 
1146     wxString 
strPath(pszPathName
); 
1148     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
1149     // so remove all trailing backslashes from the path - but don't do this for 
1150     // the pathes "d:\" (which are different from "d:") nor for just "\" 
1151     while ( wxEndsWithPathSeparator(strPath
) ) 
1153         size_t len 
= strPath
.length(); 
1154         if ( len 
== 1 || strPath
[len 
- 1] == _T(':') ) 
1157         strPath
.Truncate(len 
- 1); 
1159 #endif // __WINDOWS__ 
1162 #ifndef __VISAGECPP__ 
1163     return wxStat(wxFNSTRINGCAST strPath
.fn_str(), &st
) == 0 && 
1164         ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
1166     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
1167     return wxStat(wxFNSTRINGCAST strPath
.fn_str(), &st
) == 0 && 
1168         (st
.st_mode 
== S_IFDIR
); 
1173 // Get a temporary filename, opening and closing the file. 
1174 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1180   ::GetTempFileName(0, WXSTRINGCAST prefix
, 0, tmp
); 
1182   wxChar tmp
[MAX_PATH
]; 
1183   wxChar tmpPath
[MAX_PATH
]; 
1184   ::GetTempPath(MAX_PATH
, tmpPath
); 
1185   ::GetTempFileName(tmpPath
, WXSTRINGCAST prefix
, 0, tmp
); 
1187   if (buf
) wxStrcpy(buf
, tmp
); 
1188   else buf 
= copystring(tmp
); 
1192   static short last_temp 
= 0;        // cache last to speed things a bit 
1193   // At most 1000 temp files to a process! We use a ring count. 
1194   wxChar tmp
[100]; // FIXME static buffer 
1196   for (short suffix 
= last_temp 
+ 1; suffix 
!= last_temp
; ++suffix 
%= 1000) 
1198       wxSprintf (tmp
, wxT("/tmp/%s%d.%03x"), WXSTRINGCAST prefix
, (int) getpid (), (int) suffix
); 
1199       if (!wxFileExists( tmp 
)) 
1201           // Touch the file to create it (reserve name) 
1202           FILE *fd 
= fopen (wxFNCONV(tmp
), "w"); 
1207             wxStrcpy( buf
, tmp
); 
1209             buf 
= copystring( tmp 
); 
1213   wxLogError( _("wxWindows: error finding temporary file name.\n") ); 
1214   if (buf
) buf
[0] = 0; 
1215   return (wxChar 
*) NULL
; 
1219 bool wxGetTempFileName(const wxString
& prefix
, wxString
& buf
) 
1222     if (wxGetTempFileName(prefix
, buf2
) != (wxChar
*) NULL
) 
1231 // Get first file name matching given wild card. 
1235 // Get first file name matching given wild card. 
1236 // Flags are reserved for future use. 
1238 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 ) 
1239     static DIR *gs_dirStream 
= (DIR *) NULL
; 
1240     static wxString gs_strFileSpec
; 
1241     static int gs_findFlags 
= 0; 
1244 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1248    wxChar 
*specvms 
= NULL
; 
1251 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 ) 
1253         closedir(gs_dirStream
); // edz 941103: better housekeping 
1255     gs_findFlags 
= flags
; 
1257     gs_strFileSpec 
= spec
; 
1259     // Find path only so we can concatenate 
1260     // found file onto path 
1261     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1263     // special case: path is really "/" 
1264     if ( !path 
&& gs_strFileSpec
[0u] == wxT('/') ) 
1267         wxStrcpy( specvms 
, wxT( "[000000]" ) ); 
1268         gs_strFileSpec 
= specvms
; 
1269         wxString 
path_vms(wxPathOnly(gs_strFileSpec
)); 
1275    // path is empty => Local directory 
1279         wxStrcpy( specvms 
, wxT( "[]" ) ); 
1280         gs_strFileSpec 
= specvms
; 
1281         wxString 
path_vms1(wxPathOnly(gs_strFileSpec
)); 
1288     gs_dirStream 
= opendir(path
.fn_str()); 
1289     if ( !gs_dirStream 
) 
1291         wxLogSysError(_("Can not enumerate files in directory '%s'"), 
1296         result 
= wxFindNextFile(); 
1298 #endif // !VMS6.x or earlier 
1303 wxString 
wxFindNextFile() 
1307 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 ) 
1308     wxCHECK_MSG( gs_dirStream
, result
, wxT("must call wxFindFirstFile first") ); 
1310     // Find path only so we can concatenate 
1311     // found file onto path 
1312     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1313     wxString 
name(wxFileNameFromPath(gs_strFileSpec
)); 
1315     /* MATTHEW: special case: path is really "/" */ 
1316     if ( !path 
&& gs_strFileSpec
[0u] == wxT('/')) 
1320     struct dirent 
*nextDir
; 
1321     for ( nextDir 
= readdir(gs_dirStream
); 
1323           nextDir 
= readdir(gs_dirStream
) ) 
1325         if (wxMatchWild(name
, nextDir
->d_name
, FALSE
) &&   // RR: added FALSE to find hidden files 
1326         strcmp(nextDir
->d_name
, ".") && 
1327         strcmp(nextDir
->d_name
, "..") ) 
1330             if ( !path
.IsEmpty() ) 
1333                 if ( path 
!= wxT('/') ) 
1337             result 
+= nextDir
->d_name
; 
1339             // Only return "." and ".." when they match 
1341             if ( (strcmp(nextDir
->d_name
, ".") == 0) || 
1342                  (strcmp(nextDir
->d_name
, "..") == 0)) 
1344                 if ( (gs_findFlags 
& wxDIR
) != 0 ) 
1350                 isdir 
= wxDirExists(result
); 
1352             // and only return directories when flags & wxDIR 
1353             if ( !gs_findFlags 
|| 
1354                  ((gs_findFlags 
& wxDIR
) && isdir
) || 
1355                  ((gs_findFlags 
& wxFILE
) && !isdir
) ) 
1362     result
.Empty(); // not found 
1364     closedir(gs_dirStream
); 
1365     gs_dirStream 
= (DIR *) NULL
; 
1366 #endif // !VMS6.2 or earlier 
1371 #elif defined(__WXMAC__) 
1373 struct MacDirectoryIterator
 
1381 static int g_iter_flags 
; 
1383 static MacDirectoryIterator g_iter 
; 
1385 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1389     g_iter_flags 
= flags
; /* MATTHEW: [5] Remember flags */ 
1391     // Find path only so we can concatenate found file onto path 
1392     wxString 
path(wxPathOnly(spec
)); 
1393     if ( !path
.IsEmpty() ) 
1394         result 
<< path 
<< wxT('\\'); 
1398     wxUnixFilename2FSSpec( result 
, &fsspec 
) ; 
1399     g_iter
.m_CPB
.hFileInfo
.ioVRefNum 
= fsspec
.vRefNum 
; 
1400     g_iter
.m_CPB
.hFileInfo
.ioNamePtr 
= g_iter
.m_name 
; 
1401     g_iter
.m_index 
= 0 ; 
1404     FSpGetDirectoryID( &fsspec 
, &g_iter
.m_dirId 
, &isDir 
) ; 
1406         return wxEmptyString 
; 
1408     return wxFindNextFile( ) ; 
1411 wxString 
wxFindNextFile() 
1417     while ( err 
== noErr 
) 
1420         g_iter
.m_CPB
.dirInfo
.ioFDirIndex 
= g_iter
.m_index
; 
1421         g_iter
.m_CPB
.dirInfo
.ioDrDirID 
= g_iter
.m_dirId
;    /* we need to do this every time */ 
1422         err 
= PBGetCatInfoSync((CInfoPBPtr
)&g_iter
.m_CPB
); 
1426         if ( ( g_iter
.m_CPB
.dirInfo
.ioFlAttrib 
& ioDirMask
) != 0 && (g_iter_flags 
& wxDIR
) ) //  we have a directory 
1429         if ( ( g_iter
.m_CPB
.dirInfo
.ioFlAttrib 
& ioDirMask
) == 0 && !(g_iter_flags 
& wxFILE 
) ) 
1437         return wxEmptyString 
; 
1441     FSMakeFSSpecCompat(g_iter
.m_CPB
.hFileInfo
.ioVRefNum
, 
1446     return wxMacFSSpec2UnixFilename( &spec 
) ; 
1449 #elif defined(__WXMSW__) 
1452     static HANDLE gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1453     static WIN32_FIND_DATA gs_findDataStruct
; 
1456         static struct ffblk gs_findDataStruct
; 
1458         static struct _find_t gs_findDataStruct
; 
1462 static wxString gs_strFileSpec
; 
1463 static int gs_findFlags 
= 0; 
1465 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1469     gs_strFileSpec 
= spec
; 
1470     gs_findFlags 
= flags
; /* MATTHEW: [5] Remember flags */ 
1472     // Find path only so we can concatenate found file onto path 
1473     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1474     if ( !path
.IsEmpty() ) 
1475         result 
<< path 
<< wxT('\\'); 
1478     if ( gs_hFileStruct 
!= INVALID_HANDLE_VALUE 
) 
1479         FindClose(gs_hFileStruct
); 
1481     gs_hFileStruct 
= ::FindFirstFile(WXSTRINGCAST spec
, &gs_findDataStruct
); 
1483     if ( gs_hFileStruct 
== INVALID_HANDLE_VALUE 
) 
1490     bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1492     if (isdir 
&& !(flags 
& wxDIR
)) 
1493         return wxFindNextFile(); 
1494     else if (!isdir 
&& flags 
&& !(flags 
& wxFILE
)) 
1495         return wxFindNextFile(); 
1497     result 
+= gs_findDataStruct
.cFileName
; 
1501     int flag 
= _A_NORMAL
; 
1506     if (findfirst(WXSTRINGCAST spec
, &gs_findDataStruct
, flag
) == 0) 
1508         if (_dos_findfirst(WXSTRINGCAST spec
, flag
, &gs_findDataStruct
) == 0) 
1514             attrib 
= gs_findDataStruct
.ff_attrib
; 
1516             attrib 
= gs_findDataStruct
.attrib
; 
1519             if (attrib 
& _A_SUBDIR
) { 
1520                 if (!(gs_findFlags 
& wxDIR
)) 
1521                     return wxFindNextFile(); 
1522             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1523                 return wxFindNextFile(); 
1527                     gs_findDataStruct
.ff_name
 
1529                     gs_findDataStruct
.name
 
1539 wxString 
wxFindNextFile() 
1543     // Find path only so we can concatenate found file onto path 
1544     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1549     if (gs_hFileStruct 
== INVALID_HANDLE_VALUE
) 
1552     bool success 
= (FindNextFile(gs_hFileStruct
, &gs_findDataStruct
) != 0); 
1555         FindClose(gs_hFileStruct
); 
1556         gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1560         bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1562         if (isdir 
&& !(gs_findFlags 
& wxDIR
)) 
1564         else if (!isdir 
&& gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1567         if ( !path
.IsEmpty() ) 
1568             result 
<< path 
<< wxT('\\'); 
1569         result 
<< gs_findDataStruct
.cFileName
; 
1576     if (findnext(&gs_findDataStruct
) == 0) 
1578         if (_dos_findnext(&gs_findDataStruct
) == 0) 
1581             /* MATTHEW: [5] Check directory flag */ 
1585             attrib 
= gs_findDataStruct
.ff_attrib
; 
1587             attrib 
= gs_findDataStruct
.attrib
; 
1590             if (attrib 
& _A_SUBDIR
) { 
1591                 if (!(gs_findFlags 
& wxDIR
)) 
1593             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1599                       gs_findDataStruct
.ff_name
 
1601                       gs_findDataStruct
.name
 
1610 #elif defined(__WXPM__) 
1612 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1617     // TODO: figure something out here for OS/2 
1618     gs_strFileSpec = spec; 
1619     gs_findFlags = flags; 
1621     // Find path only so we can concatenate found file onto path 
1622     wxString path(wxPathOnly(gs_strFileSpec)); 
1623     if ( !path.IsEmpty() ) 
1624         result << path << wxT('\\'); 
1626     int flag = _A_NORMAL; 
1630     if (_dos_findfirst(WXSTRINGCAST spec, flag, &gs_findDataStruct) == 0) 
1633         attrib = gs_findDataStruct.attrib; 
1635         if (attrib & _A_SUBDIR) { 
1636             if (!(gs_findFlags & wxDIR)) 
1637                 return wxFindNextFile(); 
1638         } else if (gs_findFlags && !(gs_findFlags & wxFILE)) 
1639             return wxFindNextFile(); 
1641         result += gs_findDataStruct.name; 
1647 wxString 
wxFindNextFile() 
1654 #endif // Unix/Windows/OS/2 
1656 // Get current working directory. 
1657 // If buf is NULL, allocates space using new, else 
1659 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1662     buf 
= new wxChar
[sz
+1]; 
1664   char *cbuf 
= new char[sz
+1]; 
1666   if (_getcwd(cbuf
, sz
) == NULL
) { 
1667 #elif defined(__WXMAC__) && !defined(__UNIX__) 
1670         SFSaveDisk 
= 0x214, CurDirStore 
= 0x398 
1674     FSMakeFSSpec( - *(short *) SFSaveDisk 
, *(long *) CurDirStore 
, NULL 
, &cwdSpec 
) ; 
1675     wxString res 
= wxMacFSSpec2UnixFilename( &cwdSpec 
) ; 
1676     strcpy( buf 
, res 
) ; 
1679   if (getcwd(cbuf
, sz
) == NULL
) { 
1684   if (_getcwd(buf
, sz
) == NULL
) { 
1685 #elif defined(__WXMAC__) && !defined(__UNIX__) 
1690         pb
.ioNamePtr 
= (StringPtr
) &fileName
; 
1692         pb
.ioRefNum 
= LMGetCurApRefNum(); 
1694         error 
= PBGetFCBInfoSync(&pb
); 
1695         if ( error 
== noErr 
)  
1697                 cwdSpec
.vRefNum 
= pb
.ioFCBVRefNum
; 
1698                 cwdSpec
.parID 
= pb
.ioFCBParID
; 
1699                 cwdSpec
.name
[0] = 0 ; 
1700                 wxString res 
= wxMacFSSpec2UnixFilename( &cwdSpec 
) ; 
1702                 strcpy( buf 
, res 
) ; 
1703                 buf
[res
.length()-1]=0 ; 
1708         this version will not always give back the application directory on mac 
1711                 SFSaveDisk = 0x214, CurDirStore = 0x398  
1715         FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ; 
1716         wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ; 
1717         strcpy( buf , res ) ; 
1720 #elif(__VISAGECPP__) 
1722     rc 
= ::DosQueryCurrentDir( 0 // current drive 
1728   if (getcwd(buf
, sz
) == NULL
) { 
1736     wxConvFile
.MB2WC(buf
, cbuf
, sz
); 
1745     static const size_t maxPathLen 
= 1024; 
1748     wxGetWorkingDirectory(str
.GetWriteBuf(maxPathLen
), maxPathLen
); 
1749     str
.UngetWriteBuf(); 
1754 bool wxSetWorkingDirectory(const wxString
& d
) 
1756 #if defined( __UNIX__ ) || defined( __WXMAC__ ) 
1757   return (chdir(wxFNSTRINGCAST d
.fn_str()) == 0); 
1758 #elif defined(__WXPM__) 
1759   return (::DosSetCurrentDir((PSZ
)d
.c_str()) == 0); 
1760 #elif defined(__WINDOWS__) 
1763   return (bool)(SetCurrentDirectory(d
) != 0); 
1765   // Must change drive, too. 
1766   bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1769     wxChar firstChar 
= d
[0]; 
1773       firstChar 
= firstChar 
- 32; 
1775     // To a drive number 
1776     unsigned int driveNo 
= firstChar 
- 64; 
1779        unsigned int noDrives
; 
1780        _dos_setdrive(driveNo
, &noDrives
); 
1783   bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1791 // Get the OS directory if appropriate (such as the Windows directory). 
1792 // On non-Windows platform, probably just return the empty string. 
1793 wxString 
wxGetOSDirectory() 
1797     GetWindowsDirectory(buf
, 256); 
1798     return wxString(buf
); 
1800     return wxEmptyString
; 
1804 bool wxEndsWithPathSeparator(const wxChar 
*pszFileName
) 
1806   size_t len 
= wxStrlen(pszFileName
); 
1810     return wxIsPathSeparator(pszFileName
[len 
- 1]); 
1813 // find a file in a list of directories, returns false if not found 
1814 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1816     // we assume that it's not empty 
1817     wxCHECK_MSG( !wxIsEmpty(pszFile
), FALSE
, 
1818                  _T("empty file name in wxFindFileInPath")); 
1820     // skip path separator in the beginning of the file name if present 
1821     if ( wxIsPathSeparator(*pszFile
) ) 
1824     // copy the path (strtok will modify it) 
1825     wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1826     wxStrcpy(szPath
, pszPath
); 
1829     wxChar 
*pc
, *save_ptr
; 
1830     for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1832           pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1834         // search for the file in this directory 
1836         if ( !wxEndsWithPathSeparator(pc
) ) 
1837             strFile 
+= wxFILE_SEP_PATH
; 
1840         if ( FileExists(strFile
) ) { 
1846     // suppress warning about unused variable save_ptr when wxStrtok() is a 
1847     // macro which throws away its third argument 
1852     return pc 
!= NULL
;  // if true => we breaked from the loop 
1855 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1860     // it can be empty, but it shouldn't be NULL 
1861     wxCHECK_RET( pszFileName
, wxT("NULL file name in wxSplitPath") ); 
1863     wxFileName::SplitPath(pszFileName
, pstrPath
, pstrName
, pstrExt
); 
1866 time_t WXDLLEXPORT 
wxFileModificationTime(const wxString
& filename
) 
1870     wxStat(filename
.fn_str(), &buf
); 
1871     return buf
.st_mtime
; 
1875 //------------------------------------------------------------------------ 
1876 // wild character routines 
1877 //------------------------------------------------------------------------ 
1879 bool wxIsWild( const wxString
& pattern 
) 
1881   wxString tmp 
= pattern
; 
1882   wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
1885         case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): 
1895 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1897 #if defined(HAVE_FNMATCH_H) 
1899 // this probably won't work well for multibyte chars in Unicode mode? 
1901       return fnmatch(pat
.fn_str(), text
.fn_str(), FNM_PERIOD
) == 0; 
1903       return fnmatch(pat
.fn_str(), text
.fn_str(), 0) == 0; 
1907 // #pragma error Broken implementation of wxMatchWild() -- needs fixing! 
1910     * WARNING: this code is broken! 
1913   wxString tmp1 
= pat
; 
1914   wxChar 
*pattern 
= WXSTRINGCAST(tmp1
); 
1915   wxString tmp2 
= text
; 
1916   wxChar 
*str 
= WXSTRINGCAST(tmp2
); 
1919     bool done 
= FALSE
, ret_code
, ok
; 
1920     // Below is for vi fans 
1921     const wxChar OB 
= wxT('{'), CB 
= wxT('}'); 
1923     // dot_special means '.' only matches '.' 
1924     if (dot_special 
&& *str 
== wxT('.') && *pattern 
!= *str
) 
1927     while ((*pattern 
!= wxT('\0')) && (!done
) 
1928     && (((*str
==wxT('\0'))&&((*pattern
==OB
)||(*pattern
==wxT('*'))))||(*str
!=wxT('\0')))) { 
1932             if (*pattern 
!= wxT('\0')) 
1938             while ((*str
!=wxT('\0')) 
1939             && (!(ret_code
=wxMatchWild(pattern
, str
++, FALSE
)))) 
1942                 while (*str 
!= wxT('\0')) 
1944                 while (*pattern 
!= wxT('\0')) 
1951             if ((*pattern 
== wxT('\0')) || (*pattern 
== wxT(']'))) { 
1955             if (*pattern 
== wxT('\\')) { 
1957                 if (*pattern 
== wxT('\0')) { 
1962             if (*(pattern 
+ 1) == wxT('-')) { 
1965                 if (*pattern 
== wxT(']')) { 
1969                 if (*pattern 
== wxT('\\')) { 
1971                     if (*pattern 
== wxT('\0')) { 
1976                 if ((*str 
< c
) || (*str 
> *pattern
)) { 
1980             } else if (*pattern 
!= *str
) { 
1985             while ((*pattern 
!= wxT(']')) && (*pattern 
!= wxT('\0'))) { 
1986                 if ((*pattern 
== wxT('\\')) && (*(pattern 
+ 1) != wxT('\0'))) 
1990             if (*pattern 
!= wxT('\0')) { 
2000             while ((*pattern 
!= CB
) && (*pattern 
!= wxT('\0'))) { 
2003                 while (ok 
&& (*cp 
!= wxT('\0')) && (*pattern 
!= wxT('\0')) 
2004                 &&  (*pattern 
!= wxT(',')) && (*pattern 
!= CB
)) { 
2005                     if (*pattern 
== wxT('\\')) 
2007                     ok 
= (*pattern
++ == *cp
++); 
2009                 if (*pattern 
== wxT('\0')) { 
2015                     while ((*pattern 
!= CB
) && (*pattern 
!= wxT('\0'))) { 
2016                         if (*++pattern 
== wxT('\\')) { 
2017                             if (*++pattern 
== CB
) 
2022                     while (*pattern
!=CB 
&& *pattern
!=wxT(',') && *pattern
!=wxT('\0')) { 
2023                         if (*++pattern 
== wxT('\\')) { 
2024                             if (*++pattern 
== CB 
|| *pattern 
== wxT(',')) 
2029                 if (*pattern 
!= wxT('\0')) 
2034             if (*str 
== *pattern
) { 
2041     while (*pattern 
== wxT('*')) 
2043     return ((*str 
== wxT('\0')) && (*pattern 
== wxT('\0'))); 
2049     #pragma warning(default:4706)   // assignment within conditional expression