1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     File- and directory-related functions 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) 1998 Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  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)) 
  53 #if defined(__WXMAC__) 
  54     #include  "wx/mac/private.h"  // includes mac headers 
  59 #include "wx/msw/wince/time.h" 
  60 #include "wx/msw/private.h" 
  67 #elif !defined(__MWERKS__) 
  68     #include <sys/types.h> 
  72 #include <sys/types.h> 
  85 // need to check for __OS2__ first since currently both 
  86 // __OS2__ and __UNIX__ are defined. 
  88     #include "wx/os2/private.h" 
  92 #elif defined(__UNIX__) 
  98 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
  99 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__) && !defined(__WXWINCE__) 
 103 #endif // __WINDOWS__ 
 104 #endif // native Win compiler 
 117 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
 118                     // this (3.1 I believe) and how to test for it. 
 119                     // If this works for Borland 4.0 as well, then no worries. 
 130 // No, Cygwin doesn't appear to have fnmatch.h after all. 
 131 #if defined(HAVE_FNMATCH_H) 
 136     #include "wx/msw/wrapwin.h" 
 137     #include "wx/msw/mslu.h" 
 144     // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() 
 146     // note that it must be included after <windows.h> 
 149             #include <sys/cygwin.h> 
 151     #endif // __GNUWIN32__ 
 152 #endif // __WINDOWS__ 
 154 // TODO: Borland probably has _wgetcwd as well? 
 159 // ---------------------------------------------------------------------------- 
 161 // ---------------------------------------------------------------------------- 
 164     #define _MAXPATHLEN 1024 
 169 #    include "MoreFilesX.h" 
 171 #    include "MoreFiles.h" 
 172 #    include "MoreFilesExtras.h" 
 173 #    include "FullPath.h" 
 174 #    include "FSpCompat.h" 
 178 // ---------------------------------------------------------------------------- 
 180 // ---------------------------------------------------------------------------- 
 182 // MT-FIXME: get rid of this horror and all code using it 
 183 static wxChar wxFileFunctionsBuffer
[4*_MAXPATHLEN
]; 
 185 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
 187 // VisualAge C++ V4.0 cannot have any external linkage const decs 
 188 // in headers included by more than one primary source 
 190 const off_t wxInvalidOffset 
= (off_t
)-1; 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 // we need to translate Mac filenames before passing them to OS functions 
 198 #define OS_FILENAME(s) (s.fn_str()) 
 200 // ============================================================================ 
 202 // ============================================================================ 
 204 #ifdef wxNEED_WX_UNISTD_H 
 206 WXDLLEXPORT 
int wxStat( const wxChar 
*file_name
, wxStructStat 
*buf 
) 
 208     return stat( wxConvFile
.cWX2MB( file_name 
), buf 
); 
 211 WXDLLEXPORT 
int wxAccess( const wxChar 
*pathname
, int mode 
) 
 213     return access( wxConvFile
.cWX2MB( pathname 
), mode 
); 
 216 WXDLLEXPORT 
int wxOpen( const wxChar 
*pathname
, int flags
, mode_t mode 
) 
 218     return open( wxConvFile
.cWX2MB( pathname 
), flags
, mode 
); 
 222    // wxNEED_WX_UNISTD_H 
 224 // ---------------------------------------------------------------------------- 
 226 // ---------------------------------------------------------------------------- 
 228 // IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList) 
 230 static inline wxChar
* MYcopystring(const wxString
& s
) 
 232     wxChar
* copy 
= new wxChar
[s
.length() + 1]; 
 233     return wxStrcpy(copy
, s
.c_str()); 
 236 static inline wxChar
* MYcopystring(const wxChar
* s
) 
 238     wxChar
* copy 
= new wxChar
[wxStrlen(s
) + 1]; 
 239     return wxStrcpy(copy
, s
); 
 242 void wxPathList::Add (const wxString
& path
) 
 244     wxStringList::Add (WXSTRINGCAST path
); 
 247 // Add paths e.g. from the PATH environment variable 
 248 void wxPathList::AddEnvList (const wxString
& envVariable
) 
 250     // No environment variables on WinCE 
 252     static const wxChar PATH_TOKS
[] = 
 253 #if defined(__WINDOWS__) || defined(__OS2__) 
 255         The space has been removed from the tokenizers, otherwise a 
 256         path such as "C:\Program Files" would be split into 2 paths: 
 257         "C:\Program" and "Files" 
 259 //        wxT(" ;"); // Don't seperate with colon in DOS (used for drive) 
 260         wxT(";"); // Don't seperate with colon in DOS (used for drive) 
 265     wxChar 
*val 
= wxGetenv (WXSTRINGCAST envVariable
); 
 268         wxChar 
*s 
= MYcopystring (val
); 
 269         wxChar 
*save_ptr
, *token 
= wxStrtok (s
, PATH_TOKS
, &save_ptr
); 
 276                 if ( (token 
= wxStrtok ((wxChar 
*) NULL
, PATH_TOKS
, &save_ptr
)) 
 284         // suppress warning about unused variable save_ptr when wxStrtok() is a 
 285         // macro which throws away its third argument 
 293 // Given a full filename (with path), ensure that that file can 
 294 // be accessed again USING FILENAME ONLY by adding the path 
 295 // to the list if not already there. 
 296 void wxPathList::EnsureFileAccessible (const wxString
& path
) 
 298     wxString 
path_only(wxPathOnly(path
)); 
 299     if ( !path_only
.IsEmpty() ) 
 301         if ( !Member(path_only
) ) 
 306 bool wxPathList::Member (const wxString
& path
) 
 308   for (wxStringList::compatibility_iterator node 
= GetFirst(); node
; node 
= node
->GetNext()) 
 310       wxString 
path2( node
->GetData() ); 
 312 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__VMS__) || defined (__WXMAC__) 
 314           path
