1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/filefn.cpp 
   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 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #include "wx/filefn.h" 
  36 #include "wx/filename.h" 
  39 #include "wx/tokenzr.h" 
  41 // there are just too many of those... 
  43     #pragma warning(disable:4706)   // assignment within conditional expression 
  50 #if !wxONLY_WATCOM_EARLIER_THAN(1,4) 
  51     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  56 #if defined(__WXMAC__) 
  57     #include  "wx/mac/private.h"  // includes mac headers 
  61     #include "wx/msw/private.h" 
  62     #include "wx/msw/mslu.h" 
  64     // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() 
  66     // note that it must be included after <windows.h> 
  69             #include <sys/cygwin.h> 
  71     #endif // __GNUWIN32__ 
  73     // io.h is needed for _get_osfhandle() 
  74     // Already included by filefn.h for many Windows compilers 
  75     #if defined __MWERKS__ || defined __CYGWIN__ 
  84 // TODO: Borland probably has _wgetcwd as well? 
  89 // ---------------------------------------------------------------------------- 
  91 // ---------------------------------------------------------------------------- 
  94     #define _MAXPATHLEN 1024 
  98 #    include "MoreFilesX.h" 
 101 // ---------------------------------------------------------------------------- 
 103 // ---------------------------------------------------------------------------- 
 105 // MT-FIXME: get rid of this horror and all code using it 
 106 static wxChar wxFileFunctionsBuffer
[4*_MAXPATHLEN
]; 
 108 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
 110 // VisualAge C++ V4.0 cannot have any external linkage const decs 
 111 // in headers included by more than one primary source 
 113 const int wxInvalidOffset 
= -1; 
 116 // ---------------------------------------------------------------------------- 
 118 // ---------------------------------------------------------------------------- 
 120 // translate the filenames before passing them to OS functions 
 121 #define OS_FILENAME(s) (s.fn_str()) 
 123 // ============================================================================ 
 125 // ============================================================================ 
 127 // ---------------------------------------------------------------------------- 
 128 // wrappers around standard POSIX functions 
 129 // ---------------------------------------------------------------------------- 
 131 #ifdef wxNEED_WX_UNISTD_H 
 133 WXDLLEXPORT 
int wxStat( const wxChar 
*file_name
, wxStructStat 
*buf 
) 
 135     return stat( wxConvFile
.cWX2MB( file_name 
), buf 
); 
 138 WXDLLEXPORT 
int wxLstat( const wxChar 
*file_name
, wxStructStat 
*buf 
) 
 140     return lstat( wxConvFile
.cWX2MB( file_name 
), buf 
); 
 143 WXDLLEXPORT 
int wxAccess( const wxChar 
*pathname
, int mode 
) 
 145     return access( wxConvFile
.cWX2MB( pathname 
), mode 
); 
 148 WXDLLEXPORT 
int wxOpen( const wxChar 
*pathname
, int flags
, mode_t mode 
) 
 150     return open( wxConvFile
.cWX2MB( pathname 
), flags
, mode 
); 
 153 #endif // wxNEED_WX_UNISTD_H 
 155 #if wxUSE_UNICODE && defined __BORLANDC__ \ 
 156     && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 
 158 // BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only 
 159 // regardless of the mode parameter. This hack works around the problem by 
 160 // setting the mode with _wchmod. 
 162 int wxOpen(const wchar_t *pathname
, int flags
, mode_t mode
) 
 166     // we only want to fix the mode when the file is actually created, so 
 167     // when creating first try doing it O_EXCL so we can tell if the file 
 168     // was already there. 
 169     if ((flags 
& O_CREAT
) && !(flags 
& O_EXCL
) && (mode 
& wxS_IWUSR
) != 0) 
 172     int fd 
= _wopen(pathname
, flags 
| moreflags
, mode
); 
 174     // the file was actually created and needs fixing 
 175     if (fd 
!= -1 && (flags 
& O_CREAT
) != 0 && (mode 
& wxS_IWUSR
) != 0) 
 178         _wchmod(pathname
, mode
); 
 179         fd 
= _wopen(pathname
, flags 
& ~(O_EXCL 
| O_CREAT
)); 
 181     // the open failed, but it may have been because the added O_EXCL stopped 
 182     // the opening of an existing file, so try again without. 
 183     else if (fd 
== -1 && moreflags 
!= 0) 
 185         fd 
= _wopen(pathname
, flags 
& ~O_CREAT
); 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 bool wxPathList::Add(const wxString
& path
) 
 199     // add a path separator to force wxFileName to interpret it always as a directory 
 200     // (i.e. if we are called with '/home/user' we want to consider it a folder and 
 201     // not, as wxFileName would consider, a filename). 
 202     wxFileName 
fn(path 
+ wxFileName::GetPathSeparator()); 
 204     // add only normalized relative/absolute paths 
 205     // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to 
 206     //     normalize paths which starts with ".." (which can be normalized only if 
 207     //     we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). 
 208     if (!fn
.Normalize(wxPATH_NORM_TILDE
|wxPATH_NORM_LONG
|wxPATH_NORM_ENV_VARS
)) 
 211     wxString toadd 
= fn
.GetPath(); 
 212     if (Index(toadd
) == wxNOT_FOUND
) 
 213         wxArrayString::Add(toadd
);      // do not add duplicates 
 218 void wxPathList::Add(const wxArrayString 
&arr
) 
 220     for (size_t j
=0; j 
< arr
.GetCount(); j
++) 
 224 // Add paths e.g. from the PATH environment variable 
 225 void wxPathList::AddEnvList (const wxString
& WXUNUSED_IN_WINCE(envVariable
)) 
 227     // No environment variables on WinCE 
 230     // The space has been removed from the tokenizers, otherwise a 
 231     // path such as "C:\Program Files" would be split into 2 paths: 
 232     // "C:\Program" and "Files"; this is true for both Windows and Unix. 
 234     static const wxChar PATH_TOKS
[] = 
 235 #if defined(__WINDOWS__) || defined(__OS2__) 
 236         wxT(";"); // Don't separate with colon in DOS (used for drive) 
 242     if ( wxGetEnv(envVariable
, &val
) ) 
 244         // split into an array of string the value of the env var 
 245         wxArrayString arr 
= wxStringTokenize(val
, PATH_TOKS
); 
 246         WX_APPEND_ARRAY(*this, arr
); 
 248 #endif // !__WXWINCE__ 
 251 // Given a full filename (with path), ensure that that file can 
 252 // be accessed again USING FILENAME ONLY by adding the path 
 253 // to the list if not already there. 
 254 bool wxPathList::EnsureFileAccessible (const wxString
& path
) 
 256     return Add(wxPathOnly(path
)); 
 259 #if WXWIN_COMPATIBILITY_2_6 
 260 bool wxPathList::Member (const wxString
& path
) const 
 262     return Index(path
) != wxNOT_FOUND
; 
 266 wxString 
