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/dynarray.h" 
  38 #include "wx/filename.h" 
  41 #include "wx/tokenzr.h" 
  43 // there are just too many of those... 
  45     #pragma warning(disable:4706)   // assignment within conditional expression 
  52 #if !wxONLY_WATCOM_EARLIER_THAN(1,4) 
  53     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  58 #if defined(__WXMAC__) 
  59     #include  "wx/osx/private.h"  // includes mac headers 
  63     #include "wx/msw/private.h" 
  64     #include "wx/msw/mslu.h" 
  66     // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() 
  68     // note that it must be included after <windows.h> 
  71             #include <sys/cygwin.h> 
  73     #endif // __GNUWIN32__ 
  75     // io.h is needed for _get_osfhandle() 
  76     // Already included by filefn.h for many Windows compilers 
  77     #if defined __MWERKS__ || defined __CYGWIN__ 
  86 // TODO: Borland probably has _wgetcwd as well? 
  91 // ---------------------------------------------------------------------------- 
  93 // ---------------------------------------------------------------------------- 
  96     #define _MAXPATHLEN 1024 
  99 #ifndef INVALID_FILE_ATTRIBUTES 
 100     #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 
 103 // ---------------------------------------------------------------------------- 
 105 // ---------------------------------------------------------------------------- 
 107 #if WXWIN_COMPATIBILITY_2_8 
 108 static wxChar wxFileFunctionsBuffer
[4*_MAXPATHLEN
]; 
 111 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
 113 // VisualAge C++ V4.0 cannot have any external linkage const decs 
 114 // in headers included by more than one primary source 
 116 const int wxInvalidOffset 
= -1; 
 119 // ============================================================================ 
 121 // ============================================================================ 
 123 // ---------------------------------------------------------------------------- 
 124 // wrappers around standard POSIX functions 
 125 // ---------------------------------------------------------------------------- 
 127 #if wxUSE_UNICODE && defined __BORLANDC__ \ 
 128     && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 
 130 // BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only 
 131 // regardless of the mode parameter. This hack works around the problem by 
 132 // setting the mode with _wchmod. 
 134 int wxCRT_OpenW(const wchar_t *pathname
, int flags
, mode_t mode
) 
 138     // we only want to fix the mode when the file is actually created, so 
 139     // when creating first try doing it O_EXCL so we can tell if the file 
 140     // was already there. 
 141     if ((flags 
& O_CREAT
) && !(flags 
& O_EXCL
) && (mode 
& wxS_IWUSR
) != 0) 
 144     int fd 
= _wopen(pathname
, flags 
| moreflags
, mode
); 
 146     // the file was actually created and needs fixing 
 147     if (fd 
!= -1 && (flags 
& O_CREAT
) != 0 && (mode 
& wxS_IWUSR
) != 0) 
 150         _wchmod(pathname
, mode
); 
 151         fd 
= _wopen(pathname
, flags 
& ~(O_EXCL 
| O_CREAT
)); 
 153     // the open failed, but it may have been because the added O_EXCL stopped 
 154     // the opening of an existing file, so try again without. 
 155     else if (fd 
== -1 && moreflags 
!= 0) 
 157         fd 
= _wopen(pathname
, flags 
& ~O_CREAT
); 
 165 // ---------------------------------------------------------------------------- 
 167 // ---------------------------------------------------------------------------- 
 169 bool wxPathList::Add(const wxString
& path
) 
 171     // add a path separator to force wxFileName to interpret it always as a directory 
 172     // (i.e. if we are called with '/home/user' we want to consider it a folder and 
 173     // not, as wxFileName would consider, a filename). 
 174     wxFileName 
fn(path 
+ wxFileName::GetPathSeparator()); 
 176     // add only normalized relative/absolute paths 
 177     // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to 
 178     //     normalize paths which starts with ".." (which can be normalized only if 
 179     //     we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). 
 180     if (!fn
.Normalize(wxPATH_NORM_TILDE
|wxPATH_NORM_LONG
|wxPATH_NORM_ENV_VARS
)) 
 183     wxString toadd 
= fn
.GetPath(); 
 184     if (Index(toadd
) == wxNOT_FOUND
) 
 185         wxArrayString::Add(toadd
);      // do not add duplicates 
 190 void wxPathList::Add(const wxArrayString 
&arr
) 
 192     for (size_t j
=0; j 
< arr
.GetCount(); j
++) 
 196 // Add paths e.g. from the PATH environment variable 
 197 void wxPathList::AddEnvList (const wxString
& WXUNUSED_IN_WINCE(envVariable
)) 
 199     // No environment variables on WinCE 
 202     // The space has been removed from the tokenizers, otherwise a 
 203     // path such as "C:\Program Files" would be split into 2 paths: 
 204     // "C:\Program" and "Files"; this is true for both Windows and Unix. 
 206     static const wxChar PATH_TOKS
[] = 
 207 #if defined(__WINDOWS__) || defined(__OS2__) 
 208         wxT(";"); // Don't separate with colon in DOS (used for drive) 
 214     if ( wxGetEnv(envVariable
, &val
) ) 
 216         // split into an array of string the value of the env var 
 217         wxArrayString arr 
= wxStringTokenize(val
, PATH_TOKS
); 
 218         WX_APPEND_ARRAY(*this, arr
); 
 220 #endif // !__WXWINCE__ 
 223 // Given a full filename (with path), ensure that that file can 
 224 // be accessed again USING FILENAME ONLY by adding the path 
 225 // to the list if not already there. 
 226 bool wxPathList::EnsureFileAccessible (const wxString
& path
) 
 228     return Add(wxPathOnly(path
)); 
 231 #if WXWIN_COMPATIBILITY_2_6 
 232 bool wxPathList::Member (const wxString
& path
) const 
 234     return Index(path
) != wxNOT_FOUND
; 
 238 wxString 
wxPathList::FindValidPath (const wxString
& file
) const 
 240     // normalize the given string as it could be a path + a filename 
 241     // and not only a filename 
 245     // NB: normalize without making absolute otherwise calling this function with 
 246     //     e.g. "b/c.txt" would result in removing the directory 'b' and the for loop 
 247     //     below would only add to the paths of this list the 'c.txt' part when doing 
 248     //     the existence checks... 
 249     // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) 
 250     if (!fn
.Normalize(wxPATH_NORM_TILDE
|wxPATH_NORM_LONG
|wxPATH_NORM_ENV_VARS
)) 
 251         return wxEmptyString
; 
 253     wxASSERT_MSG(!fn
.IsDir(), wxT("Cannot search for directories; only for files")); 
 255         strend 
= fn
.GetFullName();      // search for the file name and ignore the path part 
 257         strend 
= fn
.GetFullPath(); 
 259     for (size_t i
=0; i
<GetCount(); i
++) 
 261         wxString strstart 
= Item(i
); 
 262         if (!strstart
.IsEmpty() && strstart
.Last() != wxFileName::GetPathSeparator()) 
 263             strstart 