.CompareTo (path2
, wxString::ignoreCase
) == 0 
 316       // Case sensitive File System 
 317           path
.CompareTo (path2
) == 0 
 325 wxString 
wxPathList::FindValidPath (const wxString
& file
) 
 327   if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer
, file
))) 
 328     return wxString(wxFileFunctionsBuffer
); 
 330   wxChar buf
[_MAXPATHLEN
]; 
 331   wxStrcpy(buf
, wxFileFunctionsBuffer
); 
 333   wxChar 
*filename 
= wxIsAbsolutePath (buf
) ? wxFileNameFromPath (buf
) : (wxChar 
*)buf
; 
 335   for (wxStringList::compatibility_iterator node 
= GetFirst(); node
; node 
= node
->GetNext()) 
 337       const wxChar 
*path 
= node
->GetData(); 
 338       wxStrcpy (wxFileFunctionsBuffer
, path
); 
 339       wxChar ch 
= wxFileFunctionsBuffer
[wxStrlen(wxFileFunctionsBuffer
)-1]; 
 340       if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 341         wxStrcat (wxFileFunctionsBuffer
, wxT("/")); 
 342       wxStrcat (wxFileFunctionsBuffer
, filename
); 
 344       wxUnix2DosFilename (wxFileFunctionsBuffer
); 
 346       if (wxFileExists (wxFileFunctionsBuffer
)) 
 348         return wxString(wxFileFunctionsBuffer
);        // Found! 
 352   return wxEmptyString
;                    // Not found 
 355 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) 
 357     wxString f 
= FindValidPath(file
); 
 358     if ( wxIsAbsolutePath(f
) ) 
 362     wxGetWorkingDirectory(wxStringBuffer(buf
, _MAXPATHLEN
), _MAXPATHLEN
); 
 364     if ( !wxEndsWithPathSeparator(buf
) ) 
 366         buf 
+= wxFILE_SEP_PATH
; 
 374 wxFileExists (const wxString
& filename
) 
 376     // we must use GetFileAttributes() instead of the ANSI C functions because 
 377     // it can cope with network (UNC) paths unlike them 
 378 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
 379     DWORD ret 