wxPathList::FindValidPath (const wxString
& file
) const 
 268     // normalize the given string as it could be a path + a filename 
 269     // and not only a filename 
 273     // NB: normalize without making absolute otherwise calling this function with 
 274     //     e.g. "b/c.txt" would result in removing the directory 'b' and the for loop 
 275     //     below would only add to the paths of this list the 'c.txt' part when doing 
 276     //     the existence checks... 
 277     // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) 
 278     if (!fn
.Normalize(wxPATH_NORM_TILDE
|wxPATH_NORM_LONG
|wxPATH_NORM_ENV_VARS
)) 
 279         return wxEmptyString
; 
 281     wxASSERT_MSG(!fn
.IsDir(), wxT("Cannot search for directories; only for files")); 
 283         strend 
= fn
.GetFullName();      // search for the file name and ignore the path part 
 285         strend 
= fn
.GetFullPath(); 
 287     for (size_t i
=0; i
<GetCount(); i
++) 
 289         wxString strstart 
= Item(i
); 
 290         if (!strstart
.IsEmpty() && strstart
.Last() != wxFileName::GetPathSeparator()) 
 291             strstart 
+= wxFileName::GetPathSeparator(); 
 293         if (wxFileExists(strstart 
+ strend
)) 
 294             return strstart 
+ strend
;        // Found! 
 297     return wxEmptyString
;                    // Not found 
 300 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) const 
 302     wxString f 
= FindValidPath(file
); 
 303     if ( f
.empty() || wxIsAbsolutePath(f
) ) 
 306     wxString buf 
= ::wxGetCwd(); 
 308     if ( !wxEndsWithPathSeparator(buf
) ) 
 310         buf 
+= wxFILE_SEP_PATH
; 
 317 // ---------------------------------------------------------------------------- 
 318 // miscellaneous global functions (TOFIX!) 
 319 // ---------------------------------------------------------------------------- 
 321 static inline wxChar
* MYcopystring(const wxString
& s
) 
 323     wxChar
* copy 
= new wxChar
[s
.length() + 1]; 
 324     return wxStrcpy(copy
, s
.c_str()); 
 327 static inline wxChar
* MYcopystring(const wxChar
* s
) 
 329     wxChar
* copy 
= new wxChar
[wxStrlen(s
) + 1]; 
 330     return wxStrcpy(copy
, s
); 
 335 wxFileExists (const wxString
& filename
) 
 337 #if defined(__WXPALMOS__) 
 339 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
 340     // we must use GetFileAttributes() instead of the ANSI C functions because 
 341     // it can cope with network (UNC) paths unlike them 
 342     DWORD ret 
= ::GetFileAttributes(filename
); 
 344     return (ret 
!= (DWORD
)-1) && !(ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 347         #define S_ISREG(mode) ((mode) & S_IFREG) 
 350 #ifndef wxNEED_WX_UNISTD_H 
 351     return (wxStat( filename
.fn_str() , &st
) == 0 && S_ISREG(st
.st_mode
)) 
 353       || (errno 
== EACCES
) // if access is denied something with that name 
 354                             // exists and is opened in exclusive mode. 
 358     return wxStat( filename 
, &st
) == 0 && S_ISREG(st
.st_mode
); 
 360 #endif // __WIN32__/!__WIN32__ 
 364 wxIsAbsolutePath (const wxString
& filename
) 
 366     if (!filename
.empty()) 
 368 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 369         // Classic or Carbon CodeWarrior like 
 370         // Carbon with Apple DevTools is Unix like 
 372         // This seems wrong to me, but there is no fix. since 
 373         // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt" 
 374         // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR. 
 375         if (filename
.Find(':') != wxNOT_FOUND 
&& filename
[0] != ':') 
 378         // Unix like or Windows 
 379         if (filename
[0] == wxT('/')) 
 383         if ((filename
[0] == wxT('[') && filename
[1] != wxT('.'))) 
 386 #if defined(__WINDOWS__) || defined(__OS2__) 
 388         if (filename
[0] == wxT('\\') || (wxIsalpha (filename
[0]) && filename
[1] == wxT(':'))) 
 396  * Strip off any extension (dot something) from end of file, 
 397  * IF one exists. Inserts zero into buffer. 
 401 void wxStripExtension(wxChar 
*buffer
) 
 403     int len 
= wxStrlen(buffer
); 
 407         if (buffer
[i
] == wxT('.')) 
 416 void wxStripExtension(wxString
& buffer
) 
 418     //RN:  Be careful about the handling the case where 
 419     //buffer.length() == 0 
 420     for(size_t i 
= buffer
.length() - 1; i 
!= wxString::npos
; --i
) 
 422         if (buffer
.GetChar(i
) == wxT('.')) 
 424           buffer 
= buffer
.Left(i
); 
 430 // Destructive removal of /./ and /../ stuff 
 431 wxChar 
*wxRealPath (wxChar 
*path
) 
 434   static const wxChar SEP 
= wxT('\\'); 
 435   wxUnix2DosFilename(path
); 
 437   static const wxChar SEP 
= wxT('/'); 
 439   if (path
[0] && path
[1]) { 
 440     /* MATTHEW: special case "/./x" */ 
 442     if (path
[2] == SEP 
&& path
[1] == wxT('.')) 
 450             if (p
[1] == wxT('.') && p
[2] == wxT('.') && (p
[3] == SEP 
|| p
[3] == wxT('\0'))) 
 453                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--) 
 458                 if (q
[0] == SEP 
&& (q
[1] != wxT('.') || q
[2] != wxT('.') || q
[3] != SEP
) 
 459                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 462                     if (path
[0] == wxT('\0')) 
 467 #if defined(__WXMSW__) || defined(__OS2__) 
 468                     /* Check that path[2] is NULL! */ 
 469                     else if (path
[1] == wxT(':') && !path
[2]) 
 478             else if (p
[1] == wxT('.') && (p
[2] == SEP 
|| p
[2] == wxT('\0'))) 
 486 wxString 
wxRealPath(const wxString
& path
) 
 488     wxChar 
*buf1
=MYcopystring(path
); 
 489     wxChar 
*buf2
=wxRealPath(buf1
); 
 497 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 499     if (filename
.empty()) 
 500         return (wxChar 
*) NULL
; 
 502     if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer
, filename
))) 
 504         wxString buf 
= ::wxGetCwd(); 
 505         wxChar ch 
= buf
.Last(); 
 507         if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 513         buf 
<< wxFileFunctionsBuffer
; 
 514         buf 