+= wxFileName::GetPathSeparator(); 
 265         if (wxFileExists(strstart 
+ strend
)) 
 266             return strstart 
+ strend
;        // Found! 
 269     return wxEmptyString
;                    // Not found 
 272 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) const 
 274     wxString f 
= FindValidPath(file
); 
 275     if ( f
.empty() || wxIsAbsolutePath(f
) ) 
 278     wxString buf 
= ::wxGetCwd(); 
 280     if ( !wxEndsWithPathSeparator(buf
) ) 
 282         buf 
+= wxFILE_SEP_PATH
; 
 289 // ---------------------------------------------------------------------------- 
 290 // miscellaneous global functions 
 291 // ---------------------------------------------------------------------------- 
 293 #if WXWIN_COMPATIBILITY_2_8 
 294 static inline wxChar
* MYcopystring(const wxString
& s
) 
 296     wxChar
* copy 
= new wxChar
[s
.length() + 1]; 
 297     return wxStrcpy(copy
, s
.c_str()); 
 300 template<typename CharType
> 
 301 static inline CharType
* MYcopystring(const CharType
* s
) 
 303     CharType
* copy 
= new CharType
[wxStrlen(s
) + 1]; 
 304     return wxStrcpy(copy
, s
); 
 310 wxFileExists (const wxString
& filename
) 
 312 #if defined(__WXPALMOS__) 
 314 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
 315     // we must use GetFileAttributes() instead of the ANSI C functions because 
 316     // it can cope with network (UNC) paths unlike them 
 317     DWORD ret 
= ::GetFileAttributes(filename
.fn_str()); 
 319     return (ret 
!= INVALID_FILE_ATTRIBUTES
) && !(ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 322         #define S_ISREG(mode) ((mode) & S_IFREG) 
 325 #ifndef wxNEED_WX_UNISTD_H 
 326     return (wxStat( filename
.fn_str() , &st
) == 0 && S_ISREG(st
.st_mode
)) 
 328       || (errno 
== EACCES
) // if access is denied something with that name 
 329                             // exists and is opened in exclusive mode. 
 333     return wxStat( filename 
, &st
) == 0 && S_ISREG(st
.st_mode
); 
 335 #endif // __WIN32__/!__WIN32__ 
 339 wxIsAbsolutePath (const wxString
& filename
) 
 341     if (!filename
.empty()) 
 343         // Unix like or Windows 
 344         if (filename
[0] == wxT('/')) 
 347         if ((filename
[0] == wxT('[') && filename
[1] != wxT('.'))) 
 350 #if defined(__WINDOWS__) || defined(__OS2__) 
 352         if (filename
[0] == wxT('\\') || (wxIsalpha (filename
[0]) && filename
[1] == wxT(':'))) 
 359 #if WXWIN_COMPATIBILITY_2_8 
 361  * Strip off any extension (dot something) from end of file, 
 362  * IF one exists. Inserts zero into buffer. 
 367 static void wxDoStripExtension(T 
*buffer
) 
 369     int len 
= wxStrlen(buffer
); 
 373         if (buffer
[i
] == wxT('.')) 
 382 void wxStripExtension(char *buffer
) { wxDoStripExtension(buffer
); } 
 383 void wxStripExtension(wchar_t *buffer
) { wxDoStripExtension(buffer
); } 
 385 void wxStripExtension(wxString
& buffer
) 
 387    buffer 
= wxFileName::StripExtension(buffer
); 
 390 // Destructive removal of /./ and /../ stuff 
 391 template<typename CharType
> 
 392 static CharType 
*wxDoRealPath (CharType 
*path
) 
 394   static const CharType SEP 
= wxFILE_SEP_PATH
; 
 396   wxUnix2DosFilename(path
); 
 398   if (path
[0] && path
[1]) { 
 399     /* MATTHEW: special case "/./x" */ 
 401     if (path
[2] == SEP 
&& path
[1] == wxT('.')) 
 409             if (p
[1] == wxT('.') && p
[2] == wxT('.') && (p
[3] == SEP 
|| p
[3] == wxT('\0'))) 
 412                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--) 
 417                 if (q
[0] == SEP 
&& (q
[1] != wxT('.') || q
[2] != wxT('.') || q
[3] != SEP
) 
 418                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 421                     if (path
[0] == wxT('\0')) 
 426 #if defined(__WXMSW__) || defined(__OS2__) 
 427                     /* Check that path[2] is NULL! */ 
 428                     else if (path
[1] == wxT(':') && !path
[2]) 
 437             else if (p
[1] == wxT('.') && (p
[2] == SEP 
|| p
[2] == wxT('\0'))) 
 445 char *wxRealPath(char *path
) 
 447     return wxDoRealPath(path
); 
 450 wchar_t *wxRealPath(wchar_t *path
) 
 452     return wxDoRealPath(path
); 
 455 wxString 
wxRealPath(const wxString
& path
) 
 457     wxChar 
*buf1
=MYcopystring(path
); 
 458     wxChar 
*buf2
=wxRealPath(buf1
); 
 466 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 468     if (filename
.empty()) 
 471     if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer
, filename
))) 
 473         wxString buf 
= ::wxGetCwd(); 
 474         wxChar ch 
= buf
.Last(); 
 476         if (ch 
!= wxT('\\') && ch 
!= wxT('/')) 
 482         buf 
<< wxFileFunctionsBuffer
; 
 483         buf 
= wxRealPath( buf 
); 
 484         return MYcopystring( buf 
); 
 486     return MYcopystring( wxFileFunctionsBuffer 
); 
 492    ~user/ => user's home dir 
 493    If the environment variable a = "foo" and b = "bar" then: 
 510 /* input name in name, pathname output to buf. */ 
 512 template<typename CharType
> 
 513 static CharType 
*wxDoExpandPath(CharType 
*buf
, const wxString
& name
) 
 515     register CharType 
*d
, *s
, *nm
; 
 516     CharType        lnm
[_MAXPATHLEN
]; 
 519     // Some compilers don't like this line. 
 520 //    const CharType    trimchars[] = wxT("\n \t"); 
 522     CharType      trimchars
[4]; 
 523     trimchars
[0] = wxT('\n'); 
 524     trimchars
[1] = wxT(' '); 
 525     trimchars
[2] = wxT('\t'); 
 528     static const CharType SEP 
= wxFILE_SEP_PATH
; 
 530     //wxUnix2DosFilename(path); 
 536     nm 
= ::MYcopystring(static_cast<const CharType
*>(name
.c_str())); // Make a scratch copy 
 537     CharType 
*nm_tmp 
= nm
; 
 539     /* Skip leading whitespace and cr */ 
 540     while (wxStrchr(trimchars
, *nm
) != NULL
) 
 542     /* And strip off trailing whitespace and cr */ 
 543     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 544     while (q
-- && wxStrchr(trimchars
, *s
) != NULL
) 
 552     q 