= ::GetFileAttributes(filename
); 
 381     return (ret 
!= (DWORD
)-1) && !(ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 384     return wxStat(filename
, &st
) == 0 && (st
.st_mode 
& S_IFREG
); 
 385 #endif // __WIN32__/!__WIN32__ 
 389 wxIsAbsolutePath (const wxString
& filename
) 
 391     if (filename 
!= wxT("")) 
 393 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 394         // Classic or Carbon CodeWarrior like 
 395         // Carbon with Apple DevTools is Unix like 
 397         // This seems wrong to me, but there is no fix. since 
 398         // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt" 
 399         // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR. 
 400         if (filename
.Find(':') != wxNOT_FOUND 
&& filename
[0] != ':') 
 403         // Unix like or Windows 
 404         if (filename
[0] == wxT('/')) 
 408         if ((filename
[0] == wxT('[') && filename
[1] != wxT('.'))) 
 411 #if defined(__WINDOWS__) || defined(__OS2__) 
 413         if (filename
[0] == wxT('\\') || (wxIsalpha (filename
[0]) && filename
[1] == wxT(':'))) 
 421  * Strip off any extension (dot something) from end of file, 
 422  * IF one exists. Inserts zero into buffer. 
 426 void wxStripExtension(wxChar 
*buffer
) 
 428   int len 
= wxStrlen(buffer
); 
 432     if (buffer
[i
] == wxT('.')) 
 441 void wxStripExtension(wxString
& buffer
) 
 443   size_t len 
= buffer
.Length(); 
 447     if (buffer
.GetChar(i
) == wxT('.')) 
 449       buffer 
= buffer
.Left(i
); 
 456 // Destructive removal of /./ and /../ stuff 
 457 wxChar 
*wxRealPath (wxChar 
*path
) 
 460   static const wxChar SEP 
= wxT('\\'); 
 461   wxUnix2DosFilename(path
); 
 463   static const wxChar SEP 
= wxT('/'); 
 465   if (path
[0] && path
[1]) { 
 466     /* MATTHEW: special case "/./x" */ 
 468     if (path
[2] == SEP 
&& path
[1] == wxT('.')) 
 476             if (p
[1] == wxT('.') && p
[2] == wxT('.') && (p
[3] == SEP 
|| p
[3] == wxT('\0'))) 
 479                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--) 
 484                 if (q
[0] == SEP 
&& (q
[1] != wxT('.') || q
[2] != wxT('.') || q
[3] != SEP
) 
 485                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 488                     if (path
[0] == wxT('\0')) 
 493 #if defined(__WXMSW__) || defined(__OS2__) 
 494                     /* Check that path[2] is NULL! */ 
 495                     else if (path
[1] == wxT(':') && !path
[2]) 
 504             else if (p
[1] == wxT('.') && (p
[2] == SEP 
|| p
[2] == wxT('\0'))) 
 513 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 515   if (filename 
== wxT("")) 
 516     return (wxChar 
*) NULL
; 
 518   if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer
, filename
))) { 
 519     wxChar  buf
[_MAXPATHLEN
]; 
 521     wxGetWorkingDirectory(buf
, WXSIZEOF(buf
)); 
 522     wxChar ch 
= buf
[wxStrlen(buf
) - 1]; 
 524     if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 525         wxStrcat(buf
, wxT("\\")); 
 528         wxStrcat(buf
, wxT("/")); 
 530     wxStrcat(buf
, wxFileFunctionsBuffer
); 
 531     return MYcopystring( wxRealPath(buf
) ); 
 533   return MYcopystring( wxFileFunctionsBuffer 
); 
 539    ~user/ => user's home dir 
 540    If the environment variable a = "foo" and b = "bar" then: 
 557 /* input name in name, pathname output to buf. */ 
 559 wxChar 
*wxExpandPath(wxChar 
*buf
, const wxChar 
*name
) 
 561     register wxChar 
*d
, *s
, *nm
; 
 562     wxChar          lnm
[_MAXPATHLEN
]; 
 565     // Some compilers don't like this line. 
 566 //    const wxChar    trimchars[] = wxT("\n \t"); 
 569     trimchars
[0] = wxT('\n'); 
 570     trimchars
[1] = wxT(' '); 
 571     trimchars
[2] = wxT('\t'); 
 575      const wxChar     SEP 
= wxT('\\'); 
 577      const wxChar     SEP 
= wxT('/'); 
 580     if (name 
== NULL 
|| *name 
== wxT('\0')) 
 582     nm 
= MYcopystring(name
); // Make a scratch copy 
 585     /* Skip leading whitespace and cr */ 
 586     while (wxStrchr((wxChar 
*)trimchars
, *nm
) != NULL
) 
 588     /* And strip off trailing whitespace and cr */ 
 589     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 590     while (q
-- && wxStrchr((wxChar 
*)trimchars
, *s
) != NULL
) 
 598     q 
= nm
[0] == wxT('\\') && nm
[1] == wxT('~'); 
 601     /* Expand inline environment variables */ 
 619     while ((*d
++ = *s
) != 0) { 
 621         if (*s 
== wxT('\\')) { 
 622             if ((*(d 
- 1) = *++s
)) { 
 630             // No env variables on WinCE 
 633         if (*s
++ == wxT('$') && (*s 
== wxT('{') || *s 
== wxT(')'))) 
 635         if (*s
++ == wxT('$')) 
 638             register wxChar  
*start 
= d
; 
 639             register int     braces 
= (*s 
== wxT('{') || *s 
== wxT('(')); 
 640             register wxChar  
*value
; 
 641             while ((*d
++ = *s
) != 0) 
 642                 if (braces 
? (*s 
== wxT('}') || *s 
== wxT(')')) : !(wxIsalnum(*s
) || *s 
== wxT('_')) ) 
 647             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 649                 for ((d 
= start 
- 1); (*d
++ = *value
++) != 0;) 
 663     /* Expand ~ and ~user */ 
 665     if (nm
[0] == wxT('~') && !q
) 
 668         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 670         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 671             if ((s 
= WXSTRINGCAST 
wxGetUserHome(wxT(""))) != NULL
) { 
 676         {                /* ~user/filename */ 
 677             register wxChar  
*nnm
; 
 678             register wxChar  
*home
; 
 679             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++) 
 683             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 684             was_sep 
= (*s 
== SEP
); 
 685             nnm 
= *s 
? s 
+ 1 : s
; 
 687         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 688             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 689                if (was_sep
) /* replace only if it was there: */ 
 700     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 702         while (wxT('\0') != (*d
++ = *s
++)) 
 705         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 709     while ((*d
++ = *s
++) != 0) 
 713     delete[] nm_tmp
; // clean up alloc 
 714     /* Now clean up the buffer */ 
 715     return wxRealPath(buf
); 
 718 /* Contract Paths to be build upon an environment variable 
 721    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 723    The call wxExpandPath can convert these back! 
 726 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 728   static wxChar dest
[_MAXPATHLEN
]; 
 730   if (filename 
== wxT("")) 
 731     return (wxChar 
*) NULL
; 
 733   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 735   wxUnix2DosFilename(dest
); 
 738   // Handle environment 
 742   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 743      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 745         wxStrcpy (wxFileFunctionsBuffer
, tcp 
+ wxStrlen (val
)); 
 748         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 749         wxStrcat (tcp
, wxT("}")); 
 750         wxStrcat (tcp
, wxFileFunctionsBuffer
); 
 754   // Handle User's home (ignore root homes!) 
 755   val 
= wxGetUserHome (user
); 
 759   const size_t len 
= wxStrlen(val
); 
 763   if (wxStrncmp(dest
, val
, len
) == 0) 
 765     wxStrcpy(wxFileFunctionsBuffer
, wxT("~")); 
 767            wxStrcat(wxFileFunctionsBuffer
, (const wxChar
*) user
); 
 768     wxStrcat(wxFileFunctionsBuffer
, dest 
+ len
); 
 769     wxStrcpy (dest
, wxFileFunctionsBuffer
); 
 775 // Return just the filename, not the path (basename) 
 776 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 779     wxString n 
= wxFileNameFromPath(p
); 
 781     return path 
+ p
.length() - n
.length(); 
 784 wxString 
wxFileNameFromPath (const wxString
& path
) 
 787     wxFileName::SplitPath(path
, NULL
, &name
, &ext
); 
 789     wxString fullname 
= name
; 
 792         fullname 
<< wxFILE_SEP_EXT 
<< ext
; 
 798 // Return just the directory, or NULL if no directory 
 800 wxPathOnly (wxChar 
*path
) 
 804         static wxChar buf
[_MAXPATHLEN
]; 
 807         wxStrcpy (buf
, path
); 
 809         int l 
= wxStrlen(path
); 
 812         // Search backward for a backward or forward slash 
 815 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 816             // Classic or Carbon CodeWarrior like 
 817             // Carbon with Apple DevTools is Unix like 
 818             if (path
[i
] == wxT(':') ) 
 824             // Unix like or Windows 
 825             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 832             if (path
[i
] == wxT(']')) 
 841 #if defined(__WXMSW__) || defined(__OS2__) 
 842         // Try Drive specifier 
 843         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 845             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 852     return (wxChar 
*) NULL
; 
 855 // Return just the directory, or NULL if no directory 
 856 wxString 
wxPathOnly (const wxString
& path
) 
 860         wxChar buf
[_MAXPATHLEN
]; 
 863         wxStrcpy (buf
, WXSTRINGCAST path
); 
 865         int l 
= path
.Length(); 
 868         // Search backward for a backward or forward slash 
 871 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 872             // Classic or Carbon CodeWarrior like 
 873             // Carbon with Apple DevTools is Unix like 
 874             if (path
[i
] == wxT(':') ) 
 877                 return wxString(buf
); 
 880             // Unix like or Windows 
 881             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 884                 return wxString(buf
); 
 888             if (path
[i
] == wxT(']')) 
 891                 return wxString(buf
); 
 897 #if defined(__WXMSW__) || defined(__OS2__) 
 898         // Try Drive specifier 
 899         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 901             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 904             return wxString(buf
); 
 908     return wxString(wxT("")); 
 911 // Utility for converting delimiters in DOS filenames to UNIX style 
 912 // and back again - or we get nasty problems with delimiters. 
 913 // Also, convert to lower case, since case is significant in UNIX. 
 915 #if defined(__WXMAC__) 
 916 wxString 
wxMacFSSpec2MacFilename( const FSSpec 
*spec 
) 
 922     OSStatus    theStatus 
= noErr
; 
 923     Boolean     isDirectory 
= FALSE
; 
 924     Str255    theParentPath 
= "\p"; 
 925     FSSpec      theParentSpec
; 
 928     char        theFileName
[FILENAME_MAX
]; 
 929     char        thePath
[FILENAME_MAX
]; 
 931     // we loose the long filename by merely copying the spec->name 
 932     // so try the built-ins, which only work if the file exists, but still... 
 934     theErr 
= FSpMakeFSRef(spec
, &theRef
); 
 935     if ( theErr 
== noErr 
) 
 938         fullURLRef 
= ::CFURLCreateFromFSRef(NULL
, &theRef
); 
 940         CFURLPathStyle pathstyle 
= kCFURLPOSIXPathStyle
; 
 942         CFURLPathStyle pathstyle 
= kCFURLHFSPathStyle
; 
 944         CFStringRef cfString 
= CFURLCopyFileSystemPath(fullURLRef
, pathstyle
); 
 945         ::CFRelease( fullURLRef 
) ; 
 946         return wxMacCFStringHolder(cfString
).AsString(wxFont::GetDefaultEncoding()); 
 951     // GD: Separate file name from path and make a FSRef to the parent 
 952     //     directory. This is necessary since FSRefs cannot reference files 
 953     //     that have not yet been created. 
 954     //     Based on example code from Apple Technical Note TN2022 
 955     //       http://developer.apple.com/technotes/tn/tn2022.html 
 957     // check whether we are converting a directory 
 958     isDirectory 
= ((spec
->name
)[spec
->name
[0]] == ':'); 
 959     // count length of file name 
 960     for (i 
= spec
->name
[0] - (isDirectory 
? 1 : 0); ((spec
->name
[i
] != ':') && (i 
> 0)); i
--); 
 962     //   prepend path separator since it will later be appended to the path 
 963     theFileName
[0] = wxFILE_SEP_PATH
; 
 964     for (j 
= i 
+ 1; j 
<= spec
->name
[0] - (isDirectory 
? 1 : 0); j
++) { 
 965         theFileName
[j 
- i
] = spec
->name
[j
]; 
 967     theFileName
[j 
- i
] = '\0'; 
 969     for (j 
= 1; j 
<= i
; j
++) { 
 970         theParentPath
[++theParentPath
[0]] = spec
->name
[j
]; 
 972     theErr 
= FSMakeFSSpec(spec
->vRefNum
, spec
->parID
, theParentPath
, &theParentSpec
); 
 973     if (theErr 
== noErr
) { 
 974         // convert the FSSpec to an FSRef 
 975         theErr 
= FSpMakeFSRef(&theParentSpec
, &theParentRef
); 
 977     if (theErr 
== noErr
) { 
 978         // get the POSIX path associated with the FSRef 
 979         theStatus 
= FSRefMakePath(&theParentRef
, 
 980                                   (UInt8 
*)thePath
, sizeof(thePath
)); 
 982     if (theStatus 
== noErr
) { 
 983         // append file name to path 
 984         //   includes previously prepended path separator 
 985         strcat(thePath
, theFileName
); 
 988     // create path string for return value 
 989     wxString 
result( thePath 
, wxConvLocal
) ; 
 994     // get length of path and allocate handle 
 995     FSpGetFullPath( spec 
, &length 
, &myPath 
) ; 
 996     ::SetHandleSize( myPath 
, length 
+ 1 ) ; 
 998     (*myPath
)[length
] = 0 ; 
 999     if ((length 
> 0) && ((*myPath
)[length
-1] == ':')) 
1000         (*myPath
)[length
-1] = 0 ; 
1002     // create path string for return value 
1003     wxString 
result( *myPath 
, wxConvLocal
) ; 
1005     // free allocated handle 
1006     ::HUnlock( myPath 
) ; 
1007     ::DisposeHandle( myPath 
) ; 
1013 // Mac file names are POSIX (Unix style) under Darwin 
1014 // therefore the conversion functions below are not needed 
1016 static wxChar sMacFileNameConversion
[ 1000 ] ; 
1017 static char scMacFileNameConversion
[ 1000 ] ; 
1020 void wxMacFilename2FSSpec( const char *path 
, FSSpec 
*spec 
) 
1022     OSStatus err 
= noErr 
; 
1026     // get the FSRef associated with the POSIX path 
1027     err 
= FSPathMakeRef((const UInt8 
*) path
, &theRef
, NULL
); 
1028     // convert the FSRef to an FSSpec 
1029     err 
= FSGetCatalogInfo(&theRef
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
1031     if ( strchr( path 
, ':' ) == NULL 
) 
1033         // try whether it is a volume / or a mounted volume 
1034         strncpy( scMacFileNameConversion 
, path 
, 1000 ) ; 
1035         scMacFileNameConversion
[998] = 0 ; 
1036         strcat( scMacFileNameConversion 
, ":" ) ; 
1037         err 
= FSpLocationFromFullPath( strlen(scMacFileNameConversion
) , scMacFileNameConversion 
, spec 
) ; 
1041         err 
= FSpLocationFromFullPath( strlen(path
) , path 
, spec 
) ; 
1047 WXDLLEXPORT 
void wxMacFilename2FSSpec( const wxChar 
*path 
, FSSpec 
*spec 
)  
1049     return wxMacFilename2FSSpec( wxConvFile
.cWC2MB(path
) , spec 
) ; 
1055 wxString 
wxMac2UnixFilename (const wxChar 
*str
) 
1057     wxChar 
*s 
= sMacFileNameConversion 
; 
1058     wxStrcpy( s 
, str 
) ; 
1061         memmove( s
+1 , s 
,wxStrlen( s 
) + 1 * sizeof(wxChar
)) ; 
1072                 *s 
= wxTolower(*s
);        // Case INDEPENDENT 
1076     return wxString(sMacFileNameConversion
) ; 
1079 wxString 
wxUnix2MacFilename (const wxChar 
*str
) 
1081     wxChar 
*s 
= sMacFileNameConversion 
; 
1082     wxStrcpy( s 
, str 
) ; 
1087             // relative path , since it goes on with slash which is translated to a : 
1088             memmove( s 
, s
+1 ,wxStrlen( s 
) * sizeof(wxChar
)) ; 
1090         else if ( *s 
== '/' ) 
1092             // absolute path -> on mac just start with the drive name 
1093             memmove( s 
, s
+1 ,wxStrlen( s 
) * sizeof(wxChar
) ) ; 
1097             wxASSERT_MSG( 1 , wxT("unkown path beginning") ) ; 
1101             if (*s 
== '/' || *s 
== '\\') 
1103                 // convert any back-directory situations 
1104                 if ( *(s
+1) == '.' && *(s
+2) == '.' && ( (*(s
+3) == '/' || *(s
+3) == '\\') ) ) 
1107                     memmove( s
+1 , s
+3 ,(wxStrlen( s
+3 ) + 1)*sizeof(wxChar
) ) ; 
1115     return wxString(sMacFileNameConversion
) ; 
1118 wxString 
wxMacFSSpec2UnixFilename( const FSSpec 
*spec 
) 
1120     return wxMac2UnixFilename( wxMacFSSpec2MacFilename( spec
) ) ; 
1123 void wxUnixFilename2FSSpec( const wxChar 
*path 
, FSSpec 
*spec 
) 
1125     wxString var 
= wxUnix2MacFilename( path 
) ; 
1126     wxMacFilename2FSSpec( var 
, spec 
) ; 
1128 #endif // ! __DARWIN__ 
1133 wxDos2UnixFilename (wxChar 
*s
) 
1142           *s 
= wxTolower (*s
);        // Case INDEPENDENT 
1149 #if defined(__WXMSW__) || defined(__OS2__) 
1150 wxUnix2DosFilename (wxChar 
*s
) 
1152 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
) ) 
1155 // Yes, I really mean this to happen under DOS only! JACS 
1156 #if defined(__WXMSW__) || defined(__OS2__) 
1167 // Concatenate two files to form third 
1169 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
1172   if ( !wxGetTempFileName( wxT("cat"), outfile
) ) 
1175   FILE *fp1 
wxDUMMY_INITIALIZE(NULL
); 
1178   // Open the inputs and outputs 
1179   if ((fp1 
= wxFopen ( file1
, wxT("rb"))) == NULL 
|| 
1180       (fp2 
= wxFopen ( file2
, wxT("rb"))) == NULL 
|| 
1181       (fp3 
= wxFopen ( outfile
, wxT("wb"))) == NULL
) 
1193   while ((ch 
= getc (fp1
)) != EOF
) 
1194     (void) putc (ch
, fp3
); 
1197   while ((ch 
= getc (fp2
)) != EOF
) 
1198     (void) putc (ch
, fp3
); 
1202   bool result 
= wxRenameFile(outfile
, file3
); 
1208 wxCopyFile (const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1210 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1211     // CopyFile() copies file attributes and modification time too, so use it 
1212     // instead of our code if available 
1214     // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite 
1215     if ( !::CopyFile(file1
, file2
, !overwrite
) ) 
1217         wxLogSysError(_("Failed to copy the file '%s' to '%s'"), 
1218                       file1
.c_str(), file2
.c_str()); 
1222 #elif defined(__OS2__) 
1223     if ( ::DosCopy(file2
, file2
, overwrite 
? DCPY_EXISTING 
: 0) != 0 ) 
1228     // get permissions of file1 
1229     if ( wxStat( file1
.c_str(), &fbuf
) != 0 ) 
1231         // the file probably doesn't exist or we haven't the rights to read 
1233         wxLogSysError(_("Impossible to get permissions for file '%s'"), 
1238     // open file1 for reading 
1239     wxFile 
fileIn(file1
, wxFile::read
); 
1240     if ( !fileIn
.IsOpened() ) 
1243     // remove file2, if it exists. This is needed for creating 
1244     // file2 with the correct permissions in the next step 
1245     if ( wxFileExists(file2
)  && (!overwrite 
|| !wxRemoveFile(file2
))) 
1247         wxLogSysError(_("Impossible to overwrite the file '%s'"), 
1253     // reset the umask as we want to create the file with exactly the same 
1254     // permissions as the original one 
1255     mode_t oldUmask 
= umask( 0 ); 
1258     // create file2 with the same permissions than file1 and open it for 
1262     if ( !fileOut
.Create(file2
, overwrite
, fbuf
.st_mode 
& 0777) ) 
1266     /// restore the old umask 
1270     // copy contents of file1 to file2 
1275         count 
= fileIn
.Read(buf
, WXSIZEOF(buf
)); 
1276         if ( fileIn
.Error() ) 
1283         if ( fileOut
.Write(buf
, count
) < count 
) 
1287     // we can expect fileIn to be closed successfully, but we should ensure 
1288     // that fileOut was closed as some write errors (disk full) might not be 
1289     // detected before doing this 
1290     if ( !fileIn
.Close() || !fileOut
.Close() ) 
1293 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 
1294     // no chmod in VA.  Should be some permission API for HPFS386 partitions 
1296     if ( chmod(OS_FILENAME(file2
), fbuf
.st_mode
) != 0 ) 
1298         wxLogSysError(_("Impossible to set permissions for the file '%s'"), 
1302 #endif // OS/2 || Mac 
1303 #endif // __WXMSW__ && __WIN32__ 
1309 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
1312     // Normal system call 
1313   if ( wxRename (file1
, file2
) == 0 ) 
1318   if (wxCopyFile(file1
, file2
)) { 
1319     wxRemoveFile(file1
); 
1326 bool wxRemoveFile(const wxString
& file
) 
1328 #if defined(__VISUALC__) \ 
1329  || defined(__BORLANDC__) \ 
1330  || defined(__WATCOMC__) \ 
1331  || defined(__DMC__) \ 
1332  || defined(__GNUWIN32__) \ 
1333  || (defined(__MWERKS__) && defined(__MSL__)) 
1334   int res 
= wxRemove(file
); 
1335 #elif defined(__WXMAC__) 
1336   int res 
= unlink(wxFNCONV(file
)); 
1338   int res 
= unlink(OS_FILENAME(file
)); 
1344 bool wxMkdir(const wxString
& dir
, int perm
) 
1346 #if defined(__WXMAC__) && !defined(__UNIX__) 
1347   return (mkdir( wxFNCONV(dir
) , 0 ) == 0); 
1349     const wxChar 
*dirname 
= dir
.c_str(); 
1351     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 
1352     // for the GNU compiler 
1353 #if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) 
1355     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1357     if ( mkdir(wxFNCONV(dirname
)) != 0 ) 
1359 #elif defined(__OS2__) 
1360     if (::DosCreateDir((PSZ
)dirname
, NULL
) != 0) // enhance for EAB's?? 
1361 #elif defined(__DOS__) 
1362   #if defined(__WATCOMC__) 
1364     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1365   #elif defined(__DJGPP__) 
1366     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1368     #error "Unsupported DOS compiler!" 
1370 #else  // !MSW, !DOS and !OS/2 VAC++ 
1373     if ( !CreateDirectory(dirname
, NULL
) ) 
1375     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1379         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1388 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1391     return FALSE
; //to be changed since rmdir exists in VMS7.x 
1392 #elif defined(__OS2__) 
1393     return (::DosDeleteDir((PSZ
)dir
.c_str()) == 0); 
1397     return (CreateDirectory(dir
, NULL
) != 0); 
1399     return (wxRmDir(OS_FILENAME(dir
)) == 0); 
1405 // does the path exists? (may have or not '/' or '\\' at the end) 
1406 bool wxPathExists(const wxChar 
*pszPathName
) 
1408     wxString 
strPath(pszPathName
); 
1410 #if defined(__WINDOWS__) || defined(__OS2__) 
1411     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
1412     // so remove all trailing backslashes from the path - but don't do this for 
1413     // the pathes "d:\" (which are different from "d:") nor for just "\" 
1414     while ( wxEndsWithPathSeparator(strPath
) ) 
1416         size_t len 
= strPath
.length(); 
1417         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == _T(':')) ) 
1420         strPath
.Truncate(len 
- 1); 
1422 #endif // __WINDOWS__ 
1425     // OS/2 can't handle "d:", it wants either "d:\" or "d:." 
1426     if (strPath
.length() == 2 && strPath
[1u] == _T(':')) 
1430 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1431     // stat() can't cope with network paths 
1432     DWORD ret 
= ::GetFileAttributes(strPath
); 
1434     return (ret 
!= (DWORD
)-1) && (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
1438 #ifndef __VISAGECPP__ 
1439     return wxStat(strPath
.c_str(), &st
) == 0 && ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
1441     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
1442     return wxStat(pszPathName
, &st
) == 0 && (st
.st_mode 
== S_IFDIR
); 
1445 #endif // __WIN32__/!__WIN32__ 
1448 // Get a temporary filename, opening and closing the file. 
1449 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1451     wxString filename 
= wxFileName::CreateTempFileName(prefix
); 
1452     if ( filename
.empty() ) 
1456         wxStrcpy(buf
, filename
); 
1458         buf 
= MYcopystring(filename
); 
1463 bool wxGetTempFileName(const wxString
& prefix
, wxString
& buf
) 
1465     buf 
= wxFileName::CreateTempFileName(prefix
); 
1467     return !buf
.empty(); 
1470 // Get first file name matching given wild card. 
1472 static wxDir 
*gs_dir 
= NULL
; 
1473 static wxString gs_dirPath
; 
1475 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1477     wxSplitPath(spec
, &gs_dirPath
, NULL
, NULL
); 
1478     if ( gs_dirPath
.IsEmpty() ) 
1479         gs_dirPath 
= wxT("."); 
1480     if ( !wxEndsWithPathSeparator(gs_dirPath 
) ) 
1481         gs_dirPath 
<< wxFILE_SEP_PATH
; 
1485     gs_dir 
= new wxDir(gs_dirPath
); 
1487     if ( !gs_dir
->IsOpened() ) 
1489         wxLogSysError(_("Can not enumerate files '%s'"), spec
); 
1490         return wxEmptyString
; 
1496         case wxDIR
:  dirFlags 
= wxDIR_DIRS
; break; 
1497         case wxFILE
: dirFlags 
= wxDIR_FILES
; break; 
1498         default:     dirFlags 
= wxDIR_DIRS 
| wxDIR_FILES
; break; 
1502     gs_dir
->GetFirst(&result
, wxFileNameFromPath(wxString(spec
)), dirFlags
); 
1503     if ( result
.IsEmpty() ) 
1509     return gs_dirPath 
+ result
; 
1512 wxString 
wxFindNextFile() 
1514     wxASSERT_MSG( gs_dir
, wxT("You must call wxFindFirstFile before!") ); 
1517     gs_dir
->GetNext(&result
); 
1519     if ( result
.IsEmpty() ) 
1525     return gs_dirPath 
+ result
; 
1529 // Get current working directory. 
1530 // If buf is NULL, allocates space using new, else 
1532 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1539         buf 
= new wxChar
[sz 
+ 1]; 
1542     bool ok 
wxDUMMY_INITIALIZE(FALSE
); 
1544     // for the compilers which have Unicode version of _getcwd(), call it 
1545     // directly, for the others call the ANSI version and do the translation 
1548 #else // wxUSE_UNICODE 
1549     bool needsANSI 
= TRUE
; 
1551     #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU 
1552         // This is not legal code as the compiler 
1553         // is allowed destroy the wxCharBuffer. 
1554         // wxCharBuffer c_buffer(sz); 
1555         // char *cbuf = (char*)(const char*)c_buffer; 
1556         char cbuf
[_MAXPATHLEN
]; 
1560         #if wxUSE_UNICODE_MSLU 
1561             if ( wxGetOsVersion() != wxWIN95 
) 
1563             char *cbuf 
= NULL
; // never really used because needsANSI will always be FALSE 
1566                 ok 
= _wgetcwd(buf
, sz
) != NULL
; 
1572 #endif // wxUSE_UNICODE 
1574     #if defined(_MSC_VER) || defined(__MINGW32__) 
1575         ok 
= _getcwd(cbuf
, sz
) != NULL
; 
1576     #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1581         pb
.ioNamePtr 
= (StringPtr
) &fileName
; 
1583         pb
.ioRefNum 
= LMGetCurApRefNum(); 
1585         error 
= PBGetFCBInfoSync(&pb
); 
1586         if ( error 
== noErr 
) 
1588             cwdSpec
.vRefNum 
= pb
.ioFCBVRefNum
; 
1589             cwdSpec
.parID 
= pb
.ioFCBParID
; 
1590             cwdSpec
.name
[0] = 0 ; 
1591             wxString res 
= wxMacFSSpec2MacFilename( &cwdSpec 
) ; 
1592                         wxStrcpy( buf 
, res 
) ;                  
1599     #elif defined(__OS2__) 
1601         ULONG ulDriveNum 
= 0; 
1602         ULONG ulDriveMap 
= 0; 
1603         rc 
= ::DosQueryCurrentDisk(&ulDriveNum
, &ulDriveMap
); 
1608             rc 
= ::DosQueryCurrentDir( 0 // current drive 
1612             cbuf
[0] = 'A' + (ulDriveNum 
- 1); 
1617     #else // !Win32/VC++ !Mac !OS2 
1618         ok 
= getcwd(cbuf
, sz
) != NULL
; 
1621     #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) 
1622         // finally convert the result to Unicode if needed 
1623         wxConvFile
.MB2WC(buf
, cbuf
, sz
); 
1624     #endif // wxUSE_UNICODE 
1629         wxLogSysError(_("Failed to get the working directory")); 
1631         // VZ: the old code used to return "." on error which didn't make any 
1632         //     sense at all to me - empty string is a better error indicator 
1633         //     (NULL might be even better but I'm afraid this could lead to 
1634         //     problems with the old code assuming the return is never NULL) 
1637     else // ok, but we might need to massage the path into the right format 
1640         // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths 
1641         //     with / deliminers. We don't like that. 
1642         for (wxChar 
*ch 
= buf
; *ch
; ch
++) 
1644             if (*ch 
== wxT('/')) 
1649 // MBN: we hope that in the case the user is compiling a GTK+/Motif app, 
1650 //      he needs Unix as opposed to Win32 pathnames 
1651 #if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) 
1652         // another example of DOS/Unix mix (Cygwin) 
1653         wxString pathUnix 
= buf
; 
1654         cygwin_conv_to_full_win32_path(pathUnix
, buf
); 
1655 #endif // __CYGWIN__ 
1670     wxChar 
*buffer 
= new wxChar
[_MAXPATHLEN
]; 
1671     wxGetWorkingDirectory(buffer
, _MAXPATHLEN
); 
1672     wxString 
str( buffer 
); 
1678 bool wxSetWorkingDirectory(const wxString
& d
) 
1680 #if defined(__OS2__) 
1681     return (::DosSetCurrentDir((PSZ
)d
.c_str()) == 0); 
1682 #elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) 
1683     return (chdir(wxFNSTRINGCAST d
.fn_str()) == 0); 
1684 #elif defined(__WINDOWS__) 
1688     // No equivalent in WinCE 
1691     return (bool)(SetCurrentDirectory(d
) != 0); 
1694     // Must change drive, too. 
1695     bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1698         wxChar firstChar 
= d
[0]; 
1702             firstChar 
= firstChar 
- 32; 
1704         // To a drive number 
1705         unsigned int driveNo 
= firstChar 
- 64; 
1708             unsigned int noDrives
; 
1709             _dos_setdrive(driveNo
, &noDrives
); 
1712     bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1720 // Get the OS directory if appropriate (such as the Windows directory). 
1721 // On non-Windows platform, probably just return the empty string. 
1722 wxString 
wxGetOSDirectory() 
1725     return wxString(wxT("\\Windows")); 
1726 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1728     GetWindowsDirectory(buf
, 256); 
1729     return wxString(buf
); 
1730 #elif defined(__WXMAC__) 
1731     return wxMacFindFolder(kOnSystemDisk
, 'macs', false); 
1733     return wxEmptyString
; 
1737 bool wxEndsWithPathSeparator(const wxChar 
*pszFileName
) 
1739     size_t len 
= wxStrlen(pszFileName
); 
1741     return len 
&& wxIsPathSeparator(pszFileName
[len 
- 1]); 
1744 // find a file in a list of directories, returns FALSE if not found 
1745 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1747     // we assume that it's not empty 
1748     wxCHECK_MSG( !wxIsEmpty(pszFile
), FALSE
, 
1749                  _T("empty file name in wxFindFileInPath")); 
1751     // skip path separator in the beginning of the file name if present 
1752     if ( wxIsPathSeparator(*pszFile
) ) 
1755     // copy the path (strtok will modify it) 
1756     wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1757     wxStrcpy(szPath
, pszPath
); 
1760     wxChar 
*pc
, *save_ptr
; 
1761     for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1763           pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1765         // search for the file in this directory 
1767         if ( !wxEndsWithPathSeparator(pc
) ) 
1768             strFile 
+= wxFILE_SEP_PATH
; 
1771         if ( wxFileExists(strFile
) ) { 
1777     // suppress warning about unused variable save_ptr when wxStrtok() is a 
1778     // macro which throws away its third argument 
1783     return pc 
!= NULL
;  // if TRUE => we breaked from the loop 
1786 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1791     // it can be empty, but it shouldn't be NULL 
1792     wxCHECK_RET( pszFileName
, wxT("NULL file name in wxSplitPath") ); 
1794     wxFileName::SplitPath(pszFileName
, pstrPath
, pstrName
, pstrExt
); 
1797 time_t WXDLLEXPORT 
wxFileModificationTime(const wxString
& filename
) 
1800     FILETIME creationTime
, lastAccessTime
, lastWriteTime
; 
1801     HANDLE fileHandle 
= ::CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, 
1802         0, FILE_ATTRIBUTE_NORMAL
, 0); 
1803     if (fileHandle 
== INVALID_HANDLE_VALUE
) 
1807         if (GetFileTime(fileHandle
, & creationTime
, & lastAccessTime
, & lastWriteTime
)) 
1809             CloseHandle(fileHandle
); 
1811             wxDateTime dateTime
; 
1813             if ( !::FileTimeToLocalFileTime(&lastWriteTime
, &ftLocal
) ) 
1815                 wxLogLastError(_T("FileTimeToLocalFileTime")); 
1819             if ( !::FileTimeToSystemTime(&ftLocal
, &st
) ) 
1821                 wxLogLastError(_T("FileTimeToSystemTime")); 
1824             dateTime
.Set(st
.wDay
, wxDateTime::Month(st
.wMonth 
- 1), st
.wYear
, 
1825                 st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
); 
1826             return dateTime
.GetTicks(); 
1833     wxStat( filename
, &buf
); 
1835     return buf
.st_mtime
; 
1840 //------------------------------------------------------------------------ 
1841 // wild character routines 
1842 //------------------------------------------------------------------------ 
1844 bool wxIsWild( const wxString
& pattern 
) 
1846     wxString tmp 
= pattern
; 
1847     wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
1852         case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): 
1863 * Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU> 
1865 * The match procedure is public domain code (from ircII's reg.c) 
1868 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1872                 /* Match if both are empty. */ 
1876         const wxChar 
*m 
= pat
.c_str(), 
1887         if (dot_special 
&& (*n 
== wxT('.'))) 
1889                 /* Never match so that hidden Unix files 
1890                  * are never found. */ 
1904                 else if (*m 
== wxT('?')) 
1912                         if (*m 
== wxT('\\')) 
1915                                 /* Quoting "nothing" is a bad thing */ 
1922                                 * If we are out of both strings or we just 
1923                                 * saw a wildcard, then we can say we have a 
1934                         * We could check for *n == NULL at this point, but 
1935                         * since it's more common to have a character there, 
1936                         * check to see if they match first (m and n) and 
1937                         * then if they don't match, THEN we can check for 
1955                                 * If there are no more characters in the 
1956                                 * string, but we still need to find another 
1957                                 * character (*m != NULL), then it will be 
1958                                 * impossible to match it 
1965                                         if (*np 
== wxT(' ')) 
1991     #pragma warning(default:4706)   // assignment within conditional expression