= wxRealPath( buf 
); 
 515         return MYcopystring( buf 
); 
 517     return MYcopystring( wxFileFunctionsBuffer 
); 
 523    ~user/ => user's home dir 
 524    If the environment variable a = "foo" and b = "bar" then: 
 541 /* input name in name, pathname output to buf. */ 
 543 wxChar 
*wxExpandPath(wxChar 
*buf
, const wxChar 
*name
) 
 545     register wxChar 
*d
, *s
, *nm
; 
 546     wxChar          lnm
[_MAXPATHLEN
]; 
 549     // Some compilers don't like this line. 
 550 //    const wxChar    trimchars[] = wxT("\n \t"); 
 553     trimchars
[0] = wxT('\n'); 
 554     trimchars
[1] = wxT(' '); 
 555     trimchars
[2] = wxT('\t'); 
 559     const wxChar     SEP 
= wxT('\\'); 
 561     const wxChar     SEP 
= wxT('/'); 
 564     if (name 
== NULL 
|| *name 
== wxT('\0')) 
 566     nm 
= MYcopystring(name
); // Make a scratch copy 
 569     /* Skip leading whitespace and cr */ 
 570     while (wxStrchr((wxChar 
*)trimchars
, *nm
) != NULL
) 
 572     /* And strip off trailing whitespace and cr */ 
 573     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 574     while (q
-- && wxStrchr((wxChar 
*)trimchars
, *s
) != NULL
) 
 582     q 