= nm
[0] == wxT('\\') && nm
[1] == wxT('~'); 
 555     /* Expand inline environment variables */ 
 573     while ((*d
++ = *s
) != 0) { 
 575         if (*s 
== wxT('\\')) { 
 576             if ((*(d 
- 1) = *++s
)!=0) { 
 584             // No env variables on WinCE 
 587         if (*s
++ == wxT('$') && (*s 
== wxT('{') || *s 
== wxT(')'))) 
 589         if (*s
++ == wxT('$')) 
 592             register CharType  
*start 
= d
; 
 593             register int     braces 
= (*s 
== wxT('{') || *s 
== wxT('(')); 
 594             register CharType  
*value
; 
 595             while ((*d
++ = *s
) != 0) 
 596                 if (braces 
? (*s 
== wxT('}') || *s 
== wxT(')')) : !(wxIsalnum(*s
) || *s 
== wxT('_')) ) 
 601             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 603                 for ((d 
= start 
- 1); (*d
++ = *value
++) != 0;) 
 617     /* Expand ~ and ~user */ 
 620     if (nm
[0] == wxT('~') && !q
) 
 623         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 625             homepath 
= wxGetUserHome(wxEmptyString
); 
 626             if (!homepath
.empty()) { 
 627                 s 
= (CharType
*)(const CharType
*)homepath
.c_str(); 
 632         {                /* ~user/filename */ 
 633             register CharType  
*nnm
; 
 634             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++) 
 638             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 639             was_sep 
= (*s 
== SEP
); 
 640             nnm 
= *s 
? s 
+ 1 : s
; 
 642             homepath 
= wxGetUserHome(wxString(nm 
+ 1)); 
 643             if (homepath
.empty()) 
 645                 if (was_sep
) /* replace only if it was there: */ 
 652                 s 
= (CharType
*)(const CharType
*)homepath
.c_str(); 
 658     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 660         while (wxT('\0') != (*d
++ = *s
++)) 
 663         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 667     while ((*d
++ = *s
++) != 0) 
 671     delete[] nm_tmp
; // clean up alloc 
 672     /* Now clean up the buffer */ 
 673     return wxRealPath(buf
); 
 676 char *wxExpandPath(char *buf
, const wxString
& name
) 
 678     return wxDoExpandPath(buf
, name
); 
 681 wchar_t *wxExpandPath(wchar_t *buf
, const wxString
& name
) 
 683     return wxDoExpandPath(buf
, name
); 
 687 /* Contract Paths to be build upon an environment variable 
 690    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 692    The call wxExpandPath can convert these back! 
 695 wxContractPath (const wxString
& filename
, 
 696                 const wxString
& WXUNUSED_IN_WINCE(envname
), 
 697                 const wxString
& user
) 
 699   static wxChar dest
[_MAXPATHLEN
]; 
 701   if (filename
.empty()) 
 704   wxStrcpy (dest
, filename
); 
 706   wxUnix2DosFilename(dest
); 
 709   // Handle environment 
 713   if (!envname
.empty() && !(val 
= wxGetenv (envname
)).empty() && 
 714      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 716         wxStrcpy (wxFileFunctionsBuffer
, tcp 
+ val
.length()); 
 719         wxStrcpy (tcp
, envname
); 
 720         wxStrcat (tcp
, wxT("}")); 
 721         wxStrcat (tcp
, wxFileFunctionsBuffer
); 
 725   // Handle User's home (ignore root homes!) 
 726   val 
= wxGetUserHome (user
); 
 730   const size_t len 
= val
.length(); 
 734   if (wxStrncmp(dest
, val
, len
) == 0) 
 736     wxStrcpy(wxFileFunctionsBuffer
, wxT("~")); 
 738            wxStrcat(wxFileFunctionsBuffer
, user
); 
 739     wxStrcat(wxFileFunctionsBuffer
, dest 
+ len
); 
 740     wxStrcpy (dest
, wxFileFunctionsBuffer
); 
 746 #endif // #if WXWIN_COMPATIBILITY_2_8 
 748 // Return just the filename, not the path (basename) 
 749 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 752     wxString n 
= wxFileNameFromPath(p
); 
 754     return path 
+ p
.length() - n
.length(); 
 757 wxString 
wxFileNameFromPath (const wxString
& path
) 
 760     wxFileName::SplitPath(path
, NULL
, &name
, &ext
); 
 762     wxString fullname 
= name
; 
 765         fullname 
<< wxFILE_SEP_EXT 
<< ext
; 
 771 // Return just the directory, or NULL if no directory 
 773 wxPathOnly (wxChar 
*path
) 
 777         static wxChar buf
[_MAXPATHLEN
]; 
 780         wxStrcpy (buf
, path
); 
 782         int l 
= wxStrlen(path
); 
 785         // Search backward for a backward or forward slash 
 788             // Unix like or Windows 
 789             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 795             if (path
[i
] == wxT(']')) 
 804 #if defined(__WXMSW__) || defined(__OS2__) 
 805         // Try Drive specifier 
 806         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 808             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 818 // Return just the directory, or NULL if no directory 
 819 wxString 
wxPathOnly (const wxString
& path
) 
 823         wxChar buf
[_MAXPATHLEN
]; 
 828         int l 
= path
.length(); 
 831         // Search backward for a backward or forward slash 
 834             // Unix like or Windows 
 835             if (path
[i
] == wxT('/') || path
[i
] == wxT('\\')) 
 837                 // Don't return an empty string 
 841                 return wxString(buf
); 
 844             if (path
[i
] == wxT(']')) 
 847                 return wxString(buf
); 
 853 #if defined(__WXMSW__) || defined(__OS2__) 
 854         // Try Drive specifier 
 855         if (wxIsalpha (buf
[0]) && buf
[1] == wxT(':')) 
 857             // A:junk --> A:. (since A:.\junk Not A:\junk) 
 860             return wxString(buf
); 
 864     return wxEmptyString
; 
 867 // Utility for converting delimiters in DOS filenames to UNIX style 
 868 // and back again - or we get nasty problems with delimiters. 
 869 // Also, convert to lower case, since case is significant in UNIX. 
 871 #if defined(__WXMAC__) && !defined(__WXOSX_IPHONE__) 
 873 #define kDefaultPathStyle kCFURLPOSIXPathStyle 
 875 wxString 
wxMacFSRefToPath( const FSRef 
*fsRef 
, CFStringRef additionalPathComponent 
) 
 878     fullURLRef 
= CFURLCreateFromFSRef(NULL
, fsRef
); 
 879     if ( additionalPathComponent 
) 
 881         CFURLRef parentURLRef 
= fullURLRef 
; 
 882         fullURLRef 
= CFURLCreateCopyAppendingPathComponent(NULL
, parentURLRef
, 
 883             additionalPathComponent
,false); 
 884         CFRelease( parentURLRef 
) ; 
 886     CFStringRef cfString 
= CFURLCopyFileSystemPath(fullURLRef
, kDefaultPathStyle
); 
 887     CFRelease( fullURLRef 
) ; 
 888     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, cfString
); 
 889     CFRelease( cfString 
); 
 890     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
); 
 891     return wxCFStringRef(cfMutableString
).AsString(); 
 894 OSStatus 
wxMacPathToFSRef( const wxString
&path 
, FSRef 
*fsRef 
) 
 896     OSStatus err 
= noErr 
; 
 897     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, wxCFStringRef(path
)); 
 898     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormD
); 
 899     CFURLRef url 
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, cfMutableString 
, kDefaultPathStyle
, false); 
 900     CFRelease( cfMutableString 
); 
 903         if ( CFURLGetFSRef(url
, fsRef
) == false ) 
 914 wxString 
wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname 
) 
 916     CFStringRef cfname 
= CFStringCreateWithCharacters( kCFAllocatorDefault
, 
 919     CFMutableStringRef cfMutableString 
= CFStringCreateMutableCopy(NULL
, 0, cfname
); 
 921     CFStringNormalize(cfMutableString
,kCFStringNormalizationFormC
); 
 922     return wxCFStringRef(cfMutableString
).AsString() ; 
 927 wxString 
wxMacFSSpec2MacFilename( const FSSpec 
*spec 
) 
 930     if ( FSpMakeFSRef( spec 
, &fsRef
) == noErr 
) 
 932         return wxMacFSRefToPath( &fsRef 
) ; 
 934     return wxEmptyString 
; 
 937 void wxMacFilename2FSSpec( const wxString
& path 
, FSSpec 
*spec 
) 
 939     OSStatus err 
= noErr
; 
 941     wxMacPathToFSRef( path 
, &fsRef 
); 
 942     err 
= FSGetCatalogInfo(&fsRef
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 950 #if WXWIN_COMPATIBILITY_2_8 
 953 static void wxDoDos2UnixFilename(T 
*s
) 
 962           *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 968 void wxDos2UnixFilename(char *s
) { wxDoDos2UnixFilename(s
); } 
 969 void wxDos2UnixFilename(wchar_t *s
) { wxDoDos2UnixFilename(s
); } 
 973 #if defined(__WXMSW__) || defined(__OS2__) 
 974 wxDoUnix2DosFilename(T 
*s
) 
 976 wxDoUnix2DosFilename(T 
*WXUNUSED(s
) ) 
 979 // Yes, I really mean this to happen under DOS only! JACS 
 980 #if defined(__WXMSW__) || defined(__OS2__) 
 991 void wxUnix2DosFilename(char *s
) { wxDoUnix2DosFilename(s
); } 
 992 void wxUnix2DosFilename(wchar_t *s
) { wxDoUnix2DosFilename(s
); } 
 994 #endif // #if WXWIN_COMPATIBILITY_2_8 
 996 // Concatenate two files to form third 
 998 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
1002     wxFile 
in1(file1
), in2(file2
); 
1003     wxTempFile 
out(file3
); 
1005     if ( !in1
.IsOpened() || !in2
.IsOpened() || !out
.IsOpened() ) 
1009     unsigned char buf
[1024]; 
1011     for( int i
=0; i
<2; i
++) 
1013         wxFile 
*in 
= i
==0 ? &in1 
: &in2
; 
1015             if ( (ofs 
= in
->Read(buf
,WXSIZEOF(buf
))) == wxInvalidOffset 
) return false; 
1017                 if ( !out
.Write(buf
,ofs
) ) 
1019         } while ( ofs 
== (ssize_t
)WXSIZEOF(buf
) ); 
1022     return out
.Commit(); 
1034 // helper of generic implementation of wxCopyFile() 
1035 #if !(defined(__WIN32__) || defined(__OS2__) || defined(__PALMOS__)) && \ 
1039 wxDoCopyFile(wxFile
& fileIn
, 
1040              const wxStructStat
& fbuf
, 
1041              const wxString
& filenameDst
, 
1044     // reset the umask as we want to create the file with exactly the same 
1045     // permissions as the original one 
1048     // create file2 with the same permissions than file1 and open it for 
1052     if ( !fileOut
.Create(filenameDst
, overwrite
, fbuf
.st_mode 
& 0777) ) 
1055     // copy contents of file1 to file2 
1059         ssize_t count 
= fileIn
.Read(buf
, WXSIZEOF(buf
)); 
1060         if ( count 
== wxInvalidOffset 
) 
1067         if ( fileOut
.Write(buf
, count
) < (size_t)count 
) 
1071     // we can expect fileIn to be closed successfully, but we should ensure 
1072     // that fileOut was closed as some write errors (disk full) might not be 
1073     // detected before doing this 
1074     return fileIn
.Close() && fileOut
.Close(); 
1077 #endif // generic implementation of wxCopyFile 
1081 wxCopyFile (const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1083 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1084     // CopyFile() copies file attributes and modification time too, so use it 
1085     // instead of our code if available 
1087     // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite 
1088     if ( !::CopyFile(file1
.fn_str(), file2
.fn_str(), !overwrite
) ) 
1090         wxLogSysError(_("Failed to copy the file '%s' to '%s'"), 
1091                       file1
.c_str(), file2
.c_str()); 
1095 #elif defined(__OS2__) 
1096     if ( ::DosCopy(file1
.c_str(), file2
.c_str(), overwrite 
? DCPY_EXISTING 
: 0) != 0 ) 
1098 #elif defined(__PALMOS__) 
1099     // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ 
1101 #elif wxUSE_FILE // !Win32 
1104     // get permissions of file1 
1105     if ( wxStat( file1
.c_str(), &fbuf
) != 0 ) 
1107         // the file probably doesn't exist or we haven't the rights to read 
1109         wxLogSysError(_("Impossible to get permissions for file '%s'"), 
1114     // open file1 for reading 
1115     wxFile 
fileIn(file1
, wxFile::read
); 
1116     if ( !fileIn
.IsOpened() ) 
1119     // remove file2, if it exists. This is needed for creating 
1120     // file2 with the correct permissions in the next step 
1121     if ( wxFileExists(file2
)  && (!overwrite 
|| !wxRemoveFile(file2
))) 
1123         wxLogSysError(_("Impossible to overwrite the file '%s'"), 
1128     wxDoCopyFile(fileIn
, fbuf
, file2
, overwrite
); 
1130 #if defined(__WXMAC__) || defined(__WXCOCOA__) 
1131     // copy the resource fork of the file too if it's present 
1132     wxString pathRsrcOut
; 
1136         // suppress error messages from this block as resource forks don't have 
1140         // it's not enough to check for file existence: it always does on HFS 
1141         // but is empty for files without resources 
1142         if ( fileRsrcIn
.Open(file1 
+ wxT("/..namedfork/rsrc")) && 
1143                 fileRsrcIn
.Length() > 0 ) 
1145             // we must be using HFS or another filesystem with resource fork 
1146             // support, suppose that destination file system also is HFS[-like] 
1147             pathRsrcOut 
= file2 
+ wxT("/..namedfork/rsrc"); 
1149         else // check if we have resource fork in separate file (non-HFS case) 
1151             wxFileName 
fnRsrc(file1
); 
1152             fnRsrc
.SetName(wxT("._") + fnRsrc
.GetName()); 
1155             if ( fileRsrcIn
.Open( fnRsrc
.GetFullPath() ) ) 
1158                 fnRsrc
.SetName(wxT("._") + fnRsrc
.GetName()); 
1160                 pathRsrcOut 
= fnRsrc
.GetFullPath(); 
1165     if ( !pathRsrcOut
.empty() ) 
1167         if ( !wxDoCopyFile(fileRsrcIn
, fbuf
, pathRsrcOut
, overwrite
) ) 
1170 #endif // wxMac || wxCocoa 
1172 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 
1173     // no chmod in VA.  Should be some permission API for HPFS386 partitions 
1175     if ( chmod(file2
.fn_str(), fbuf
.st_mode
) != 0 ) 
1177         wxLogSysError(_("Impossible to set permissions for the file '%s'"), 
1181 #endif // OS/2 || Mac 
1183 #else // !Win32 && ! wxUSE_FILE 
1185     // impossible to simulate with wxWidgets API 
1188     wxUnusedVar(overwrite
); 
1191 #endif // __WXMSW__ && __WIN32__ 
1197 wxRenameFile(const wxString
& file1
, const wxString
& file2
, bool overwrite
) 
1199     if ( !overwrite 
&& wxFileExists(file2
) ) 
1203             _("Failed to rename the file '%s' to '%s' because the destination file already exists."), 
1204             file1
.c_str(), file2
.c_str() 
1210 #if !defined(__WXWINCE__) && !defined(__WXPALMOS__) 
1211     // Normal system call 
1212   if ( wxRename (file1
, file2
) == 0 ) 
1217   if (wxCopyFile(file1
, file2
, overwrite
)) { 
1218     wxRemoveFile(file1
); 
1225 bool wxRemoveFile(const wxString
& file
) 
1227 #if defined(__VISUALC__) \ 
1228  || defined(__BORLANDC__) \ 
1229  || defined(__WATCOMC__) \ 
1230  || defined(__DMC__) \ 
1231  || defined(__GNUWIN32__) \ 
1232  || (defined(__MWERKS__) && defined(__MSL__)) 
1233     int res 
= wxRemove(file
); 
1234 #elif defined(__WXMAC__) 
1235     int res 
= unlink(file
.fn_str()); 
1236 #elif defined(__WXPALMOS__) 
1238     // TODO with VFSFileDelete() 
1240     int res 
= unlink(file
.fn_str()); 
1246 bool wxMkdir(const wxString
& dir
, int perm
) 
1248 #if defined(__WXPALMOS__) 
1251 #if defined(__WXMAC__) && !defined(__UNIX__) 
1252     if ( mkdir(dir
.fn_str(), 0) != 0 ) 
1254     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 
1255     // for the GNU compiler 
1256 #elif (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || \ 
1257       (defined(__GNUWIN32__) && !defined(__MINGW32__)) ||                \ 
1258       defined(__WINE__) || defined(__WXMICROWIN__) 
1259     const wxChar 
*dirname 
= dir
.c_str(); 
1262     if ( mkdir(wxFNCONV(dirname
)) != 0 ) 
1264     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1266 #elif defined(__OS2__) 
1268     if (::DosCreateDir(dir
.c_str(), NULL
) != 0) // enhance for EAB's?? 
1269 #elif defined(__DOS__) 
1270     const wxChar 
*dirname 
= dir
.c_str(); 
1271   #if defined(__WATCOMC__) 
1273     if ( wxMkDir(wxFNSTRINGCAST 
wxFNCONV(dirname
)) != 0 ) 
1274   #elif defined(__DJGPP__) 
1275     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1277     #error "Unsupported DOS compiler!" 
1279 #else  // !MSW, !DOS and !OS/2 VAC++ 
1282     if ( CreateDirectory(dir
, NULL
) == 0 ) 
1284     if ( wxMkDir(dir
.fn_str()) != 0 ) 
1288         wxLogSysError(_("Directory '%s' couldn't be created"), dir
); 
1293 #endif // PALMOS/!PALMOS 
1296 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1298 #if defined(__VMS__) 
1299     return false; //to be changed since rmdir exists in VMS7.x 
1300 #elif defined(__WXPALMOS__) 
1301     // TODO with VFSFileRename() 
1304   #if defined(__OS2__) 
1305     if ( ::DosDeleteDir(dir
.c_str()) != 0 ) 
1306   #elif defined(__WXWINCE__) 
1307     if ( RemoveDirectory(dir
) == 0 ) 
1309     if ( wxRmDir(dir
.fn_str()) != 0 ) 
1312         wxLogSysError(_("Directory '%s' couldn't be deleted"), dir
); 
1317 #endif // PALMOS/!PALMOS 
1320 // does the path exists? (may have or not '/' or '\\' at the end) 
1321 bool wxDirExists(const wxString
& pathName
) 
1323     wxString 
strPath(pathName
); 
1325 #if defined(__WINDOWS__) || defined(__OS2__) 
1326     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
1327     // so remove all trailing backslashes from the path - but don't do this for 
1328     // the paths "d:\" (which are different from "d:") nor for just "\" 
1329     while ( wxEndsWithPathSeparator(strPath
) ) 
1331         size_t len 
= strPath
.length(); 
1332         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == _T(':')) ) 
1335         strPath
.Truncate(len 
- 1); 
1337 #endif // __WINDOWS__ 
1340     // OS/2 can't handle "d:", it wants either "d:\" or "d:." 
1341     if (strPath
.length() == 2 && strPath
[1u] == _T(':')) 
1345 #if defined(__WXPALMOS__) 
1347 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
1348     // stat() can't cope with network paths 
1349     DWORD ret 
= ::GetFileAttributes(strPath
.fn_str()); 
1351     return (ret 
!= INVALID_FILE_ATTRIBUTES
) && (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
1352 #elif defined(__OS2__) 
1353     FILESTATUS3 Info 
= {{0}}; 
1354     APIRET rc 
= ::DosQueryPathInfo((PSZ
)(WXSTRINGCAST strPath
), FIL_STANDARD
, 
1355                                    (void*) &Info
, sizeof(FILESTATUS3
)); 
1357     return ((rc 
== NO_ERROR
) && (Info
.attrFile 
& FILE_DIRECTORY
)) || 
1358       (rc 
== ERROR_SHARING_VIOLATION
); 
1359     // If we got a sharing violation, there must be something with this name. 
1363 #ifndef __VISAGECPP__ 
1364     return wxStat(strPath
.c_str(), &st
) == 0 && ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
1366     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
1367     return wxStat(strPath
.c_str(), &st
) == 0 && (st
.st_mode 
== S_IFDIR
); 
1370 #endif // __WIN32__/!__WIN32__ 
1373 #if WXWIN_COMPATIBILITY_2_8 
1375 // Get a temporary filename, opening and closing the file. 
1376 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1379     if ( !wxGetTempFileName(prefix
, filename
) ) 
1384         // work around the PalmOS pacc compiler bug 
1385         wxStrcpy(buf
, filename
.data()); 
1387         wxStrcpy(buf
, filename
); 
1390         buf 
= MYcopystring(filename
); 
1395 bool wxGetTempFileName(const wxString
& prefix
, wxString
& buf
) 
1398     buf 
= wxFileName::CreateTempFileName(prefix
); 
1400     return !buf
.empty(); 
1401 #else // !wxUSE_FILE 
1402     wxUnusedVar(prefix
); 
1406 #endif // wxUSE_FILE/!wxUSE_FILE 
1409 #endif // #if WXWIN_COMPATIBILITY_2_8 
1411 // Get first file name matching given wild card. 
1413 static wxDir 
*gs_dir 
= NULL
; 
1414 static wxString gs_dirPath
; 
1416 wxString 
wxFindFirstFile(const wxString
& spec
, int flags
) 
1418     wxFileName::SplitPath(spec
, &gs_dirPath
, NULL
, NULL
); 
1419     if ( gs_dirPath
.empty() ) 
1420         gs_dirPath 
= wxT("."); 
1421     if ( !wxEndsWithPathSeparator(gs_dirPath 
) ) 
1422         gs_dirPath 
<< wxFILE_SEP_PATH
; 
1424     delete gs_dir
; // can be NULL, this is ok 
1425     gs_dir 
= new wxDir(gs_dirPath
); 
1427     if ( !gs_dir
->IsOpened() ) 
1429         wxLogSysError(_("Can not enumerate files '%s'"), spec
); 
1430         return wxEmptyString
; 
1436         case wxDIR
:  dirFlags 
= wxDIR_DIRS
; break; 
1437         case wxFILE
: dirFlags 
= wxDIR_FILES
; break; 
1438         default:     dirFlags 
= wxDIR_DIRS 
| wxDIR_FILES
; break; 
1442     gs_dir
->GetFirst(&result
, wxFileNameFromPath(spec
), dirFlags
); 
1443     if ( result
.empty() ) 
1449     return gs_dirPath 
+ result
; 
1452 wxString 
wxFindNextFile() 
1454     wxCHECK_MSG( gs_dir
, "", "You must call wxFindFirstFile before!" ); 
1457     gs_dir
->GetNext(&result
); 
1459     if ( result
.empty() ) 
1465     return gs_dirPath 
+ result
; 
1469 // Get current working directory. 
1470 // If buf is NULL, allocates space using new, else copies into buf. 
1471 // wxGetWorkingDirectory() is obsolete, use wxGetCwd() 
1472 // wxDoGetCwd() is their common core to be moved 
1473 // to wxGetCwd() once wxGetWorkingDirectory() will be removed. 
1474 // Do not expose wxDoGetCwd in headers! 
1476 wxChar 
*wxDoGetCwd(wxChar 
*buf
, int sz
) 
1478 #if defined(__WXPALMOS__) 
1480     if(buf 
&& sz
>0) buf
[0] = _T('\0'); 
1482 #elif defined(__WXWINCE__) 
1484     if(buf 
&& sz
>0) buf
[0] = _T('\0'); 
1489         buf 
= new wxChar
[sz 
+ 1]; 
1492     bool ok 
wxDUMMY_INITIALIZE(false); 
1494     // for the compilers which have Unicode version of _getcwd(), call it 
1495     // directly, for the others call the ANSI version and do the translation 
1498 #else // wxUSE_UNICODE 
1499     bool needsANSI 
= true; 
1501     #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU 
1502         char cbuf
[_MAXPATHLEN
]; 
1506         #if wxUSE_UNICODE_MSLU 
1507             if ( wxGetOsVersion() != wxOS_WINDOWS_9X 
) 
1509             char *cbuf 
= NULL
; // never really used because needsANSI will always be false 
1512                 ok 
= _wgetcwd(buf
, sz
) != NULL
; 
1518 #endif // wxUSE_UNICODE 
1520     #if defined(_MSC_VER) || defined(__MINGW32__) 
1521         ok 
= _getcwd(cbuf
, sz
) != NULL
; 
1522     #elif defined(__OS2__) 
1524         ULONG ulDriveNum 
= 0; 
1525         ULONG ulDriveMap 
= 0; 
1526         rc 
= ::DosQueryCurrentDisk(&ulDriveNum
, &ulDriveMap
); 
1531             rc 
= ::DosQueryCurrentDir( 0 // current drive 
1535             cbuf
[0] = char('A' + (ulDriveNum 
- 1)); 
1540     #else // !Win32/VC++ !Mac !OS2 
1541         ok 
= getcwd(cbuf
, sz
) != NULL
; 
1545         // finally convert the result to Unicode if needed 
1546         wxConvFile
.MB2WC(buf
, cbuf
, sz
); 
1547     #endif // wxUSE_UNICODE 
1552         wxLogSysError(_("Failed to get the working directory")); 
1554         // VZ: the old code used to return "." on error which didn't make any 
1555         //     sense at all to me - empty string is a better error indicator 
1556         //     (NULL might be even better but I'm afraid this could lead to 
1557         //     problems with the old code assuming the return is never NULL) 
1560     else // ok, but we might need to massage the path into the right format 
1563         // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths 
1564         //     with / deliminers. We don't like that. 
1565         for (wxChar 
*ch 
= buf
; *ch
; ch
++) 
1567             if (*ch 
== wxT('/')) 
1572 // MBN: we hope that in the case the user is compiling a GTK+/Motif app, 
1573 //      he needs Unix as opposed to Win32 pathnames 
1574 #if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) 
1575         // another example of DOS/Unix mix (Cygwin) 
1576         wxString pathUnix 
= buf
; 
1578         char bufA
[_MAXPATHLEN
]; 
1579         cygwin_conv_to_full_win32_path(pathUnix
.mb_str(wxConvFile
), bufA
); 
1580         wxConvFile
.MB2WC(buf
, bufA
, sz
); 
1582         cygwin_conv_to_full_win32_path(pathUnix
, buf
); 
1583 #endif // wxUSE_UNICODE 
1584 #endif // __CYGWIN__ 
1597 #if WXWIN_COMPATIBILITY_2_6 
1598 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1600     return wxDoGetCwd(buf
,sz
); 
1602 #endif // WXWIN_COMPATIBILITY_2_6 
1607     wxDoGetCwd(wxStringBuffer(str
, _MAXPATHLEN
), _MAXPATHLEN
); 
1611 bool wxSetWorkingDirectory(const wxString
& d
) 
1613 #if defined(__OS2__) 
1616         ::DosSetDefaultDisk(wxToupper(d
[0]) - _T('A') + 1); 
1617     // do not call DosSetCurrentDir when just changing drive, 
1618     // since it requires e.g. "d:." instead of "d:"! 
1619     if (d
.length() == 2) 
1622     return (::DosSetCurrentDir(d
.c_str()) == 0); 
1623 #elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) 
1624     return (chdir(wxFNSTRINGCAST d
.fn_str()) == 0); 
1625 #elif defined(__WINDOWS__) 
1629     // No equivalent in WinCE 
1633     return (bool)(SetCurrentDirectory(d
.fn_str()) != 0); 
1636     // Must change drive, too. 
1637     bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1640         wxChar firstChar 
= d
[0]; 
1644             firstChar 
= firstChar 
- 32; 
1646         // To a drive number 
1647         unsigned int driveNo 
= firstChar 
- 64; 
1650             unsigned int noDrives
; 
1651             _dos_setdrive(driveNo
, &noDrives
); 
1654     bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1662 // Get the OS directory if appropriate (such as the Windows directory). 
1663 // On non-Windows platform, probably just return the empty string. 
1664 wxString 
wxGetOSDirectory() 
1667     return wxString(wxT("\\Windows")); 
1668 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1670     GetWindowsDirectory(buf
, 256); 
1671     return wxString(buf
); 
1672 #elif defined(__WXMAC__) && wxOSX_USE_CARBON 
1673     return wxMacFindFolder(kOnSystemDisk
, 'macs', false); 
1675     return wxEmptyString
; 
1679 bool wxEndsWithPathSeparator(const wxString
& filename
) 
1681     return !filename
.empty() && wxIsPathSeparator(filename
.Last()); 
1684 // find a file in a list of directories, returns false if not found 
1685 bool wxFindFileInPath(wxString 
*pStr
, const wxString
& szPath
, const wxString
& szFile
) 
1687     // we assume that it's not empty 
1688     wxCHECK_MSG( !szFile
.empty(), false, 
1689                  _T("empty file name in wxFindFileInPath")); 
1691     // skip path separator in the beginning of the file name if present 
1693     if ( wxIsPathSeparator(szFile
[0u]) ) 
1694         szFile2 
= szFile
.Mid(1); 
1698     wxStringTokenizer 
tkn(szPath
, wxPATH_SEP
); 
1700     while ( tkn
.HasMoreTokens() ) 
1702         wxString strFile 
= tkn
.GetNextToken(); 
1703         if ( !wxEndsWithPathSeparator(strFile
) ) 
1704             strFile 
+= wxFILE_SEP_PATH
; 
1707         if ( wxFileExists(strFile
) ) 
1717 #if WXWIN_COMPATIBILITY_2_8 
1718 void WXDLLIMPEXP_BASE 
wxSplitPath(const wxString
& fileName
, 
1723     wxFileName::SplitPath(fileName
, pstrPath
, pstrName
, pstrExt
); 
1725 #endif  // #if WXWIN_COMPATIBILITY_2_8 
1729 time_t WXDLLIMPEXP_BASE 
wxFileModificationTime(const wxString
& filename
) 
1732     if ( !wxFileName(filename
).GetTimes(NULL
, &mtime
, NULL
) ) 
1735     return mtime
.GetTicks(); 
1738 #endif // wxUSE_DATETIME 
1741 // Parses the filterStr, returning the number of filters. 
1742 // Returns 0 if none or if there's a problem. 
1743 // filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" 
1745 int WXDLLIMPEXP_BASE 
wxParseCommonDialogsFilter(const wxString
& filterStr
, 
1746                                            wxArrayString
& descriptions
, 
1747                                            wxArrayString
& filters
) 
1749     descriptions
.Clear(); 
1752     wxString 
str(filterStr
); 
1754     wxString description
, filter
; 
1756     while( pos 
!= wxNOT_FOUND 
) 
1758         pos 
= str
.Find(wxT('|')); 
1759         if ( pos 
== wxNOT_FOUND 
) 
1761             // if there are no '|'s at all in the string just take the entire 
1762             // string as filter and make description empty for later autocompletion 
1763             if ( filters
.IsEmpty() ) 
1765                 descriptions
.Add(wxEmptyString
); 
1766                 filters
.Add(filterStr
); 
1770                 wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); 
1776         description 
= str
.Left(pos
); 
1777         str 
= str
.Mid(pos 
+ 1); 
1778         pos 
= str
.Find(wxT('|')); 
1779         if ( pos 
== wxNOT_FOUND 
) 
1785             filter 
= str
.Left(pos
); 
1786             str 
= str
.Mid(pos 
+ 1); 
1789         descriptions
.Add(description
); 
1790         filters
.Add(filter
); 
1793 #if defined(__WXMOTIF__) 
1794     // split it so there is one wildcard per entry 
1795     for( size_t i 
= 0 ; i 
< descriptions
.GetCount() ; i
++ ) 
1797         pos 
= filters
[i
].Find(wxT(';')); 
1798         if (pos 
!= wxNOT_FOUND
) 
1800             // first split only filters 
1801             descriptions
.Insert(descriptions
[i
],i
+1); 
1802             filters
.Insert(filters
[i
].Mid(pos
+1),i
+1); 
1803             filters
[i
]=filters
[i
].Left(pos
); 
1805             // autoreplace new filter in description with pattern: 
1806             //     C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h 
1807             // cause split into: 
1808             //     C/C++ Files(*.cpp)|*.cpp 
1809             //     C/C++ Files(*.c;*.h)|*.c;*.h 
1810             // and next iteration cause another split into: 
1811             //     C/C++ Files(*.cpp)|*.cpp 
1812             //     C/C++ Files(*.c)|*.c 
1813             //     C/C++ Files(*.h)|*.h 
1814             for ( size_t k
=i
;k
<i
+2;k
++ ) 
1816                 pos 
= descriptions
[k
].Find(filters
[k
]); 
1817                 if (pos 
!= wxNOT_FOUND
) 
1819                     wxString before 
= descriptions
[k
].Left(pos
); 
1820                     wxString after 
= descriptions
[k
].Mid(pos
+filters
[k
].Len()); 
1821                     pos 
= before
.Find(_T('('),true); 
1822                     if (pos
>before
.Find(_T(')'),true)) 
1824                         before 
= before
.Left(pos
+1); 
1825                         before 
<< filters
[k
]; 
1826                         pos 
= after
.Find(_T(')')); 
1827                         int pos1 
= after
.Find(_T('(')); 
1828                         if (pos 
!= wxNOT_FOUND 
&& (pos
<pos1 
|| pos1
==wxNOT_FOUND
)) 
1830                             before 
<< after
.Mid(pos
); 
1831                             descriptions
[k
] = before
; 
1841     for( size_t j 
= 0 ; j 
< descriptions
.GetCount() ; j
++ ) 
1843         if ( descriptions
[j
].empty() && !filters
[j
].empty() ) 
1845             descriptions
[j
].Printf(_("Files (%s)"), filters
[j
].c_str()); 
1849     return filters
.GetCount(); 
1852 #if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__)) 
1853 static bool wxCheckWin32Permission(const wxString
& path
, DWORD access
) 
1855     // quoting the MSDN: "To obtain a handle to a directory, call the 
1856     // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this 
1857     // doesn't work under Win9x/ME but then it's not needed there anyhow 
1858     const DWORD dwAttr 
= ::GetFileAttributes(path
.fn_str()); 
1859     if ( dwAttr 
== INVALID_FILE_ATTRIBUTES 
) 
1861         // file probably doesn't exist at all 
1865     if ( wxGetOsVersion() == wxOS_WINDOWS_9X 
) 
1867         // FAT directories always allow all access, even if they have the 
1868         // readonly flag set, and FAT files can only be read-only 
1869         return (dwAttr 
& FILE_ATTRIBUTE_DIRECTORY
) || 
1870                     (access 
!= GENERIC_WRITE 
|| 
1871                         !(dwAttr 
& FILE_ATTRIBUTE_READONLY
)); 
1874     HANDLE h 
= ::CreateFile
 
1878                     FILE_SHARE_READ 
| FILE_SHARE_WRITE 
| FILE_SHARE_DELETE
, 
1881                     dwAttr 
& FILE_ATTRIBUTE_DIRECTORY
 
1882                         ? FILE_FLAG_BACKUP_SEMANTICS
 
1886     if ( h 
!= INVALID_HANDLE_VALUE 
) 
1889     return h 
!= INVALID_HANDLE_VALUE
; 
1891 #endif // __WINDOWS__ 
1893 bool wxIsWritable(const wxString 
&path
) 
1895 #if defined( __UNIX__ ) || defined(__OS2__) 
1896     // access() will take in count also symbolic links 
1897     return wxAccess(path
.c_str(), W_OK
) == 0; 
1898 #elif defined( __WINDOWS__ ) 
1899     return wxCheckWin32Permission(path
, GENERIC_WRITE
); 
1907 bool wxIsReadable(const wxString 
&path
) 
1909 #if defined( __UNIX__ ) || defined(__OS2__) 
1910     // access() will take in count also symbolic links 
1911     return wxAccess(path
.c_str(), R_OK
) == 0; 
1912 #elif defined( __WINDOWS__ ) 
1913     return wxCheckWin32Permission(path
, GENERIC_READ
); 
1921 bool wxIsExecutable(const wxString 
&path
) 
1923 #if defined( __UNIX__ ) || defined(__OS2__) 
1924     // access() will take in count also symbolic links 
1925     return wxAccess(path
.c_str(), X_OK
) == 0; 
1926 #elif defined( __WINDOWS__ ) 
1927    return wxCheckWin32Permission(path
, GENERIC_EXECUTE
); 
1935 // Return the type of an open file 
1937 // Some file types on some platforms seem seekable but in fact are not. 
1938 // The main use of this function is to allow such cases to be detected 
1939 // (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK). 
1941 // This is important for the archive streams, which benefit greatly from 
1942 // being able to seek on a stream, but which will produce corrupt archives 
1943 // if they unknowingly seek on a non-seekable stream. 
1945 // wxFILE_KIND_DISK is a good catch all return value, since other values 
1946 // disable features of the archive streams. Some other value must be returned 
1947 // for a file type that appears seekable but isn't. 
1950 //   *  Pipes on Windows 
1951 //   *  Files on VMS with a record format other than StreamLF 
1953 wxFileKind 
wxGetFileKind(int fd
) 
1955 #if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle 
1956     switch (::GetFileType(wxGetOSFHandle(fd
)) & ~FILE_TYPE_REMOTE
) 
1958         case FILE_TYPE_CHAR
: 
1959             return wxFILE_KIND_TERMINAL
; 
1960         case FILE_TYPE_DISK
: 
1961             return wxFILE_KIND_DISK
; 
1962         case FILE_TYPE_PIPE
: 
1963             return wxFILE_KIND_PIPE
; 
1966     return wxFILE_KIND_UNKNOWN
; 
1968 #elif defined(__UNIX__) 
1970         return wxFILE_KIND_TERMINAL
; 
1975     if (S_ISFIFO(st
.st_mode
)) 
1976         return wxFILE_KIND_PIPE
; 
1977     if (!S_ISREG(st
.st_mode
)) 
1978         return wxFILE_KIND_UNKNOWN
; 
1980     #if defined(__VMS__) 
1981         if (st
.st_fab_rfm 
!= FAB$C_STMLF
) 
1982             return wxFILE_KIND_UNKNOWN
; 
1985     return wxFILE_KIND_DISK
; 
1988     #define wxFILEKIND_STUB 
1990     return wxFILE_KIND_DISK
; 
1994 wxFileKind 
wxGetFileKind(FILE *fp
) 
1996     // Note: The watcom rtl dll doesn't have fileno (the static lib does). 
1997     //       Should be fixed in version 1.4. 
1998 #if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4) 
2000     return wxFILE_KIND_DISK
; 
2001 #elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__) 
2002     return fp 
? wxGetFileKind(_fileno(fp
)) : wxFILE_KIND_UNKNOWN
; 
2004     return fp 
? wxGetFileKind(fileno(fp
)) : wxFILE_KIND_UNKNOWN
; 
2009 //------------------------------------------------------------------------ 
2010 // wild character routines 
2011 //------------------------------------------------------------------------ 
2013 bool wxIsWild( const wxString
& pattern 
) 
2015     for ( wxString::const_iterator p 
= pattern
.begin(); p 
!= pattern
.end(); ++p 
) 
2017         switch ( (*p
).GetValue() ) 
2026                 if ( ++p 
== pattern
.end() ) 
2034 * Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU> 
2036 * The match procedure is public domain code (from ircII's reg.c) 
2037 * but modified to suit our tastes (RN: No "%" syntax I guess) 
2040 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
2044         /* Match if both are empty. */ 
2048     const wxChar 
*m 
= pat
.c_str(), 
2056     if (dot_special 
&& (*n 
== wxT('.'))) 
2058         /* Never match so that hidden Unix files 
2059          * are never found. */ 
2072         else if (*m 
== wxT('?')) 
2080             if (*m 
== wxT('\\')) 
2083                 /* Quoting "nothing" is a bad thing */ 
2090                 * If we are out of both strings or we just 
2091                 * saw a wildcard, then we can say we have a 
2102             * We could check for *n == NULL at this point, but 
2103             * since it's more common to have a character there, 
2104             * check to see if they match first (m and n) and 
2105             * then if they don't match, THEN we can check for 
2121                 * If there are no more characters in the 
2122                 * string, but we still need to find another 
2123                 * character (*m != NULL), then it will be 
2124                 * impossible to match it 
2143     #pragma warning(default:4706)   // assignment within conditional expression