1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     File- and directory-related functions 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) 1998 Julian Smart 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13     #pragma implementation "filefn.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  31 // there are just too many of those... 
  33     #pragma warning(disable:4706)   // assignment within conditional expression 
  40 #if !defined(__WATCOMC__) 
  41     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  49     #include <sys/types.h> 
  62 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__) 
  66 #endif // native Win compiler 
  70         #include <sys/unistd.h> 
  73     #define stricmp strcasecmp 
  76 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
  77                     // this (3.1 I believe) and how to test for it. 
  78                     // If this works for Borland 4.0 as well, then no worries. 
  90 // No, Cygwin doesn't appear to have fnmatch.h after all. 
  91 #if defined(HAVE_FNMATCH_H) 
  99 #define _MAXPATHLEN 500 
 101 extern wxChar 
*wxBuffer
; 
 103     extern wxChar gwxMacFileName
[] ; 
 104     extern wxChar gwxMacFileName2
[] ; 
 105     extern wxChar gwxMacFileName3
[] ; 
 108 #if !USE_SHARED_LIBRARIES 
 109     IMPLEMENT_DYNAMIC_CLASS(wxPathList
, wxStringList
) 
 112 void wxPathList::Add (const wxString
& path
) 
 114     wxStringList::Add (WXSTRINGCAST path
); 
 117 // Add paths e.g. from the PATH environment variable 
 118 void wxPathList::AddEnvList (const wxString
& envVariable
) 
 120   static const wxChar PATH_TOKS
[] = 
 122         _T(" ;"); // Don't seperate with colon in DOS (used for drive) 
 127   wxChar 
*val 
= wxGetenv (WXSTRINGCAST envVariable
); 
 130       wxChar 
*s 
= copystring (val
); 
 131       wxChar 
*save_ptr
, *token 
= wxStrtok (s
, PATH_TOKS
, &save_ptr
); 
 135           Add (copystring (token
)); 
 138               if ((token 
= wxStrtok ((wxChar 
*) NULL
, PATH_TOKS
, &save_ptr
)) != NULL
) 
 139                 Add (wxString(token
)); 
 146 // Given a full filename (with path), ensure that that file can 
 147 // be accessed again USING FILENAME ONLY by adding the path 
 148 // to the list if not already there. 
 149 void wxPathList::EnsureFileAccessible (const wxString
& path
) 
 151     wxString 
path_only(wxPathOnly(path
)); 
 152     if ( !path_only
.IsEmpty() ) 
 154         if ( !Member(path_only
) ) 
 159 bool wxPathList::Member (const wxString
& path
) 
 161   for (wxNode 
* node 
= First (); node 
!= NULL
; node 
= node
->Next ()) 
 163       wxString 
path2((wxChar 
*) node
->Data ()); 
 165 #if defined(__WINDOWS__) || defined(__VMS__) || defined (__WXMAC__) 
 167           path
.CompareTo (path2
, wxString::ignoreCase
) == 0 
 169       // Case sensitive File System 
 170           path
.CompareTo (path2
) == 0 
 178 wxString 
wxPathList::FindValidPath (const wxString
& file
) 
 180   if (wxFileExists (wxExpandPath(wxBuffer
, file
))) 
 181     return wxString(wxBuffer
); 
 183   wxChar buf
[_MAXPATHLEN
]; 
 184   wxStrcpy(buf
, wxBuffer
); 
 186   wxChar 
*filename 
= (wxChar
*) NULL
; /* shut up buggy egcs warning */ 
 187   filename 
= IsAbsolutePath (buf
) ? wxFileNameFromPath (buf
) : (wxChar 
*)buf
; 
 189   for (wxNode 
* node 
= First (); node
; node 
= node
->Next ()) 
 191       wxChar 
*path 
= (wxChar 
*) node
->Data (); 
 192       wxStrcpy (wxBuffer
, path
); 
 193       wxChar ch 
= wxBuffer
[wxStrlen(wxBuffer
)-1]; 
 194       if (ch 
!= _T('\\') && ch 
!= _T('/')) 
 195         wxStrcat (wxBuffer
, _T("/")); 
 196       wxStrcat (wxBuffer
, filename
); 
 198       Unix2DosFilename (wxBuffer
); 
 200       if (wxFileExists (wxBuffer
)) 
 202         return wxString(wxBuffer
);        // Found! 
 206   return wxString(_T(""));                    // Not found 
 209 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) 
 211   wxString f 
= FindValidPath(file
); 
 212   if (wxIsAbsolutePath(f
)) 
 217     wxGetWorkingDirectory(buf
, 499); 
 218     int len 