= nm
[0] == wxT('\\') && nm
[1] == wxT('~'); 
 585     /* Expand inline environment variables */ 
 603     while ((*d
++ = *s
) != 0) { 
 605         if (*s 
== wxT('\\')) { 
 606             if ((*(d 
- 1) = *++s
)!=0) { 
 614             // No env variables on WinCE 
 617         if (*s
++ == wxT('$') && (*s 
== wxT('{') || *s 
== wxT(')'))) 
 619         if (*s
++ == wxT('$')) 
 622             register wxChar  
*start 
= d
; 
 623             register int     braces 
= (*s 
== wxT('{') || *s 
== wxT('(')); 
 624             register wxChar  
*value
; 
 625             while ((*d
++ = *s
) != 0) 
 626                 if (braces 
? (*s 
== wxT('}') || *s 
== wxT(')')) : !(wxIsalnum(*s
) || *s 
== wxT('_')) ) 
 631             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 633                 for ((d 
= start 
- 1); (*d
++ = *value
++) != 0;) 
 647     /* Expand ~ and ~user */ 
 649     if (nm
[0] == wxT('~') && !q
) 
 652         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 654         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 655             if ((s 
= WXSTRINGCAST 
wxGetUserHome(wxEmptyString
)) != NULL
) { 
 660         {                /* ~user/filename */ 
 661             register wxChar  
*nnm
; 
 662             register wxChar  
*home
; 
 663             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++) 
 667             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 668             was_sep 
= (*s 
== SEP
); 
 669             nnm 
= *s 
? s 
+ 1 : s
; 
 671         // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 672             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) 
 674                 if (was_sep
) /* replace only if it was there: */ 
 687     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 689         while (wxT('\0') != (*d
++ = *s
++)) 
 692         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 696     while ((*d
++ = *s
++) != 0) 
 700     delete[] nm_tmp
; // clean up alloc 
 701     /* Now clean up the buffer */ 
 702     return wxRealPath(buf
); 
 705 /* Contract Paths to be build upon an environment variable 
 708    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 710    The call wxExpandPath can convert these back! 
 713 wxContractPath (const wxString
& filename
, 
 714                 const wxString
& WXUNUSED_IN_WINCE(envname
), 
 715                 const wxString
& user
) 
 717   static wxChar dest
[_MAXPATHLEN
]; 
 719   if (filename
.empty()) 
 720     return (wxChar 
*) NULL
; 
 722   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 724   wxUnix2DosFilename(dest
); 
 727   // Handle environment 
 731   if (!envname
.empty() && (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 732      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 734         wxStrcpy (wxFileFunctionsBuffer
, tcp 
+ wxStrlen (val
)); 
 737         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 738         wxStrcat (tcp
, wxT("}")); 
 739         wxStrcat (tcp
, wxFileFunctionsBuffer
); 
 743   // Handle User's home (ignore root homes!) 
 744   val 
= wxGetUserHome (user
); 
 748   const size_t len 
= wxStrlen(val
); 
 752   if (wxStrncmp(dest
, val
, len
) == 0) 
 754     wxStrcpy(wxFileFunctionsBuffer
, wxT("~")); 
 756            wxStrcat(wxFileFunctionsBuffer
, (const wxChar
*) user
); 
 757     wxStrcat(wxFileFunctionsBuffer
, dest 
+ len
); 
 758     wxStrcpy (dest
, wxFileFunctionsBuffer
); 
 764 // Return just the filename, not the path (basename) 
 765 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 768     wxString n 
= wxFileNameFromPath(p
); 
 770     return path 
+ p
.length() - n
.length(); 
 773 wxString 
wxFileNameFromPath (const wxString
& path
) 
 776     wxFileName::SplitPath(path
, NULL
, &name
, &ext
); 
 778     wxString fullname 
= name
; 
 781         fullname 
<< wxFILE_SEP_EXT 
<< ext
; 
 787 // Return just the directory, or NULL if no directory 
 789 wxPathOnly (wxChar 
*path
) 
 793         static wxChar buf
[_MAXPATHLEN
]; 
 796         wxStrcpy (buf
, path
); 
 798         int l 
= wxStrlen(path
); 
 801         // Search backward for a backward or forward slash 
 804 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 805             // Classic or Carbon CodeWarrior like 
 806             // Carbon with Apple DevTools is Unix like 
 807             if (path
[i
] == wxT(':') ) 
 813             // Unix like or Windows 
 814             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 821             if (path
[i
] == wxT(']')) 
 830 #if defined(__WXMSW__) || defined(__OS2__) 
 831         // Try Drive specifier 
 832         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 834             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 841     return (wxChar 
*) NULL
; 
 844 // Return just the directory, or NULL if no directory 
 845 wxString 
wxPathOnly (const wxString
& path
) 
 849         wxChar buf
[_MAXPATHLEN
]; 
 852         wxStrcpy (buf
, WXSTRINGCAST path
); 
 854         int l 
= path
.length(); 
 857         // Search backward for a backward or forward slash 
 860 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 861             // Classic or Carbon CodeWarrior like 
 862             // Carbon with Apple DevTools is Unix like 
 863             if (path
[i
] == wxT(':') ) 
 866                 return wxString(buf
); 
 869             // Unix like or Windows 
 870             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 872                 // Don't return an empty string 
 876                 return wxString(buf
); 
 880             if (path
[i
] == wxT(']')) 
 883                 return wxString(buf
); 
 889 #if defined(__WXMSW__) || defined(__OS2__) 
 890         // Try Drive specifier 
 891         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 893             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 896             return wxString(buf
); 
 900     return wxEmptyString
; 
 903 // Utility for converting delimiters in DOS filenames to UNIX style 
 904 // and back again - or we get nasty problems with delimiters. 
 905 // Also, convert to lower case, since case is significant in UNIX. 
 907 #if defined(__WXMAC__) 
 909 #if TARGET_API_MAC_OSX 
 910 #define kDefaultPathStyle kCFURLPOSIXPathStyle 
 912 #define kDefaultPathStyle kCFURLHFSPathStyle 
 915 wxString 
wxMacFSRefToPath( const FSRef 
*fsRef 
, CFStringRef additionalPathComponent 
) 
 918     fullURLRef 
= CFURLCreateFromFSRef(NULL
, fsRef
); 
 919     if ( additionalPathComponent 
) 
 921         CFURLRef parentURLRef 
= fullURLRef 
; 
 922         fullURLRef 
= CFURLCreateCopyAppendingPathComponent(NULL
, parentURLRef
, 
 923             additionalPathComponent
,false); 
 924         CFRelease( parentURLRef 
) ; 
 926     CFStringRef cfString 
= CFURLCopyFileSystemPath(fullURLRef
, kDefaultPathStyle
); 
 927     CFRelease( fullURLRef 
) ; 
 928     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, cfString
); 
 929     CFRelease( cfString 
); 
 930     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
); 
 931     return wxMacCFStringHolder(cfMutableString
).AsString(); 
 934 OSStatus 
wxMacPathToFSRef( const wxString
&path 
, FSRef 
*fsRef 
) 
 936     OSStatus err 
= noErr 
; 
 937     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, wxMacCFStringHolder(path
)); 
 938     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormD
); 
 939     CFURLRef url 
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, cfMutableString 
, kDefaultPathStyle
, false); 
 940     CFRelease( cfMutableString 
); 
 943         if ( CFURLGetFSRef(url
, fsRef
) == false ) 
 954 wxString 
wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname 
) 
 956     CFStringRef cfname 
= CFStringCreateWithCharacters( kCFAllocatorDefault
, 
 959     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, cfname
); 
 961     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
); 
 962     return wxMacCFStringHolder(cfMutableString
).AsString() ; 
 967 wxString 
wxMacFSSpec2MacFilename( const FSSpec 
*spec 
) 
 970     if ( FSpMakeFSRef( spec 
, &fsRef
) == noErr 
) 
 972         return wxMacFSRefToPath( &fsRef 
) ; 
 974     return wxEmptyString 
; 
 977 void wxMacFilename2FSSpec( const wxString
& path 
, FSSpec 
*spec 
) 
 979     OSStatus err 
= noErr 
; 
 981     wxMacPathToFSRef( path 
, &fsRef 
) ; 
 982     err 
= FSRefMakeFSSpec( &fsRef 
, spec 
) ; 
 989 wxDos2UnixFilename (wxChar 
*s
) 
 998           *s 
= (wxChar
)wxTolower (*s
);        // Case INDEPENDENT 
1005 #if defined(__WXMSW__) || defined(__OS2__) 
1006 wxUnix2DosFilename (wxChar 
*s
) 
1008 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
) ) 
1011 // Yes, I really mean this to happen under DOS only! JACS 
1012 #if defined(__WXMSW__) || defined(__OS2__) 
1023 // Concatenate two files to form third 
1025 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
1029     wxFile 
in1(file1
), in2(file2
); 
1030     wxTempFile 
out(file3
); 
1032     if ( !in1
.IsOpened() || !in2
.IsOpened() || !out
.IsOpened() ) 
1036     unsigned char buf
[1024]; 
1038     for( int i
=0; i
<2; i
++) 
1040         wxFile 
*in 
= i
==0 ? &in1 
: &in2
; 
1042             if ( (ofs 
= in
->Read(buf
,WXSIZEOF(buf
))) == wxInvalidOffset 
) return false; 
1044                 if ( !out
.Write(buf
,ofs
) ) 
1046         } while ( ofs 
== (ssize_t
)WXSIZEOF(buf
) ); 
1049     return out
.Commit(); 
1061 // helper of generic implementation of wxCopyFile() 
1062 #if !(defined(__WIN32__) || defined(__OS2__) || defined(__PALMOS__)) && \ 
1066 wxDoCopyFile(wxFile
& fileIn
, 
1067              const wxStructStat
& fbuf
, 
1068              const wxString
& filenameDst
, 
1071     // reset the umask as we want to create the file with exactly the same 
1072     // permissions as the original one 
1075     // create file2 with the same permissions than file1 and open it for 
1079     if ( !fileOut
.Create(filenameDst
, overwrite
, fbuf
.st_mode 
& 0777) ) 
1082     // copy contents of file1 to file2 
1086         ssize_t count 
= fileIn
.Read(buf
, WXSIZEOF(buf
)); 
1087         if ( count 
== wxInvalidOffset 
) 
1094         if ( fileOut
.Write(buf
, count
) < (size_t)count 
) 
1098     // we can expect fileIn to be closed successfully, but we should ensure 
1099     // that fileOut was closed as some write errors (disk full) might not be 
1100     // detected before doing this 
1101     return fileIn
.Close() && fileOut
.Close(); 
1104 #endif // generic implementation of wxCopyFile 
1108 wxCopyFile (const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1110 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1111     // CopyFile() copies file attributes and modification time too, so use it 
1112     // instead of our code if available 
1114     // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite 
1115     if ( !::CopyFile(file1
, file2
, !overwrite
) ) 
1117         wxLogSysError(_("Failed to copy the file '%s' to '%s'"), 
1118                       file1
.c_str(), file2
.c_str()); 
1122 #elif defined(__OS2__) 
1123     if ( ::DosCopy(file1
.c_str(), file2
.c_str(), overwrite 
? DCPY_EXISTING 
: 0) != 0 ) 
1125 #elif defined(__PALMOS__) 
1126     // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ 
1128 #elif wxUSE_FILE // !Win32 
1131     // get permissions of file1 
1132     if ( wxStat( file1
.c_str(), &fbuf
) != 0 ) 
1134         // the file probably doesn't exist or we haven't the rights to read 
1136         wxLogSysError(_("Impossible to get permissions for file '%s'"), 
1141     // open file1 for reading 
1142     wxFile 
fileIn(file1
, wxFile::read
); 
1143     if ( !fileIn
.IsOpened() ) 
1146     // remove file2, if it exists. This is needed for creating 
1147     // file2 with the correct permissions in the next step 
1148     if ( wxFileExists(file2
)  && (!overwrite 
|| !wxRemoveFile(file2
))) 
1150         wxLogSysError(_("Impossible to overwrite the file '%s'"), 
1155     wxDoCopyFile(fileIn
, fbuf
, file2
, overwrite
); 
1157 #if defined(__WXMAC__) || defined(__WXCOCOA__) 
1158     // copy the resource fork of the file too if it's present 
1159     wxString pathRsrcOut
; 
1163         // suppress error messages from this block as resource forks don't have 
1167         // it's not enough to check for file existence: it always does on HFS 
1168         // but is empty for files without resources 
1169         if ( fileRsrcIn
.Open(file1 
+ wxT("/..namedfork/rsrc")) && 
1170                 fileRsrcIn
.Length() > 0 ) 
1172             // we must be using HFS or another filesystem with resource fork 
1173             // support, suppose that destination file system also is HFS[-like] 
1174             pathRsrcOut 
= file2 
+ wxT("/..namedfork/rsrc"); 
1176         else // check if we have resource fork in separate file (non-HFS case) 
1178             wxFileName 
fnRsrc(file1
); 
1179             fnRsrc
.SetName(wxT("._") + fnRsrc
.GetName()); 
1182             if ( fileRsrcIn
.Open( fnRsrc
.GetFullPath() ) ) 
1185                 fnRsrc
.SetName(wxT("._") + fnRsrc
.GetName()); 
1187                 pathRsrcOut 
= fnRsrc
.GetFullPath(); 
1192     if ( !pathRsrcOut
.empty() ) 
1194         if ( !wxDoCopyFile(fileRsrcIn
, fbuf
, pathRsrcOut
, overwrite
) ) 
1197 #endif // wxMac || wxCocoa 
1199 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 
1200     // no chmod in VA.  Should be some permission API for HPFS386 partitions 
1202     if ( chmod(OS_FILENAME(file2
), fbuf
.st_mode
) != 0 ) 
1204         wxLogSysError(_("Impossible to set permissions for the file '%s'"), 
1208 #endif // OS/2 || Mac 
1210 #else // !Win32 && ! wxUSE_FILE 
1212     // impossible to simulate with wxWidgets API 
1215     wxUnusedVar(overwrite
); 
1218 #endif // __WXMSW__ && __WIN32__ 
1224 wxRenameFile(const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1226     if ( !overwrite 
&& wxFileExists(file2
) ) 
1230             _("Failed to rename the file '%s' to '%s' because the destination file already exists."), 
1231             file1
.c_str(), file2
.c_str() 
1237 #if !defined(__WXWINCE__) && !defined(__WXPALMOS__) 
1238     // Normal system call 
1239   if ( wxRename (file1
, file2
) == 0 ) 
1244   if (wxCopyFile(file1
, file2
, overwrite
)) { 
1245     wxRemoveFile(file1
); 
1252 bool wxRemoveFile(const wxString
& file
) 
1254 #if defined(__VISUALC__) \ 
1255  || defined(__BORLANDC__) \ 
1256  || defined(__WATCOMC__) \ 
1257  || defined(__DMC__) \ 
1258  || defined(__GNUWIN32__) \ 
1259  || (defined(__MWERKS__) && defined(__MSL__)) 
1260     int res 
= wxRemove(file
); 
1261 #elif defined(__WXMAC__) 
1262     int res 
= unlink(wxFNCONV(file
)); 
1263 #elif defined(__WXPALMOS__) 
1265     // TODO with VFSFileDelete() 
1267     int res 
= unlink(OS_FILENAME(file
)); 
1273 bool wxMkdir(const wxString
& dir
, int perm
) 
1275 #if defined(__WXPALMOS__) 
1277 #elif defined(__WXMAC__) && !defined(__UNIX__) 
1278     return (mkdir( wxFNCONV(dir
) , 0 ) == 0); 
1280     const wxChar 
*dirname 
= dir
.c_str(); 
1282     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 
1283     // for the GNU compiler 
1284 #if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) 
1287     if ( mkdir(wxFNCONV(dirname
)) != 0 ) 
1289     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1291 #elif defined(__OS2__) 
1293     if (::DosCreateDir((PSZ
)dirname
, NULL
) != 0) // enhance for EAB's?? 
1294 #elif defined(__DOS__) 
1295   #if defined(__WATCOMC__) 
1297     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1298   #elif defined(__DJGPP__) 
1299     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1301     #error "Unsupported DOS compiler!" 
1303 #else  // !MSW, !DOS and !OS/2 VAC++ 
1306     if ( !CreateDirectory(dirname
, NULL
) ) 
1308     if ( wxMkDir(dir
.fn_str()) != 0 ) 
1312         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1321 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1323 #if defined(__VMS__) 
1324     return false; //to be changed since rmdir exists in VMS7.x 
1325 #elif defined(__OS2__) 
1326     return (::DosDeleteDir(dir
.c_str()) == 0); 
1327 #elif defined(__WXWINCE__) 
1328     return (RemoveDirectory(dir
) != 0); 
1329 #elif defined(__WXPALMOS__) 
1330     // TODO with VFSFileRename() 
1333     return (wxRmDir(OS_FILENAME(dir
)) == 0); 
1337 // does the path exists? (may have or not '/' or '\\' at the end) 
1338 bool wxDirExists(const wxString
& pathName
) 
1340     wxString 
strPath(pathName
); 
1342 #if defined(__WINDOWS__) || defined(__OS2__) 
1343     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
1344     // so remove all trailing backslashes from the path - but don't do this for 
1345     // the paths "d:\" (which are different from "d:") nor for just "\" 
1346     while ( wxEndsWithPathSeparator(strPath
) ) 
1348         size_t len 
= strPath
.length(); 
1349         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == _T(':')) ) 
1352         strPath
.Truncate(len 
- 1); 
1354 #endif // __WINDOWS__ 
1357     // OS/2 can't handle "d:", it wants either "d:\" or "d:." 
1358     if (strPath
.length() == 2 && strPath
[1u] == _T(':')) 
1362 #if defined(__WXPALMOS__) 
1364 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
1365     // stat() can't cope with network paths 
1366     DWORD ret 
= ::GetFileAttributes(strPath
); 
1368     return (ret 
!= (DWORD
)-1) && (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
1369 #elif defined(__OS2__) 
1370     FILESTATUS3 Info 
= {{0}}; 
1371     APIRET rc 
= ::DosQueryPathInfo((PSZ
)(WXSTRINGCAST strPath
), FIL_STANDARD
, 
1372                                    (void*) &Info
, sizeof(FILESTATUS3
)); 
1374     return ((rc 
== NO_ERROR
) && (Info
.attrFile 
& FILE_DIRECTORY
)) || 
1375       (rc 
== ERROR_SHARING_VIOLATION
); 
1376     // If we got a sharing violation, there must be something with this name. 
1380 #ifndef __VISAGECPP__ 
1381     return wxStat(strPath
.c_str(), &st
) == 0 && ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
1383     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
1384     return wxStat(strPath
.c_str(), &st
) == 0 && (st
.st_mode 
== S_IFDIR
); 
1387 #endif // __WIN32__/!__WIN32__ 
1390 // Get a temporary filename, opening and closing the file. 
1391 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1394     if ( !wxGetTempFileName(prefix
, filename
) ) 
1398         wxStrcpy(buf
, filename
); 
1400         buf 
= MYcopystring(filename
); 
1405 bool wxGetTempFileName(const wxString
& prefix
, wxString
& buf
) 
1408     buf 
= wxFileName::CreateTempFileName(prefix
); 
1410     return !buf
.empty(); 
1411 #else // !wxUSE_FILE 
1412     wxUnusedVar(prefix
); 
1416 #endif // wxUSE_FILE/!wxUSE_FILE 
1419 // Get first file name matching given wild card. 
1421 static wxDir 
*gs_dir 
= NULL
; 
1422 static wxString gs_dirPath
; 
1424 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1426     wxSplitPath(spec
, &gs_dirPath
, NULL
, NULL
); 
1427     if ( gs_dirPath
.empty() ) 
1428         gs_dirPath 
= wxT("."); 
1429     if ( !wxEndsWithPathSeparator(gs_dirPath 
) ) 
1430         gs_dirPath 
<< wxFILE_SEP_PATH
; 
1434     gs_dir 
= new wxDir(gs_dirPath
); 
1436     if ( !gs_dir
->IsOpened() ) 
1438         wxLogSysError(_("Can not enumerate files '%s'"), spec
); 
1439         return wxEmptyString
; 
1445         case wxDIR
:  dirFlags 
= wxDIR_DIRS
; break; 
1446         case wxFILE
: dirFlags 
= wxDIR_FILES
; break; 
1447         default:     dirFlags 
= wxDIR_DIRS 
| wxDIR_FILES
; break; 
1451     gs_dir
->GetFirst(&result
, wxFileNameFromPath(wxString(spec
)), dirFlags
); 
1452     if ( result
.empty() ) 
1458     return gs_dirPath 
+ result
; 
1461 wxString 
wxFindNextFile() 
1463     wxASSERT_MSG( gs_dir
, wxT("You must call wxFindFirstFile before!") ); 
1466     gs_dir
->GetNext(&result
); 
1468     if ( result
.empty() ) 
1474     return gs_dirPath 
+ result
; 
1478 // Get current working directory. 
1479 // If buf is NULL, allocates space using new, else copies into buf. 
1480 // wxGetWorkingDirectory() is obsolete, use wxGetCwd() 
1481 // wxDoGetCwd() is their common core to be moved 
1482 // to wxGetCwd() once wxGetWorkingDirectory() will be removed. 
1483 // Do not expose wxDoGetCwd in headers! 
1485 wxChar 
*wxDoGetCwd(wxChar 
*buf
, int sz
) 
1487 #if defined(__WXPALMOS__) 
1489     if(buf 
&& sz
>0) buf
[0] = _T('\0'); 
1491 #elif defined(__WXWINCE__) 
1493     if(buf 
&& sz
>0) buf
[0] = _T('\0'); 
1498         buf 
= new wxChar
[sz 
+ 1]; 
1501     bool ok 
wxDUMMY_INITIALIZE(false); 
1503     // for the compilers which have Unicode version of _getcwd(), call it 
1504     // directly, for the others call the ANSI version and do the translation 
1507 #else // wxUSE_UNICODE 
1508     bool needsANSI 
= true; 
1510     #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU 
1511         char cbuf
[_MAXPATHLEN
]; 
1515         #if wxUSE_UNICODE_MSLU 
1516             if ( wxGetOsVersion() != wxOS_WINDOWS_9X 
) 
1518             char *cbuf 
= NULL
; // never really used because needsANSI will always be false 
1521                 ok 
= _wgetcwd(buf
, sz
) != NULL
; 
1527 #endif // wxUSE_UNICODE 
1529     #if defined(_MSC_VER) || defined(__MINGW32__) 
1530         ok 
= _getcwd(cbuf
, sz
) != NULL
; 
1531     #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1533         if ( getcwd( lbuf 
, sizeof( lbuf 
) ) ) 
1535             wxString 
res( lbuf 
, *wxConvCurrent 
) ; 
1536             wxStrcpy( buf 
, res 
) ; 
1541     #elif defined(__OS2__) 
1543         ULONG ulDriveNum 
= 0; 
1544         ULONG ulDriveMap 
= 0; 
1545         rc 
= ::DosQueryCurrentDisk(&ulDriveNum
, &ulDriveMap
); 
1550             rc 
= ::DosQueryCurrentDir( 0 // current drive 
1554             cbuf
[0] = char('A' + (ulDriveNum 
- 1)); 
1559     #else // !Win32/VC++ !Mac !OS2 
1560         ok 
= getcwd(cbuf
, sz
) != NULL
; 
1563     #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) 
1564         // finally convert the result to Unicode if needed 
1565         wxConvFile
.MB2WC(buf
, cbuf
, sz
); 
1566     #endif // wxUSE_UNICODE 
1571         wxLogSysError(_("Failed to get the working directory")); 
1573         // VZ: the old code used to return "." on error which didn't make any 
1574         //     sense at all to me - empty string is a better error indicator 
1575         //     (NULL might be even better but I'm afraid this could lead to 
1576         //     problems with the old code assuming the return is never NULL) 
1579     else // ok, but we might need to massage the path into the right format 
1582         // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths 
1583         //     with / deliminers. We don't like that. 
1584         for (wxChar 
*ch 
= buf
; *ch
; ch
++) 
1586             if (*ch 
== wxT('/')) 
1591 // MBN: we hope that in the case the user is compiling a GTK+/Motif app, 
1592 //      he needs Unix as opposed to Win32 pathnames 
1593 #if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) 
1594         // another example of DOS/Unix mix (Cygwin) 
1595         wxString pathUnix 
= buf
; 
1597         char bufA
[_MAXPATHLEN
]; 
1598         cygwin_conv_to_full_win32_path(pathUnix
.mb_str(wxConvFile
), bufA
); 
1599         wxConvFile
.MB2WC(buf
, bufA
, sz
); 
1601         cygwin_conv_to_full_win32_path(pathUnix
, buf
); 
1602 #endif // wxUSE_UNICODE 
1603 #endif // __CYGWIN__ 
1616 #if WXWIN_COMPATIBILITY_2_6 
1617 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1619     return wxDoGetCwd(buf
,sz
); 
1621 #endif // WXWIN_COMPATIBILITY_2_6 
1626     wxDoGetCwd(wxStringBuffer(str
, _MAXPATHLEN
), _MAXPATHLEN
); 
1630 bool wxSetWorkingDirectory(const wxString
& d
) 
1632 #if defined(__OS2__) 
1635         ::DosSetDefaultDisk(1 + wxToupper(d
[0]) - _T('A')); 
1636         // do not call DosSetCurrentDir when just changing drive, 
1637         // since it requires e.g. "d:." instead of "d:"! 
1638         if (d
.length() == 2) 
1641     return (::DosSetCurrentDir(d
.c_str()) == 0); 
1642 #elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) 
1643     return (chdir(wxFNSTRINGCAST d
.fn_str()) == 0); 
1644 #elif defined(__WINDOWS__) 
1648     // No equivalent in WinCE 
1652     return (bool)(SetCurrentDirectory(d
) != 0); 
1655     // Must change drive, too. 
1656     bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1659         wxChar firstChar 
= d
[0]; 
1663             firstChar 
= firstChar 
- 32; 
1665         // To a drive number 
1666         unsigned int driveNo 
= firstChar 
- 64; 
1669             unsigned int noDrives
; 
1670             _dos_setdrive(driveNo
, &noDrives
); 
1673     bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1681 // Get the OS directory if appropriate (such as the Windows directory). 
1682 // On non-Windows platform, probably just return the empty string. 
1683 wxString 
wxGetOSDirectory() 
1686     return wxString(wxT("\\Windows")); 
1687 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1689     GetWindowsDirectory(buf
, 256); 
1690     return wxString(buf
); 
1691 #elif defined(__WXMAC__) 
1692     return wxMacFindFolder(kOnSystemDisk
, 'macs', false); 
1694     return wxEmptyString
; 
1698 bool wxEndsWithPathSeparator(const wxChar 
*pszFileName
) 
1700     size_t len 
= wxStrlen(pszFileName
); 
1702     return len 
&& wxIsPathSeparator(pszFileName
[len 
- 1]); 
1705 // find a file in a list of directories, returns false if not found 
1706 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1708     // we assume that it's not empty 
1709     wxCHECK_MSG( !wxIsEmpty(pszFile
), false, 
1710                  _T("empty file name in wxFindFileInPath")); 
1712     // skip path separator in the beginning of the file name if present 
1713     if ( wxIsPathSeparator(*pszFile
) ) 
1716     // copy the path (strtok will modify it) 
1717     wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1718     wxStrcpy(szPath
, pszPath
); 
1721     wxChar 
*pc
, *save_ptr
; 
1722     for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1724           pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1726         // search for the file in this directory 
1728         if ( !wxEndsWithPathSeparator(pc
) ) 
1729             strFile 
+= wxFILE_SEP_PATH
; 
1732         if ( wxFileExists(strFile
) ) { 
1738     // suppress warning about unused variable save_ptr when wxStrtok() is a 
1739     // macro which throws away its third argument 
1744     return pc 
!= NULL
;  // if true => we breaked from the loop 
1747 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1752     // it can be empty, but it shouldn't be NULL 
1753     wxCHECK_RET( pszFileName
, wxT("NULL file name in wxSplitPath") ); 
1755     wxFileName::SplitPath(pszFileName
, pstrPath
, pstrName
, pstrExt
); 
1760 time_t WXDLLEXPORT 
wxFileModificationTime(const wxString
& filename
) 
1763     if ( !wxFileName(filename
).GetTimes(NULL
, &mtime
, NULL
) ) 
1766     return mtime
.GetTicks(); 
1769 #endif // wxUSE_DATETIME 
1772 // Parses the filterStr, returning the number of filters. 
1773 // Returns 0 if none or if there's a problem. 
1774 // filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" 
1776 int WXDLLEXPORT 
wxParseCommonDialogsFilter(const wxString
& filterStr
, 
1777                                            wxArrayString
& descriptions
, 
1778                                            wxArrayString
& filters
) 
1780     descriptions
.Clear(); 
1783     wxString 
str(filterStr
); 
1785     wxString description
, filter
; 
1787     while( pos 
!= wxNOT_FOUND 
) 
1789         pos 
= str
.Find(wxT('|')); 
1790         if ( pos 
== wxNOT_FOUND 
) 
1792             // if there are no '|'s at all in the string just take the entire 
1793             // string as filter and make description empty for later autocompletion 
1794             if ( filters
.IsEmpty() ) 
1796                 descriptions
.Add(wxEmptyString
); 
1797                 filters
.Add(filterStr
); 
1801                 wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); 
1807         description 
= str
.Left(pos
); 
1808         str 
= str
.Mid(pos 
+ 1); 
1809         pos 
= str
.Find(wxT('|')); 
1810         if ( pos 
== wxNOT_FOUND 
) 
1816             filter 
= str
.Left(pos
); 
1817             str 
= str
.Mid(pos 
+ 1); 
1820         descriptions
.Add(description
); 
1821         filters
.Add(filter
); 
1824 #if defined(__WXMOTIF__) 
1825     // split it so there is one wildcard per entry 
1826     for( size_t i 
= 0 ; i 
< descriptions
.GetCount() ; i
++ ) 
1828         pos 
= filters
[i
].Find(wxT(';')); 
1829         if (pos 
!= wxNOT_FOUND
) 
1831             // first split only filters 
1832             descriptions
.Insert(descriptions
[i
],i
+1); 
1833             filters
.Insert(filters
[i
].Mid(pos
+1),i
+1); 
1834             filters
[i
]=filters
[i
].Left(pos
); 
1836             // autoreplace new filter in description with pattern: 
1837             //     C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h 
1838             // cause split into: 
1839             //     C/C++ Files(*.cpp)|*.cpp 
1840             //     C/C++ Files(*.c;*.h)|*.c;*.h 
1841             // and next iteration cause another split into: 
1842             //     C/C++ Files(*.cpp)|*.cpp 
1843             //     C/C++ Files(*.c)|*.c 
1844             //     C/C++ Files(*.h)|*.h 
1845             for ( size_t k
=i
;k
<i
+2;k
++ ) 
1847                 pos 
= descriptions
[k
].Find(filters
[k
]); 
1848                 if (pos 
!= wxNOT_FOUND
) 
1850                     wxString before 
= descriptions
[k
].Left(pos
); 
1851                     wxString after 
= descriptions
[k
].Mid(pos
+filters
[k
].Len()); 
1852                     pos 
= before
.Find(_T('('),true); 
1853                     if (pos
>before
.Find(_T(')'),true)) 
1855                         before 
= before
.Left(pos
+1); 
1856                         before 
<< filters
[k
]; 
1857                         pos 
= after
.Find(_T(')')); 
1858                         int pos1 
= after
.Find(_T('(')); 
1859                         if (pos 
!= wxNOT_FOUND 
&& (pos
<pos1 
|| pos1
==wxNOT_FOUND
)) 
1861                             before 
<< after
.Mid(pos
); 
1862                             descriptions
[k
] = before
; 
1872     for( size_t j 
= 0 ; j 
< descriptions
.GetCount() ; j
++ ) 
1874         if ( descriptions
[j
].empty() && !filters
[j
].empty() ) 
1876             descriptions
[j
].Printf(_("Files (%s)"), filters
[j
].c_str()); 
1880     return filters
.GetCount(); 
1883 #if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__)) 
1884 static bool wxCheckWin32Permission(const wxString
& path
, DWORD access
) 
1886     // quoting the MSDN: "To obtain a handle to a directory, call the 
1887     // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this 
1888     // doesn't work under Win9x/ME but then it's not needed there anyhow 
1889     bool isdir 
= wxDirExists(path
); 
1890     if ( isdir 
&& wxGetOsVersion() == wxOS_WINDOWS_9X 
) 
1892         // FAT directories always allow all access, even if they have the 
1893         // readonly flag set 
1897     HANDLE h 
= ::CreateFile
 
1901                     FILE_SHARE_READ 
| FILE_SHARE_WRITE 
| FILE_SHARE_DELETE
, 
1904                     isdir 
? FILE_FLAG_BACKUP_SEMANTICS 
: 0, 
1907     if ( h 
!= INVALID_HANDLE_VALUE 
) 
1910     return h 
!= INVALID_HANDLE_VALUE
; 
1912 #endif // __WINDOWS__ 
1914 bool wxIsWritable(const wxString 
&path
) 
1916 #if defined( __UNIX__ ) || defined(__OS2__) 
1917     // access() will take in count also symbolic links 
1918     return access(wxConvFile
.cWX2MB(path
), W_OK
) == 0; 
1919 #elif defined( __WINDOWS__ ) 
1920     return wxCheckWin32Permission(path
, GENERIC_WRITE
); 
1928 bool wxIsReadable(const wxString 
&path
) 
1930 #if defined( __UNIX__ ) || defined(__OS2__) 
1931     // access() will take in count also symbolic links 
1932     return access(wxConvFile
.cWX2MB(path
), R_OK
) == 0; 
1933 #elif defined( __WINDOWS__ ) 
1934     return wxCheckWin32Permission(path
, GENERIC_READ
); 
1942 bool wxIsExecutable(const wxString 
&path
) 
1944 #if defined( __UNIX__ ) || defined(__OS2__) 
1945     // access() will take in count also symbolic links 
1946     return access(wxConvFile
.cWX2MB(path
), X_OK
) == 0; 
1947 #elif defined( __WINDOWS__ ) 
1948    return wxCheckWin32Permission(path
, GENERIC_EXECUTE
); 
1956 // Return the type of an open file 
1958 // Some file types on some platforms seem seekable but in fact are not. 
1959 // The main use of this function is to allow such cases to be detected 
1960 // (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK). 
1962 // This is important for the archive streams, which benefit greatly from 
1963 // being able to seek on a stream, but which will produce corrupt archives 
1964 // if they unknowingly seek on a non-seekable stream. 
1966 // wxFILE_KIND_DISK is a good catch all return value, since other values 
1967 // disable features of the archive streams. Some other value must be returned 
1968 // for a file type that appears seekable but isn't. 
1971 //   *  Pipes on Windows 
1972 //   *  Files on VMS with a record format other than StreamLF 
1974 wxFileKind 
wxGetFileKind(int fd
) 
1976 #if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle 
1977     switch (::GetFileType(wxGetOSFHandle(fd
)) & ~FILE_TYPE_REMOTE
) 
1979         case FILE_TYPE_CHAR
: 
1980             return wxFILE_KIND_TERMINAL
; 
1981         case FILE_TYPE_DISK
: 
1982             return wxFILE_KIND_DISK
; 
1983         case FILE_TYPE_PIPE
: 
1984             return wxFILE_KIND_PIPE
; 
1987     return wxFILE_KIND_UNKNOWN
; 
1989 #elif defined(__UNIX__) 
1991         return wxFILE_KIND_TERMINAL
; 
1996     if (S_ISFIFO(st
.st_mode
)) 
1997         return wxFILE_KIND_PIPE
; 
1998     if (!S_ISREG(st
.st_mode
)) 
1999         return wxFILE_KIND_UNKNOWN
; 
2001     #if defined(__VMS__) 
2002         if (st
.st_fab_rfm 
!= FAB$C_STMLF
) 
2003             return wxFILE_KIND_UNKNOWN
; 
2006     return wxFILE_KIND_DISK
; 
2009     #define wxFILEKIND_STUB 
2011     return wxFILE_KIND_DISK
; 
2015 wxFileKind 
wxGetFileKind(FILE *fp
) 
2017     // Note: The watcom rtl dll doesn't have fileno (the static lib does). 
2018     //       Should be fixed in version 1.4. 
2019 #if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4) 
2021     return wxFILE_KIND_DISK
; 
2022 #elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__) 
2023     return fp 
? wxGetFileKind(_fileno(fp
)) : wxFILE_KIND_UNKNOWN
; 
2025     return fp 
? wxGetFileKind(fileno(fp
)) : wxFILE_KIND_UNKNOWN
; 
2030 //------------------------------------------------------------------------ 
2031 // wild character routines 
2032 //------------------------------------------------------------------------ 
2034 bool wxIsWild( const wxString
& pattern 
) 
2036     wxString tmp 
= pattern
; 
2037     wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
2042         case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): 
2053 * Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU> 
2055 * The match procedure is public domain code (from ircII's reg.c) 
2056 * but modified to suit our tastes (RN: No "%" syntax I guess) 
2059 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
2063         /* Match if both are empty. */ 
2067     const wxChar 
*m 
= pat
.c_str(), 
2075     if (dot_special 
&& (*n 
== wxT('.'))) 
2077         /* Never match so that hidden Unix files 
2078          * are never found. */ 
2091         else if (*m 
== wxT('?')) 
2099             if (*m 
== wxT('\\')) 
2102                 /* Quoting "nothing" is a bad thing */ 
2109                 * If we are out of both strings or we just 
2110                 * saw a wildcard, then we can say we have a 
2121             * We could check for *n == NULL at this point, but 
2122             * since it's more common to have a character there, 
2123             * check to see if they match first (m and n) and 
2124             * then if they don't match, THEN we can check for 
2140                 * If there are no more characters in the 
2141                 * string, but we still need to find another 
2142                 * character (*m != NULL), then it will be 
2143                 * impossible to match it 
2162     #pragma warning(default:4706)   // assignment within conditional expression