= (int)wxStrlen(buf
); 
 222     if (lastCh 
!= _T('/') && lastCh 
!= _T('\\')) 
 225       wxStrcat(buf
, _T("\\")); 
 227       wxStrcat(buf
, _T("/")); 
 230     wxStrcat(buf
, (const wxChar 
*)f
); 
 231     wxStrcpy(wxBuffer
, buf
); 
 232     return wxString(wxBuffer
); 
 237 wxFileExists (const wxString
& filename
) 
 239 #ifdef __GNUWIN32__ // (fix a B20 bug) 
 240   if (GetFileAttributes(filename
) == 0xFFFFFFFF) 
 244 #elif defined(__WXMAC__) 
 246         wxStrcpy( gwxMacFileName 
, filename 
) ; 
 247         wxUnix2MacFilename( gwxMacFileName 
) ; 
 248           if (gwxMacFileName 
&& stat (WXSTRINGCAST gwxMacFileName
, &stbuf
) == 0) 
 259   if ((filename 
!= _T("")) && stat (FNSTRINGCAST filename
.fn_str(), &stbuf
) == 0) 
 265 /* Vadim's alternative implementation 
 267 // does the file exist? 
 268 bool wxFileExists(const char *pszFileName) 
 271   return !access(pszFileName, 0) && 
 272          !stat(pszFileName, &st) && 
 273          (st.st_mode & S_IFREG); 
 278 wxIsAbsolutePath (const wxString
& filename
) 
 280   if (filename 
!= _T("")) 
 282       if (filename
[0] == _T('/') 
 284       || (filename
[0] == _T('[') && filename
[1] != _T('.')) 
 288       || filename
[0] == _T('\\') || (wxIsalpha (filename
[0]) && filename
[1] == _T(':')) 
 297  * Strip off any extension (dot something) from end of file, 
 298  * IF one exists. Inserts zero into buffer. 
 302 void wxStripExtension(wxChar 
*buffer
) 
 304   int len 
= wxStrlen(buffer
); 
 308     if (buffer
[i
] == _T('.')) 
 317 void wxStripExtension(wxString
& buffer
) 
 319   size_t len 
= buffer
.Length(); 
 323     if (buffer
.GetChar(i
) == _T('.')) 
 325       buffer 
= buffer
.Left(i
); 
 332 // Destructive removal of /./ and /../ stuff 
 333 wxChar 
*wxRealPath (wxChar 
*path
) 
 336   static const wxChar SEP 
= _T('\\'); 
 337   Unix2DosFilename(path
); 
 339   static const wxChar SEP 
= _T('/'); 
 341   if (path
[0] && path
[1]) { 
 342     /* MATTHEW: special case "/./x" */ 
 344     if (path
[2] == SEP 
&& path
[1] == _T('.')) 
 352             if (p
[1] == _T('.') && p
[2] == _T('.') && (p
[3] == SEP 
|| p
[3] == _T('\0'))) 
 355                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--); 
 356                 if (q
[0] == SEP 
&& (q
[1] != _T('.') || q
[2] != _T('.') || q
[3] != SEP
) 
 357                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 360                     if (path
[0] == _T('\0')) 
 366                     /* Check that path[2] is NULL! */ 
 367                     else if (path
[1] == _T(':') && !path
[2]) 
 376             else if (p
[1] == _T('.') && (p
[2] == SEP 
|| p
[2] == _T('\0'))) 
 385 wxChar 
*wxCopyAbsolutePath(const wxString
& filename
) 
 387   if (filename 
== _T("")) 
 388     return (wxChar 
*) NULL
; 
 390   if (! IsAbsolutePath(wxExpandPath(wxBuffer
, filename
))) { 
 391     wxChar  buf
[_MAXPATHLEN
]; 
 393     wxGetWorkingDirectory(buf
, WXSIZEOF(buf
)); 
 394     wxChar ch 
= buf
[wxStrlen(buf
) - 1]; 
 396     if (ch 
!= _T('\\') && ch 
!= _T('/')) 
 397         wxStrcat(buf
, _T("\\")); 
 400         wxStrcat(buf
, _T("/")); 
 402     wxStrcat(buf
, wxBuffer
); 
 403     return copystring( wxRealPath(buf
) ); 
 405   return copystring( wxBuffer 
); 
 411    ~user/ => user's home dir 
 412    If the environment variable a = "foo" and b = "bar" then: 
 429 /* input name in name, pathname output to buf. */ 
 431 wxChar 
*wxExpandPath(wxChar 
*buf
, const wxChar 
*name
) 
 433     register wxChar 
*d
, *s
, *nm
; 
 434     wxChar          lnm
[_MAXPATHLEN
]; 
 437     // Some compilers don't like this line. 
 438 //    const wxChar    trimchars[] = _T("\n \t"); 
 441     trimchars
[0] = _T('\n'); 
 442     trimchars
[1] = _T(' '); 
 443     trimchars
[2] = _T('\t'); 
 447      const wxChar     SEP 
= _T('\\'); 
 449      const wxChar     SEP 
= _T('/'); 
 452     if (name 
== NULL 
|| *name 
== _T('\0')) 
 454     nm 
= copystring(name
); // Make a scratch copy 
 457     /* Skip leading whitespace and cr */ 
 458     while (wxStrchr((wxChar 
*)trimchars
, *nm
) != NULL
) 
 460     /* And strip off trailing whitespace and cr */ 
 461     s 
= nm 
+ (q 
= wxStrlen(nm
)) - 1; 
 462     while (q
-- && wxStrchr((wxChar 
*)trimchars
, *s
) != NULL
) 
 470     q 
= nm
[0] == _T('\\') && nm
[1] == _T('~'); 
 473     /* Expand inline environment variables */ 
 474     while ((*d
++ = *s
)) { 
 476         if (*s 
== _T('\\')) { 
 477             if ((*(d 
- 1) = *++s
)) { 
 485         if (*s
++ == _T('$') && (*s 
== _T('{') || *s 
== _T(')'))) 
 490             register wxChar  
*start 
= d
; 
 491             register int     braces 
= (*s 
== _T('{') || *s 
== _T('(')); 
 492             register wxChar  
*value
; 
 494                 if (braces 
? (*s 
== _T('}') || *s 
== _T(')')) : !(wxIsalnum(*s
) || *s 
== _T('_')) ) 
 499             value 
= wxGetenv(braces 
? start 
+ 1 : start
); 
 501                 for ((d 
= start 
- 1); (*d
++ = *value
++);); 
 509     /* Expand ~ and ~user */ 
 512     if (nm
[0] == _T('~') && !q
) 
 515         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 517             // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 518             if ((s 
= WXSTRINGCAST 
wxGetUserHome(_T(""))) != NULL
) { 
 523         {                /* ~user/filename */ 
 524             register wxChar  
*nnm
; 
 525             register wxChar  
*home
; 
 526             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++); 
 527             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 528             was_sep 
= (*s 
== SEP
); 
 529             nnm 
= *s 
? s 
+ 1 : s
; 
 531             // FIXME: wxGetUserHome could return temporary storage in Unicode mode 
 532             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 533                if (was_sep
) /* replace only if it was there: */ 
 544     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 546         while (_T('\0') != (*d
++ = *s
++)) 
 549         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 553     while ((*d
++ = *s
++)); 
 555     delete[] nm_tmp
; // clean up alloc 
 556     /* Now clean up the buffer */ 
 557     return wxRealPath(buf
); 
 561 /* Contract Paths to be build upon an environment variable 
 564    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 566    The call wxExpandPath can convert these back! 
 569 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 571   static wxChar dest
[_MAXPATHLEN
]; 
 573   if (filename 
== _T("")) 
 574     return (wxChar 
*) NULL
; 
 576   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 578   Unix2DosFilename(dest
); 
 581   // Handle environment 
 582   const wxChar 
*val 
= (const wxChar 
*) NULL
; 
 583   wxChar 
*tcp 
= (wxChar 
*) NULL
; 
 584   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 585      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 587         wxStrcpy (wxBuffer
, tcp 
+ wxStrlen (val
)); 
 590         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 591         wxStrcat (tcp
, _T("}")); 
 592         wxStrcat (tcp
, wxBuffer
); 
 595   // Handle User's home (ignore root homes!) 
 597   if ((val 
= wxGetUserHome (user
)) != NULL 
&& 
 598       (len 
= wxStrlen(val
)) > 2 && 
 599       wxStrncmp(dest
, val
, len
) == 0) 
 601       wxStrcpy(wxBuffer
, _T("~")); 
 603              wxStrcat(wxBuffer
, (const wxChar
*) user
); 
 605 //      strcat(wxBuffer, "\\"); 
 607 //      strcat(wxBuffer, "/"); 
 609       wxStrcat(wxBuffer
, dest 
+ len
); 
 610       wxStrcpy (dest
, wxBuffer
); 
 616 // Return just the filename, not the path 
 618 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 622       register wxChar 
*tcp
; 
 624       tcp 
= path 
+ wxStrlen (path
); 
 625       while (--tcp 
>= path
) 
 627           if (*tcp 
== _T('/') || *tcp 
== _T('\\') 
 629      || *tcp 
== _T(':') || *tcp 
== _T(']')) 
 636       if (wxIsalpha (*path
) && *(path 
+ 1) == _T(':')) 
 643 wxString 
wxFileNameFromPath (const wxString
& path1
) 
 648       wxChar 
*path 
= WXSTRINGCAST path1 
; 
 649       register wxChar 
*tcp
; 
 651       tcp 
= path 
+ wxStrlen (path
); 
 652       while (--tcp 
>= path
) 
 654             if (*tcp 
== _T('/') || *tcp 
== _T('\\') 
 656         || *tcp 
== _T(':') || *tcp 
== _T(']')) 
 660                 return wxString(tcp 
+ 1); 
 663       if (wxIsalpha (*path
) && *(path 
+ 1) == _T(':')) 
 664             return wxString(path 
+ 2); 
 667   // Yes, this should return the path, not an empty string, otherwise 
 668   // we get "thing.txt" -> "". 
 672 // Return just the directory, or NULL if no directory 
 674 wxPathOnly (wxChar 
*path
) 
 678       static wxChar buf
[_MAXPATHLEN
]; 
 681       wxStrcpy (buf
, path
); 
 683       int l 
= wxStrlen(path
); 
 688       // Search backward for a backward or forward slash 
 689       while (!done 
&& i 
> -1) 
 692         if (path
[i
] == _T('/') || path
[i
] == _T('\\') || path
[i
] == _T(']')) 
 707       // Try Drive specifier 
 708       if (wxIsalpha (buf
[0]) && buf
[1] == _T(':')) 
 710           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 718   return (wxChar 
*) NULL
; 
 721 // Return just the directory, or NULL if no directory 
 722 wxString 
wxPathOnly (const wxString
& path
) 
 726       wxChar buf
[_MAXPATHLEN
]; 
 729       wxStrcpy (buf
, WXSTRINGCAST path
); 
 731       int l 
= path
.Length(); 
 736       // Search backward for a backward or forward slash 
 737       while (!done 
&& i 
> -1) 
 740         if (path
[i
] == _T('/') || path
[i
] == _T('\\') || path
[i
] == _T(']')) 
 749           return wxString(buf
); 
 755       // Try Drive specifier 
 756       if (wxIsalpha (buf
[0]) && buf
[1] == _T(':')) 
 758           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 761           return wxString(buf
); 
 766   return wxString(_T("")); 
 769 // Utility for converting delimiters in DOS filenames to UNIX style 
 770 // and back again - or we get nasty problems with delimiters. 
 771 // Also, convert to lower case, since case is significant in UNIX. 
 775 wxMac2UnixFilename (wxChar 
*s
) 
 779                 memmove( s
+1 , s 
,(strlen( s 
) + 1)*sizeof(wxChar
)) ; 
 790                           *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 797 wxUnix2MacFilename (wxChar 
*s
) 
 803                         // relative path , since it goes on with slash which is translated to a : 
 804                         memmove( s 
, s
+1 ,strlen( s 
)*sizeof(wxChar
) ) ; 
 806                 else if ( *s 
== _T('/') ) 
 808                         // absolute path -> on mac just start with the drive name 
 809                         memmove( s 
, s
+1 ,strlen( s 
)*sizeof(wxChar
) ) ; 
 813                         wxASSERT_MSG( 1 , _T("unknown path beginning") ) ; 
 817                         if (*s 
== _T('/') || *s 
== _T('\\')) 
 826 wxDos2UnixFilename (wxChar 
*s
) 
 835           *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 843 wxUnix2DosFilename (wxChar 
*s
) 
 845 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
)) 
 848 // Yes, I really mean this to happen under DOS only! JACS 
 860 // Concatenate two files to form third 
 862 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
 864   wxChar 
*outfile 
= wxGetTempFileName("cat"); 
 866   FILE *fp1 
= (FILE *) NULL
; 
 867   FILE *fp2 
= (FILE *) NULL
; 
 868   FILE *fp3 
= (FILE *) NULL
; 
 869   // Open the inputs and outputs 
 871         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 872         wxUnix2MacFilename( gwxMacFileName 
) ; 
 873         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 874         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 875         wxStrcpy( gwxMacFileName3 
, outfile
) ; 
 876         wxUnix2MacFilename( gwxMacFileName3 
) ; 
 878   if ((fp1 
= fopen (gwxMacFileName
, "rb")) == NULL 
|| 
 879       (fp2 
= fopen (gwxMacFileName2
, "rb")) == NULL 
|| 
 880       (fp3 
= fopen (gwxMacFileName3
, "wb")) == NULL
) 
 882   if ((fp1 
= fopen (FNSTRINGCAST file1
.fn_str(), "rb")) == NULL 
|| 
 883       (fp2 
= fopen (FNSTRINGCAST file2
.fn_str(), "rb")) == NULL 
|| 
 884       (fp3 
= fopen (wxFNCONV(outfile
), "wb")) == NULL
) 
 897   while ((ch 
= getc (fp1
)) != EOF
) 
 898     (void) putc (ch
, fp3
); 
 901   while ((ch 
= getc (fp2
)) != EOF
) 
 902     (void) putc (ch
, fp3
); 
 906   bool result 
= wxRenameFile(outfile
, file3
); 
 913 wxCopyFile (const wxString
& file1
, const wxString
& file2
) 
 920         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 921         wxUnix2MacFilename( gwxMacFileName 
) ; 
 922         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 923         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 925   if ((fd1 
= fopen (gwxMacFileName
, "rb")) == NULL
) 
 927   if ((fd2 
= fopen (gwxMacFileName2
, "wb")) == NULL
) 
 929   if ((fd1 
= fopen (FNSTRINGCAST file1
.fn_str(), "rb")) == NULL
) 
 931   if ((fd2 
= fopen (FNSTRINGCAST file2
.fn_str(), "wb")) == NULL
) 
 938   while ((ch 
= getc (fd1
)) != EOF
) 
 939     (void) putc (ch
, fd2
); 
 947 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
 950         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 951         wxUnix2MacFilename( gwxMacFileName 
) ; 
 952         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 953         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 955   if (0 == rename (gwxMacFileName
, gwxMacFileName2
)) 
 958   // Normal system call 
 959   if (0 == rename (FNSTRINGCAST file1
.fn_str(), FNSTRINGCAST file2
.fn_str())) 
 963   if (wxCopyFile(file1
, file2
)) { 
 971 bool wxRemoveFile(const wxString
& file
) 
 973 #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__WATCOMC__) 
 974   int flag 
= remove(FNSTRINGCAST file
.fn_str()); 
 975 #elif defined( __WXMAC__ ) 
 976         wxStrcpy( gwxMacFileName 
, file 
) ; 
 977         wxUnix2MacFilename( gwxMacFileName 
) ; 
 978   int flag 
= unlink(gwxMacFileName
); 
 980   int flag 
= unlink(FNSTRINGCAST file
.fn_str()); 
 985 bool wxMkdir(const wxString
& dir
, int perm
) 
 987 #if defined( __WXMAC__ ) 
 988     wxStrcpy( gwxMacFileName 
, dir 
) ; 
 989     wxUnix2MacFilename( gwxMacFileName 
) ; 
 990     const wxChar 
*dirname 
= gwxMacFileName
; 
 992     const wxChar 
*dirname 
= dir
.c_str(); 
 995     // assume mkdir() has 2 args on non Windows platforms and on Windows too 
 996     // for the GNU compiler 
 997 #if !defined(__WXMSW__) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) 
 998     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
1000     if ( mkdir(wxFNCONV(dirname
)) != 0 ) 
1003         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1011 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1015 #elif defined( __WXMAC__ ) 
1016         wxStrcpy( gwxMacFileName 
, dir 
) ; 
1017         wxUnix2MacFilename( gwxMacFileName 
) ; 
1018   return (rmdir(WXSTRINGCAST gwxMacFileName
) == 0); 
1022   return FALSE
; // What to do? 
1024   return (rmdir(FNSTRINGCAST dir
.fn_str()) == 0); 
1031 bool wxDirExists(const wxString
& dir
) 
1035 #elif !defined(__WXMSW__) 
1037   return (stat(dir
.fn_str(), &sbuf
) != -1) && S_ISDIR(sbuf
.st_mode
) ? TRUE 
: FALSE
; 
1040   /* MATTHEW: [6] Always use same code for Win32, call FindClose */ 
1041 #if defined(__WIN32__) 
1042   WIN32_FIND_DATA fileInfo
; 
1045   struct ffblk fileInfo
; 
1047   struct find_t fileInfo
; 
1051 #if defined(__WIN32__) 
1052         HANDLE h 
= FindFirstFile((LPTSTR
) WXSTRINGCAST dir
,(LPWIN32_FIND_DATA
)&fileInfo
); 
1054         if (h
==INVALID_HANDLE_VALUE
) 
1058          return ((fileInfo
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
) == FILE_ATTRIBUTE_DIRECTORY
); 
1061   // In Borland findfirst has a different argument 
1062   // ordering from _dos_findfirst. But _dos_findfirst 
1063   // _should_ be ok in both MS and Borland... why not? 
1065   return ((findfirst(WXSTRINGCAST dir
, &fileInfo
, _A_SUBDIR
) == 0  && (fileInfo
.ff_attrib 
& _A_SUBDIR
) != 0)); 
1067   return (((_dos_findfirst(WXSTRINGCAST dir
, _A_SUBDIR
, &fileInfo
) == 0) && (fileInfo
.attrib 
& _A_SUBDIR
)) != 0); 
1076 // does the path exists? (may have or not '/' or '\\' at the end) 
1077 bool wxPathExists(const wxChar 
*pszPathName
) 
1079   // Windows API returns -1 from stat for "c:\dir\" if "c:\dir" exists 
1080   // OTOH, we should change "d:" to "d:\" and leave "\" as is. 
1081   wxString 
strPath(pszPathName
); 
1082   if ( wxEndsWithPathSeparator(pszPathName
) && pszPathName
[1] != _T('\0') ) 
1083     strPath
.Last() = _T('\0'); 
1091   return stat(FNSTRINGCAST strPath
.fn_str(), &st
) == 0 && (st
.st_mode 
& S_IFDIR
); 
1094 // Get a temporary filename, opening and closing the file. 
1095 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1101   ::GetTempFileName(0, WXSTRINGCAST prefix
, 0, tmp
); 
1103   wxChar tmp
[MAX_PATH
]; 
1104   wxChar tmpPath
[MAX_PATH
]; 
1105   ::GetTempPath(MAX_PATH
, tmpPath
); 
1106   ::GetTempFileName(tmpPath
, WXSTRINGCAST prefix
, 0, tmp
); 
1108   if (buf
) wxStrcpy(buf
, tmp
); 
1109   else buf 
= copystring(tmp
); 
1113   static short last_temp 
= 0;        // cache last to speed things a bit 
1114   // At most 1000 temp files to a process! We use a ring count. 
1115   wxChar tmp
[100]; // FIXME static buffer 
1117   for (short suffix 
= last_temp 
+ 1; suffix 
!= last_temp
; ++suffix 
%= 1000) 
1119       wxSprintf (tmp
, _T("/tmp/%s%d.%03x"), WXSTRINGCAST prefix
, (int) getpid (), (int) suffix
); 
1120       if (!wxFileExists( tmp 
)) 
1122           // Touch the file to create it (reserve name) 
1123           FILE *fd 
= fopen (wxFNCONV(tmp
), "w"); 
1128             wxStrcpy( buf
, tmp
); 
1130             buf 
= copystring( tmp 
); 
1134   wxLogError( _("wxWindows: error finding temporary file name.\n") ); 
1135   if (buf
) buf
[0] = 0; 
1136   return (wxChar 
*) NULL
; 
1140 // Get first file name matching given wild card. 
1144 // Get first file name matching given wild card. 
1145 // Flags are reserved for future use. 
1148     static DIR *gs_dirStream 
= (DIR *) NULL
; 
1149     static wxString gs_strFileSpec
; 
1150     static int gs_findFlags 
= 0; 
1153 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1159         closedir(gs_dirStream
); // edz 941103: better housekeping 
1161     gs_findFlags 
= flags
; 
1163     gs_strFileSpec 
= spec
; 
1165     // Find path only so we can concatenate 
1166     // found file onto path 
1167     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1169     // special case: path is really "/" 
1170     if ( !path 
&& gs_strFileSpec
[0u] == _T('/') ) 
1172     // path is empty => Local directory 
1176     gs_dirStream 
= opendir(path
.fn_str()); 
1177     if ( !gs_dirStream 
) 
1179         wxLogSysError(_("Can not enumerate files in directory '%s'"), 
1184         result 
= wxFindNextFile(); 
1191 wxString 
wxFindNextFile() 
1196     wxCHECK_MSG( gs_dirStream
, result
, _T("must call wxFindFirstFile first") ); 
1198     // Find path only so we can concatenate 
1199     // found file onto path 
1200     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1201     wxString 
name(wxFileNameFromPath(gs_strFileSpec
)); 
1203     /* MATTHEW: special case: path is really "/" */ 
1204     if ( !path 
&& gs_strFileSpec
[0u] == _T('/')) 
1208     struct dirent 
*nextDir
; 
1209     for ( nextDir 
= readdir(gs_dirStream
); 
1211           nextDir 
= readdir(gs_dirStream
) ) 
1213         if (wxMatchWild(name
, nextDir
->d_name
)) 
1216             if ( !path
.IsEmpty() ) 
1219                 if ( path 
!= _T('/') ) 
1223             result 
+= nextDir
->d_name
; 
1225             // Only return "." and ".." when they match 
1227             if ( (strcmp(nextDir
->d_name
, ".") == 0) || 
1228                  (strcmp(nextDir
->d_name
, "..") == 0)) 
1230                 if ( (gs_findFlags 
& wxDIR
) != 0 ) 
1236                 isdir 
= wxDirExists(result
); 
1238             // and only return directories when flags & wxDIR 
1239             if ( !gs_findFlags 
|| 
1240                  ((gs_findFlags 
& wxDIR
) && isdir
) || 
1241                  ((gs_findFlags 
& wxFILE
) && !isdir
) ) 
1248     result
.Empty(); // not found 
1250     closedir(gs_dirStream
); 
1251     gs_dirStream 
= (DIR *) NULL
; 
1257 #elif defined(__WXMSW__) 
1260     static HANDLE gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1261     static WIN32_FIND_DATA gs_findDataStruct
; 
1264         static struct ffblk gs_findDataStruct
; 
1266         static struct _find_t gs_findDataStruct
; 
1270 static wxString gs_strFileSpec
; 
1271 static int gs_findFlags 
= 0; 
1273 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1277     gs_strFileSpec 
= spec
; 
1278     gs_findFlags 
= flags
; /* MATTHEW: [5] Remember flags */ 
1280     // Find path only so we can concatenate found file onto path 
1281     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1282     if ( !path
.IsEmpty() ) 
1283         result 
<< path 
<< _T('\\'); 
1286     if ( gs_hFileStruct 
!= INVALID_HANDLE_VALUE 
) 
1287         FindClose(gs_hFileStruct
); 
1289     gs_hFileStruct 
= ::FindFirstFile(WXSTRINGCAST spec
, &gs_findDataStruct
); 
1291     if ( gs_hFileStruct 
== INVALID_HANDLE_VALUE 
) 
1298     bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1300     if (isdir 
&& !(flags 
& wxDIR
)) 
1301         return wxFindNextFile(); 
1302     else if (!isdir 
&& flags 
&& !(flags 
& wxFILE
)) 
1303         return wxFindNextFile(); 
1305     result 
+= gs_findDataStruct
.cFileName
; 
1309     int flag 
= _A_NORMAL
; 
1310     if (flags 
& wxDIR
) /* MATTHEW: [5] Use & */ 
1314     if (findfirst(WXSTRINGCAST spec
, &gs_findDataStruct
, flag
) == 0) 
1316         if (_dos_findfirst(WXSTRINGCAST spec
, flag
, &gs_findDataStruct
) == 0) 
1319             /* MATTHEW: [5] Check directory flag */ 
1323             attrib 
= gs_findDataStruct
.ff_attrib
; 
1325             attrib 
= gs_findDataStruct
.attrib
; 
1328             if (attrib 
& _A_SUBDIR
) { 
1329                 if (!(gs_findFlags 
& wxDIR
)) 
1330                     return wxFindNextFile(); 
1331             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1332                 return wxFindNextFile(); 
1336                     gs_findDataStruct
.ff_name
 
1338                     gs_findDataStruct
.name
 
1347 wxString 
wxFindNextFile() 
1351     // Find path only so we can concatenate found file onto path 
1352     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1357     if (gs_hFileStruct 
== INVALID_HANDLE_VALUE
) 
1360     bool success 
= (FindNextFile(gs_hFileStruct
, &gs_findDataStruct
) != 0); 
1363         FindClose(gs_hFileStruct
); 
1364         gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1368         bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1370         if (isdir 
&& !(gs_findFlags 
& wxDIR
)) 
1372         else if (!isdir 
&& gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1375         if ( !path
.IsEmpty() ) 
1376             result 
<< path 
<< _T('\\'); 
1377         result 
<< gs_findDataStruct
.cFileName
; 
1384     if (findnext(&gs_findDataStruct
) == 0) 
1386         if (_dos_findnext(&gs_findDataStruct
) == 0) 
1389             /* MATTHEW: [5] Check directory flag */ 
1393             attrib 
= gs_findDataStruct
.ff_attrib
; 
1395             attrib 
= gs_findDataStruct
.attrib
; 
1398             if (attrib 
& _A_SUBDIR
) { 
1399                 if (!(gs_findFlags 
& wxDIR
)) 
1401             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1407                       gs_findDataStruct
.ff_name
 
1409                       gs_findDataStruct
.name
 
1418 #endif // Unix/Windows 
1420 // Get current working directory. 
1421 // If buf is NULL, allocates space using new, else 
1423 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1426     buf 
= new wxChar
[sz
+1]; 
1428   char *cbuf 
= new char[sz
+1]; 
1430   if (_getcwd(cbuf
, sz
) == NULL
) { 
1432   if (getcwd(cbuf
, sz
) == NULL
) { 
1437   if (_getcwd(buf
, sz
) == NULL
) { 
1439   if (getcwd(buf
, sz
) == NULL
) { 
1447     wxConv_file
.MB2WC(buf
, cbuf
, sz
); 
1456     static const size_t maxPathLen 
= 1024; 
1459     wxGetWorkingDirectory(str
.GetWriteBuf(maxPathLen
), maxPathLen
); 
1460     str
.UngetWriteBuf(); 
1465 bool wxSetWorkingDirectory(const wxString
& d
) 
1467 #if defined( __UNIX__ ) || defined( __WXMAC__ ) 
1468   return (chdir(d
.fn_str()) == 0); 
1469 #elif defined(__WINDOWS__) 
1472   return (bool)(SetCurrentDirectory(d
) != 0); 
1474   // Must change drive, too. 
1475   bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1478     wxChar firstChar 
= d
[0]; 
1482       firstChar 
= firstChar 
- 32; 
1484     // To a drive number 
1485     unsigned int driveNo 
= firstChar 
- 64; 
1488        unsigned int noDrives
; 
1489        _dos_setdrive(driveNo
, &noDrives
); 
1492   bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1500 // Get the OS directory if appropriate (such as the Windows directory). 
1501 // On non-Windows platform, probably just return the empty string. 
1502 wxString 
wxGetOSDirectory() 
1506     GetWindowsDirectory(buf
, 256); 
1507     return wxString(buf
); 
1509     return wxEmptyString
; 
1513 bool wxEndsWithPathSeparator(const wxChar 
*pszFileName
) 
1515   size_t len 
= wxStrlen(pszFileName
); 
1519     return wxIsPathSeparator(pszFileName
[len 
- 1]); 
1522 // find a file in a list of directories, returns false if not found 
1523 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1525   // we assume that it's not empty 
1526   wxCHECK_MSG( !wxIsEmpty(pszFile
), FALSE
, 
1527                _("empty file name in wxFindFileInPath")); 
1529   // skip path separator in the beginning of the file name if present 
1530   if ( wxIsPathSeparator(*pszFile
) ) 
1533   // copy the path (strtok will modify it) 
1534   wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1535   wxStrcpy(szPath
, pszPath
); 
1538   wxChar 
*pc
, *save_ptr
; 
1539   for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1541         pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1543     // search for the file in this directory 
1545     if ( !wxEndsWithPathSeparator(pc
) ) 
1546       strFile 
+= wxFILE_SEP_PATH
; 
1549     if ( FileExists(strFile
) ) { 
1557   return pc 
!= NULL
;  // if true => we breaked from the loop 
1560 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1565     // it can be empty, but it shouldn't be NULL 
1566     wxCHECK_RET( pszFileName
, _T("NULL file name in wxSplitPath") ); 
1568     const wxChar 
*pDot 
= wxStrrchr(pszFileName
, wxFILE_SEP_EXT
); 
1571     // under Windows we understand both separators 
1572     const wxChar 
*pSepUnix 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_UNIX
); 
1573     const wxChar 
*pSepDos 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_DOS
); 
1574     const wxChar 
*pLastSeparator 
= pSepUnix 
> pSepDos 
? pSepUnix 
: pSepDos
; 
1575 #else // assume Unix 
1576     const wxChar 
*pLastSeparator 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_UNIX
); 
1578     if ( pDot 
== pszFileName 
) 
1580         // under Unix files like .profile are treated in a special way 
1585     if ( pDot 
< pLastSeparator 
) 
1587         // the dot is part of the path, not the start of the extension 
1593         if ( pLastSeparator 
)     
1594             *pstrPath 
= wxString(pszFileName
, pLastSeparator 
- pszFileName
); 
1601         const wxChar 
*start 
= pLastSeparator 
? pLastSeparator 
+ 1 : pszFileName
; 
1602         const wxChar 
*end 
= pDot 
? pDot 
: pszFileName 
+ wxStrlen(pszFileName
); 
1604         *pstrName 
= wxString(start
, end 
- start
); 
1610             *pstrExt 
= wxString(pDot 
+ 1); 
1616 //------------------------------------------------------------------------ 
1617 // wild character routines 
1618 //------------------------------------------------------------------------ 
1620 bool wxIsWild( const wxString
& pattern 
) 
1622   wxString tmp 
= pattern
; 
1623   wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
1626         case _T('?'): case _T('*'): case _T('['): case _T('{'): 
1636 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1638 #if defined(HAVE_FNMATCH_H) 
1640 // this probably won't work well for multibyte chars in Unicode mode? 
1642       return fnmatch(pat
.fn_str(), text
.fn_str(), FNM_PERIOD
) == 0; 
1644       return fnmatch(pat
.fn_str(), text
.fn_str(), 0) == 0; 
1648 // #pragma error Broken implementation of wxMatchWild() -- needs fixing! 
1651     * WARNING: this code is broken! 
1654   wxString tmp1 
= pat
; 
1655   wxChar 
*pattern 
= WXSTRINGCAST(tmp1
); 
1656   wxString tmp2 
= text
; 
1657   wxChar 
*str 
= WXSTRINGCAST(tmp2
); 
1660     bool done 
= FALSE
, ret_code
, ok
; 
1661     // Below is for vi fans 
1662     const wxChar OB 
= _T('{'), CB 
= _T('}'); 
1664     // dot_special means '.' only matches '.' 
1665     if (dot_special 
&& *str 
== _T('.') && *pattern 
!= *str
) 
1668     while ((*pattern 
!= _T('\0')) && (!done
) 
1669     && (((*str
==_T('\0'))&&((*pattern
==OB
)||(*pattern
==_T('*'))))||(*str
!=_T('\0')))) { 
1673             if (*pattern 
!= _T('\0')) 
1679             while ((*str
!=_T('\0')) 
1680             && (!(ret_code
=wxMatchWild(pattern
, str
++, FALSE
)))) 
1683                 while (*str 
!= _T('\0')) 
1685                 while (*pattern 
!= _T('\0')) 
1692             if ((*pattern 
== _T('\0')) || (*pattern 
== _T(']'))) { 
1696             if (*pattern 
== _T('\\')) { 
1698                 if (*pattern 
== _T('\0')) { 
1703             if (*(pattern 
+ 1) == _T('-')) { 
1706                 if (*pattern 
== _T(']')) { 
1710                 if (*pattern 
== _T('\\')) { 
1712                     if (*pattern 
== _T('\0')) { 
1717                 if ((*str 
< c
) || (*str 
> *pattern
)) { 
1721             } else if (*pattern 
!= *str
) { 
1726             while ((*pattern 
!= _T(']')) && (*pattern 
!= _T('\0'))) { 
1727                 if ((*pattern 
== _T('\\')) && (*(pattern 
+ 1) != _T('\0'))) 
1731             if (*pattern 
!= _T('\0')) { 
1741             while ((*pattern 
!= CB
) && (*pattern 
!= _T('\0'))) { 
1744                 while (ok 
&& (*cp 
!= _T('\0')) && (*pattern 
!= _T('\0')) 
1745                 &&  (*pattern 
!= _T(',')) && (*pattern 
!= CB
)) { 
1746                     if (*pattern 
== _T('\\')) 
1748                     ok 
= (*pattern
++ == *cp
++); 
1750                 if (*pattern 
== _T('\0')) { 
1756                     while ((*pattern 
!= CB
) && (*pattern 
!= _T('\0'))) { 
1757                         if (*++pattern 
== _T('\\')) { 
1758                             if (*++pattern 
== CB
) 
1763                     while (*pattern
!=CB 
&& *pattern
!=_T(',') && *pattern
!=_T('\0')) { 
1764                         if (*++pattern 
== _T('\\')) { 
1765                             if (*++pattern 
== CB 
|| *pattern 
== _T(',')) 
1770                 if (*pattern 
!= _T('\0')) 
1775             if (*str 
== *pattern
) { 
1782     while (*pattern 
== _T('*')) 
1784     return ((*str 
== _T('\0')) && (*pattern 
== _T('\0'))); 
1790     #pragma warning(default:4706)   // assignment within conditional expression