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
) 
 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             if ((s 
= WXSTRINGCAST 
wxGetUserHome(_T(""))) != NULL
) { 
 522         {                /* ~user/filename */ 
 523             register wxChar  
*nnm
; 
 524             register wxChar  
*home
; 
 525             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++); 
 526             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 527             was_sep 
= (*s 
== SEP
); 
 528             nnm 
= *s 
? s 
+ 1 : s
; 
 530             if ((home 
= WXSTRINGCAST 
wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 531                if (was_sep
) /* replace only if it was there: */ 
 542     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 544         while (_T('\0') != (*d
++ = *s
++)) 
 547         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 551     while ((*d
++ = *s
++)); 
 553     delete[] nm_tmp
; // clean up alloc 
 554     /* Now clean up the buffer */ 
 555     return wxRealPath(buf
); 
 559 /* Contract Paths to be build upon an environment variable 
 562    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 564    The call wxExpandPath can convert these back! 
 567 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 569   static wxChar dest
[_MAXPATHLEN
]; 
 571   if (filename 
== _T("")) 
 572     return (wxChar 
*) NULL
; 
 574   wxStrcpy (dest
, WXSTRINGCAST filename
); 
 576   Unix2DosFilename(dest
); 
 579   // Handle environment 
 580   const wxChar 
*val 
= (const wxChar 
*) NULL
; 
 581   wxChar 
*tcp 
= (wxChar 
*) NULL
; 
 582   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= wxGetenv (WXSTRINGCAST envname
)) != NULL 
&& 
 583      (tcp 
= wxStrstr (dest
, val
)) != NULL
) 
 585         wxStrcpy (wxBuffer
, tcp 
+ wxStrlen (val
)); 
 588         wxStrcpy (tcp
, WXSTRINGCAST envname
); 
 589         wxStrcat (tcp
, _T("}")); 
 590         wxStrcat (tcp
, wxBuffer
); 
 593   // Handle User's home (ignore root homes!) 
 595   if ((val 
= wxGetUserHome (user
)) != NULL 
&& 
 596       (len 
= wxStrlen(val
)) > 2 && 
 597       wxStrncmp(dest
, val
, len
) == 0) 
 599       wxStrcpy(wxBuffer
, _T("~")); 
 601              wxStrcat(wxBuffer
, (const wxChar
*) user
); 
 603 //      strcat(wxBuffer, "\\"); 
 605 //      strcat(wxBuffer, "/"); 
 607       wxStrcat(wxBuffer
, dest 
+ len
); 
 608       wxStrcpy (dest
, wxBuffer
); 
 614 // Return just the filename, not the path 
 616 wxChar 
*wxFileNameFromPath (wxChar 
*path
) 
 620       register wxChar 
*tcp
; 
 622       tcp 
= path 
+ wxStrlen (path
); 
 623       while (--tcp 
>= path
) 
 625           if (*tcp 
== _T('/') || *tcp 
== _T('\\') 
 627      || *tcp 
== _T(':') || *tcp 
== _T(']')) 
 634       if (wxIsalpha (*path
) && *(path 
+ 1) == _T(':')) 
 641 wxString 
wxFileNameFromPath (const wxString
& path1
) 
 646       wxChar 
*path 
= WXSTRINGCAST path1 
; 
 647       register wxChar 
*tcp
; 
 649       tcp 
= path 
+ wxStrlen (path
); 
 650       while (--tcp 
>= path
) 
 652             if (*tcp 
== _T('/') || *tcp 
== _T('\\') 
 654         || *tcp 
== _T(':') || *tcp 
== _T(']')) 
 658                 return wxString(tcp 
+ 1); 
 661       if (wxIsalpha (*path
) && *(path 
+ 1) == _T(':')) 
 662             return wxString(path 
+ 2); 
 665   // Yes, this should return the path, not an empty string, otherwise 
 666   // we get "thing.txt" -> "". 
 670 // Return just the directory, or NULL if no directory 
 672 wxPathOnly (wxChar 
*path
) 
 676       static wxChar buf
[_MAXPATHLEN
]; 
 679       wxStrcpy (buf
, path
); 
 681       int l 
= wxStrlen(path
); 
 686       // Search backward for a backward or forward slash 
 687       while (!done 
&& i 
> -1) 
 690         if (path
[i
] == _T('/') || path
[i
] == _T('\\') || path
[i
] == _T(']')) 
 705       // Try Drive specifier 
 706       if (wxIsalpha (buf
[0]) && buf
[1] == _T(':')) 
 708           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 716   return (wxChar 
*) NULL
; 
 719 // Return just the directory, or NULL if no directory 
 720 wxString 
wxPathOnly (const wxString
& path
) 
 724       wxChar buf
[_MAXPATHLEN
]; 
 727       wxStrcpy (buf
, WXSTRINGCAST path
); 
 729       int l 
= path
.Length(); 
 734       // Search backward for a backward or forward slash 
 735       while (!done 
&& i 
> -1) 
 738         if (path
[i
] == _T('/') || path
[i
] == _T('\\') || path
[i
] == _T(']')) 
 747           return wxString(buf
); 
 753       // Try Drive specifier 
 754       if (wxIsalpha (buf
[0]) && buf
[1] == _T(':')) 
 756           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 759           return wxString(buf
); 
 764   return wxString(_T("")); 
 767 // Utility for converting delimiters in DOS filenames to UNIX style 
 768 // and back again - or we get nasty problems with delimiters. 
 769 // Also, convert to lower case, since case is significant in UNIX. 
 773 wxMac2UnixFilename (wxChar 
*s
) 
 777                 memmove( s
+1 , s 
,(strlen( s 
) + 1)*sizeof(wxChar
)) ; 
 788                           *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 795 wxUnix2MacFilename (wxChar 
*s
) 
 801                         // relative path , since it goes on with slash which is translated to a : 
 802                         memmove( s 
, s
+1 ,strlen( s 
)*sizeof(wxChar
) ) ; 
 804                 else if ( *s 
== _T('/') ) 
 806                         // absolute path -> on mac just start with the drive name 
 807                         memmove( s 
, s
+1 ,strlen( s 
)*sizeof(wxChar
) ) ; 
 811                         wxASSERT_MSG( 1 , _T("unknown path beginning") ) ; 
 815                         if (*s 
== _T('/') || *s 
== _T('\\')) 
 824 wxDos2UnixFilename (wxChar 
*s
) 
 833           *s 
= wxTolower(*s
);        // Case INDEPENDENT 
 841 wxUnix2DosFilename (wxChar 
*s
) 
 843 wxUnix2DosFilename (wxChar 
*WXUNUSED(s
)) 
 846 // Yes, I really mean this to happen under DOS only! JACS 
 858 // Concatenate two files to form third 
 860 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
 862   wxChar 
*outfile 
= wxGetTempFileName("cat"); 
 864   FILE *fp1 
= (FILE *) NULL
; 
 865   FILE *fp2 
= (FILE *) NULL
; 
 866   FILE *fp3 
= (FILE *) NULL
; 
 867   // Open the inputs and outputs 
 869         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 870         wxUnix2MacFilename( gwxMacFileName 
) ; 
 871         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 872         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 873         wxStrcpy( gwxMacFileName3 
, outfile
) ; 
 874         wxUnix2MacFilename( gwxMacFileName3 
) ; 
 876   if ((fp1 
= fopen (gwxMacFileName
, "rb")) == NULL 
|| 
 877       (fp2 
= fopen (gwxMacFileName2
, "rb")) == NULL 
|| 
 878       (fp3 
= fopen (gwxMacFileName3
, "wb")) == NULL
) 
 880   if ((fp1 
= fopen (FNSTRINGCAST file1
.fn_str(), "rb")) == NULL 
|| 
 881       (fp2 
= fopen (FNSTRINGCAST file2
.fn_str(), "rb")) == NULL 
|| 
 882       (fp3 
= fopen (wxFNCONV(outfile
), "wb")) == NULL
) 
 895   while ((ch 
= getc (fp1
)) != EOF
) 
 896     (void) putc (ch
, fp3
); 
 899   while ((ch 
= getc (fp2
)) != EOF
) 
 900     (void) putc (ch
, fp3
); 
 904   bool result 
= wxRenameFile(outfile
, file3
); 
 911 wxCopyFile (const wxString
& file1
, const wxString
& file2
) 
 918         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 919         wxUnix2MacFilename( gwxMacFileName 
) ; 
 920         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 921         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 923   if ((fd1 
= fopen (gwxMacFileName
, "rb")) == NULL
) 
 925   if ((fd2 
= fopen (gwxMacFileName2
, "wb")) == NULL
) 
 927   if ((fd1 
= fopen (FNSTRINGCAST file1
.fn_str(), "rb")) == NULL
) 
 929   if ((fd2 
= fopen (FNSTRINGCAST file2
.fn_str(), "wb")) == NULL
) 
 936   while ((ch 
= getc (fd1
)) != EOF
) 
 937     (void) putc (ch
, fd2
); 
 945 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
 948         wxStrcpy( gwxMacFileName 
, file1 
) ; 
 949         wxUnix2MacFilename( gwxMacFileName 
) ; 
 950         wxStrcpy( gwxMacFileName2 
, file2
) ; 
 951         wxUnix2MacFilename( gwxMacFileName2 
) ; 
 953   if (0 == rename (gwxMacFileName
, gwxMacFileName2
)) 
 956   // Normal system call 
 957   if (0 == rename (FNSTRINGCAST file1
.fn_str(), FNSTRINGCAST file2
.fn_str())) 
 961   if (wxCopyFile(file1
, file2
)) { 
 969 bool wxRemoveFile(const wxString
& file
) 
 971 #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__WATCOMC__) 
 972   int flag 
= remove(FNSTRINGCAST file
.fn_str()); 
 973 #elif defined( __WXMAC__ ) 
 974         wxStrcpy( gwxMacFileName 
, file 
) ; 
 975         wxUnix2MacFilename( gwxMacFileName 
) ; 
 976   int flag 
= unlink(gwxMacFileName
); 
 978   int flag 
= unlink(FNSTRINGCAST file
.fn_str()); 
 983 bool wxMkdir(const wxString
& dir
, int perm
) 
 985 #if defined( __WXMAC__ ) 
 986     wxStrcpy( gwxMacFileName 
, dir 
) ; 
 987     wxUnix2MacFilename( gwxMacFileName 
) ; 
 988     const wxChar 
*dirname 
= gwxMacFileName
; 
 990     const wxChar 
*dirname 
= dir
.c_str(); 
 993     // assume mkdir() has 2 args on non Windows platforms and on Windows too 
 994     // for the GNU compiler 
 995 #if !defined(__WXMSW__) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) 
 996     if ( mkdir(wxFNCONV(dirname
), perm
) != 0 ) 
 998     if ( mkdir(wxFNCONV(dirname
)) != 0 ) 
1001         wxLogSysError(_("Directory '%s' couldn't be created"), dirname
); 
1009 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
1013 #elif defined( __WXMAC__ ) 
1014         wxStrcpy( gwxMacFileName 
, dir 
) ; 
1015         wxUnix2MacFilename( gwxMacFileName 
) ; 
1016   return (rmdir(WXSTRINGCAST gwxMacFileName
) == 0); 
1020   return FALSE
; // What to do? 
1022   return (rmdir(FNSTRINGCAST dir
.fn_str()) == 0); 
1029 bool wxDirExists(const wxString
& dir
) 
1033 #elif !defined(__WXMSW__) 
1035   return (stat(dir
.fn_str(), &sbuf
) != -1) && S_ISDIR(sbuf
.st_mode
) ? TRUE 
: FALSE
; 
1038   /* MATTHEW: [6] Always use same code for Win32, call FindClose */ 
1039 #if defined(__WIN32__) 
1040   WIN32_FIND_DATA fileInfo
; 
1043   struct ffblk fileInfo
; 
1045   struct find_t fileInfo
; 
1049 #if defined(__WIN32__) 
1050         HANDLE h 
= FindFirstFile((LPTSTR
) WXSTRINGCAST dir
,(LPWIN32_FIND_DATA
)&fileInfo
); 
1052         if (h
==INVALID_HANDLE_VALUE
) 
1056          return ((fileInfo
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
) == FILE_ATTRIBUTE_DIRECTORY
); 
1059   // In Borland findfirst has a different argument 
1060   // ordering from _dos_findfirst. But _dos_findfirst 
1061   // _should_ be ok in both MS and Borland... why not? 
1063   return ((findfirst(WXSTRINGCAST dir
, &fileInfo
, _A_SUBDIR
) == 0  && (fileInfo
.ff_attrib 
& _A_SUBDIR
) != 0)); 
1065   return (((_dos_findfirst(WXSTRINGCAST dir
, _A_SUBDIR
, &fileInfo
) == 0) && (fileInfo
.attrib 
& _A_SUBDIR
)) != 0); 
1074 // does the path exists? (may have or not '/' or '\\' at the end) 
1075 bool wxPathExists(const wxChar 
*pszPathName
) 
1077   // Windows API returns -1 from stat for "c:\dir\" if "c:\dir" exists 
1078   // OTOH, we should change "d:" to "d:\" and leave "\" as is. 
1079   wxString 
strPath(pszPathName
); 
1080   if ( wxEndsWithPathSeparator(pszPathName
) && pszPathName
[1] != _T('\0') ) 
1081     strPath
.Last() = _T('\0'); 
1089   return stat(FNSTRINGCAST strPath
.fn_str(), &st
) == 0 && (st
.st_mode 
& S_IFDIR
); 
1092 // Get a temporary filename, opening and closing the file. 
1093 wxChar 
*wxGetTempFileName(const wxString
& prefix
, wxChar 
*buf
) 
1099   ::GetTempFileName(0, WXSTRINGCAST prefix
, 0, tmp
); 
1101   wxChar tmp
[MAX_PATH
]; 
1102   wxChar tmpPath
[MAX_PATH
]; 
1103   ::GetTempPath(MAX_PATH
, tmpPath
); 
1104   ::GetTempFileName(tmpPath
, WXSTRINGCAST prefix
, 0, tmp
); 
1106   if (buf
) wxStrcpy(buf
, tmp
); 
1107   else buf 
= copystring(tmp
); 
1111   static short last_temp 
= 0;        // cache last to speed things a bit 
1112   // At most 1000 temp files to a process! We use a ring count. 
1113   wxChar tmp
[100]; // FIXME static buffer 
1115   for (short suffix 
= last_temp 
+ 1; suffix 
!= last_temp
; ++suffix 
%= 1000) 
1117       wxSprintf (tmp
, _T("/tmp/%s%d.%03x"), WXSTRINGCAST prefix
, (int) getpid (), (int) suffix
); 
1118       if (!wxFileExists( tmp 
)) 
1120           // Touch the file to create it (reserve name) 
1121           FILE *fd 
= fopen (wxFNCONV(tmp
), "w"); 
1126             wxStrcpy( buf
, tmp
); 
1128             buf 
= copystring( tmp 
); 
1132   wxLogError( _("wxWindows: error finding temporary file name.\n") ); 
1133   if (buf
) buf
[0] = 0; 
1134   return (wxChar 
*) NULL
; 
1138 // Get first file name matching given wild card. 
1142 // Get first file name matching given wild card. 
1143 // Flags are reserved for future use. 
1146     static DIR *gs_dirStream 
= (DIR *) NULL
; 
1147     static wxString gs_strFileSpec
; 
1148     static int gs_findFlags 
= 0; 
1151 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1157         closedir(gs_dirStream
); // edz 941103: better housekeping 
1159     gs_findFlags 
= flags
; 
1161     gs_strFileSpec 
= spec
; 
1163     // Find path only so we can concatenate 
1164     // found file onto path 
1165     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1167     // special case: path is really "/" 
1168     if ( !path 
&& gs_strFileSpec
[0u] == _T('/') ) 
1170     // path is empty => Local directory 
1174     gs_dirStream 
= opendir(path
.fn_str()); 
1175     if ( !gs_dirStream 
) 
1177         wxLogSysError(_("Can not enumerate files in directory '%s'"), 
1182         result 
= wxFindNextFile(); 
1189 wxString 
wxFindNextFile() 
1194     wxCHECK_MSG( gs_dirStream
, result
, _T("must call wxFindFirstFile first") ); 
1196     // Find path only so we can concatenate 
1197     // found file onto path 
1198     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1199     wxString 
name(wxFileNameFromPath(gs_strFileSpec
)); 
1201     /* MATTHEW: special case: path is really "/" */ 
1202     if ( !path 
&& gs_strFileSpec
[0u] == _T('/')) 
1206     struct dirent 
*nextDir
; 
1207     for ( nextDir 
= readdir(gs_dirStream
); 
1209           nextDir 
= readdir(gs_dirStream
) ) 
1211         if (wxMatchWild(name
, nextDir
->d_name
)) 
1214             if ( !path
.IsEmpty() ) 
1217                 if ( path 
!= _T('/') ) 
1221             result 
+= nextDir
->d_name
; 
1223             // Only return "." and ".." when they match 
1225             if ( (strcmp(nextDir
->d_name
, ".") == 0) || 
1226                  (strcmp(nextDir
->d_name
, "..") == 0)) 
1228                 if ( (gs_findFlags 
& wxDIR
) != 0 ) 
1234                 isdir 
= wxDirExists(result
); 
1236             // and only return directories when flags & wxDIR 
1237             if ( !gs_findFlags 
|| 
1238                  ((gs_findFlags 
& wxDIR
) && isdir
) || 
1239                  ((gs_findFlags 
& wxFILE
) && !isdir
) ) 
1246     result
.Empty(); // not found 
1248     closedir(gs_dirStream
); 
1249     gs_dirStream 
= (DIR *) NULL
; 
1255 #elif defined(__WXMSW__) 
1258     static HANDLE gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1259     static WIN32_FIND_DATA gs_findDataStruct
; 
1262         static struct ffblk gs_findDataStruct
; 
1264         static struct _find_t gs_findDataStruct
; 
1268 static wxString gs_strFileSpec
; 
1269 static int gs_findFlags 
= 0; 
1271 wxString 
wxFindFirstFile(const wxChar 
*spec
, int flags
) 
1275     gs_strFileSpec 
= spec
; 
1276     gs_findFlags 
= flags
; /* MATTHEW: [5] Remember flags */ 
1278     // Find path only so we can concatenate found file onto path 
1279     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1280     if ( !path
.IsEmpty() ) 
1281         result 
<< path 
<< _T('\\'); 
1284     if ( gs_hFileStruct 
!= INVALID_HANDLE_VALUE 
) 
1285         FindClose(gs_hFileStruct
); 
1287     gs_hFileStruct 
= ::FindFirstFile(WXSTRINGCAST spec
, &gs_findDataStruct
); 
1289     if ( gs_hFileStruct 
== INVALID_HANDLE_VALUE 
) 
1296     bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1298     if (isdir 
&& !(flags 
& wxDIR
)) 
1299         return wxFindNextFile(); 
1300     else if (!isdir 
&& flags 
&& !(flags 
& wxFILE
)) 
1301         return wxFindNextFile(); 
1303     result 
+= gs_findDataStruct
.cFileName
; 
1307     int flag 
= _A_NORMAL
; 
1308     if (flags 
& wxDIR
) /* MATTHEW: [5] Use & */ 
1312     if (findfirst(WXSTRINGCAST spec
, &gs_findDataStruct
, flag
) == 0) 
1314         if (_dos_findfirst(WXSTRINGCAST spec
, flag
, &gs_findDataStruct
) == 0) 
1317             /* MATTHEW: [5] Check directory flag */ 
1321             attrib 
= gs_findDataStruct
.ff_attrib
; 
1323             attrib 
= gs_findDataStruct
.attrib
; 
1326             if (attrib 
& _A_SUBDIR
) { 
1327                 if (!(gs_findFlags 
& wxDIR
)) 
1328                     return wxFindNextFile(); 
1329             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1330                 return wxFindNextFile(); 
1334                     gs_findDataStruct
.ff_name
 
1336                     gs_findDataStruct
.name
 
1345 wxString 
wxFindNextFile() 
1349     // Find path only so we can concatenate found file onto path 
1350     wxString 
path(wxPathOnly(gs_strFileSpec
)); 
1355     if (gs_hFileStruct 
== INVALID_HANDLE_VALUE
) 
1358     bool success 
= (FindNextFile(gs_hFileStruct
, &gs_findDataStruct
) != 0); 
1361         FindClose(gs_hFileStruct
); 
1362         gs_hFileStruct 
= INVALID_HANDLE_VALUE
; 
1366         bool isdir 
= !!(gs_findDataStruct
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1368         if (isdir 
&& !(gs_findFlags 
& wxDIR
)) 
1370         else if (!isdir 
&& gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1373         if ( !path
.IsEmpty() ) 
1374             result 
<< path 
<< _T('\\'); 
1375         result 
<< gs_findDataStruct
.cFileName
; 
1382     if (findnext(&gs_findDataStruct
) == 0) 
1384         if (_dos_findnext(&gs_findDataStruct
) == 0) 
1387             /* MATTHEW: [5] Check directory flag */ 
1391             attrib 
= gs_findDataStruct
.ff_attrib
; 
1393             attrib 
= gs_findDataStruct
.attrib
; 
1396             if (attrib 
& _A_SUBDIR
) { 
1397                 if (!(gs_findFlags 
& wxDIR
)) 
1399             } else if (gs_findFlags 
&& !(gs_findFlags 
& wxFILE
)) 
1405                       gs_findDataStruct
.ff_name
 
1407                       gs_findDataStruct
.name
 
1416 #endif // Unix/Windows 
1418 // Get current working directory. 
1419 // If buf is NULL, allocates space using new, else 
1421 wxChar 
*wxGetWorkingDirectory(wxChar 
*buf
, int sz
) 
1424     buf 
= new wxChar
[sz
+1]; 
1426   char *cbuf 
= new char[sz
+1]; 
1428   if (_getcwd(cbuf
, sz
) == NULL
) { 
1430   if (getcwd(cbuf
, sz
) == NULL
) { 
1435   if (_getcwd(buf
, sz
) == NULL
) { 
1437   if (getcwd(buf
, sz
) == NULL
) { 
1445     wxConv_file
.MB2WC(buf
, cbuf
, sz
); 
1454     static const size_t maxPathLen 
= 1024; 
1457     wxGetWorkingDirectory(str
.GetWriteBuf(maxPathLen
), maxPathLen
); 
1458     str
.UngetWriteBuf(); 
1463 bool wxSetWorkingDirectory(const wxString
& d
) 
1465 #if defined( __UNIX__ ) || defined( __WXMAC__ ) 
1466   return (chdir(d
.fn_str()) == 0); 
1467 #elif defined(__WINDOWS__) 
1470   return (bool)(SetCurrentDirectory(d
) != 0); 
1472   // Must change drive, too. 
1473   bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1476     wxChar firstChar 
= d
[0]; 
1480       firstChar 
= firstChar 
- 32; 
1482     // To a drive number 
1483     unsigned int driveNo 
= firstChar 
- 64; 
1486        unsigned int noDrives
; 
1487        _dos_setdrive(driveNo
, &noDrives
); 
1490   bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1498 // Get the OS directory if appropriate (such as the Windows directory). 
1499 // On non-Windows platform, probably just return the empty string. 
1500 wxString 
wxGetOSDirectory() 
1504     GetWindowsDirectory(buf
, 256); 
1505     return wxString(buf
); 
1507     return wxEmptyString
; 
1511 bool wxEndsWithPathSeparator(const char *pszFileName
) 
1513   size_t len 
= Strlen(pszFileName
); 
1517     return wxIsPathSeparator(pszFileName
[len 
- 1]); 
1520 // find a file in a list of directories, returns false if not found 
1521 bool wxFindFileInPath(wxString 
*pStr
, const wxChar 
*pszPath
, const wxChar 
*pszFile
) 
1523   // we assume that it's not empty 
1524   wxCHECK_MSG( !wxIsEmpty(pszFile
), FALSE
, 
1525                _("empty file name in wxFindFileInPath")); 
1527   // skip path separator in the beginning of the file name if present 
1528   if ( wxIsPathSeparator(*pszFile
) ) 
1531   // copy the path (strtok will modify it) 
1532   wxChar 
*szPath 
= new wxChar
[wxStrlen(pszPath
) + 1]; 
1533   wxStrcpy(szPath
, pszPath
); 
1536   wxChar 
*pc
, *save_ptr
; 
1537   for ( pc 
= wxStrtok(szPath
, wxPATH_SEP
, &save_ptr
); 
1539         pc 
= wxStrtok((wxChar 
*) NULL
, wxPATH_SEP
, &save_ptr
) ) 
1541     // search for the file in this directory 
1543     if ( !wxEndsWithPathSeparator(pc
) ) 
1544       strFile 
+= wxFILE_SEP_PATH
; 
1547     if ( FileExists(strFile
) ) { 
1555   return pc 
!= NULL
;  // if true => we breaked from the loop 
1558 void WXDLLEXPORT 
wxSplitPath(const wxChar 
*pszFileName
, 
1563     // it can be empty, but it shouldn't be NULL 
1564     wxCHECK_RET( pszFileName
, _T("NULL file name in wxSplitPath") ); 
1566     const wxChar 
*pDot 
= wxStrrchr(pszFileName
, wxFILE_SEP_EXT
); 
1569     // under Windows we understand both separators 
1570     const wxChar 
*pSepUnix 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_UNIX
); 
1571     const wxChar 
*pSepDos 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_DOS
); 
1572     const wxChar 
*pLastSeparator 
= pSepUnix 
> pSepDos 
? pSepUnix 
: pSepDos
; 
1573 #else // assume Unix 
1574     const wxChar 
*pLastSeparator 
= wxStrrchr(pszFileName
, wxFILE_SEP_PATH_UNIX
); 
1576     if ( pDot 
== pszFileName 
) 
1578         // under Unix files like .profile are treated in a special way 
1583     if ( pDot 
< pLastSeparator 
) 
1585         // the dot is part of the path, not the start of the extension 
1591         if ( pLastSeparator 
)     
1592             *pstrPath 
= wxString(pszFileName
, pLastSeparator 
- pszFileName
); 
1599         const wxChar 
*start 
= pLastSeparator 
? pLastSeparator 
+ 1 : pszFileName
; 
1600         const wxChar 
*end 
= pDot 
? pDot 
: pszFileName 
+ wxStrlen(pszFileName
); 
1602         *pstrName 
= wxString(start
, end 
- start
); 
1608             *pstrExt 
= wxString(pDot 
+ 1); 
1614 //------------------------------------------------------------------------ 
1615 // wild character routines 
1616 //------------------------------------------------------------------------ 
1618 bool wxIsWild( const wxString
& pattern 
) 
1620   wxString tmp 
= pattern
; 
1621   wxChar 
*pat 
= WXSTRINGCAST(tmp
); 
1624         case _T('?'): case _T('*'): case _T('['): case _T('{'): 
1634 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1636 #if defined(HAVE_FNMATCH_H) 
1638 // this probably won't work well for multibyte chars in Unicode mode? 
1640       return fnmatch(pat
.fn_str(), text
.fn_str(), FNM_PERIOD
) == 0; 
1642       return fnmatch(pat
.fn_str(), text
.fn_str(), 0) == 0; 
1646 // #pragma error Broken implementation of wxMatchWild() -- needs fixing! 
1649     * WARNING: this code is broken! 
1652   wxString tmp1 
= pat
; 
1653   wxChar 
*pattern 
= WXSTRINGCAST(tmp1
); 
1654   wxString tmp2 
= text
; 
1655   wxChar 
*str 
= WXSTRINGCAST(tmp2
); 
1658     bool done 
= FALSE
, ret_code
, ok
; 
1659     // Below is for vi fans 
1660     const wxChar OB 
= _T('{'), CB 
= _T('}'); 
1662     // dot_special means '.' only matches '.' 
1663     if (dot_special 
&& *str 
== _T('.') && *pattern 
!= *str
) 
1666     while ((*pattern 
!= _T('\0')) && (!done
) 
1667     && (((*str
==_T('\0'))&&((*pattern
==OB
)||(*pattern
==_T('*'))))||(*str
!=_T('\0')))) { 
1671             if (*pattern 
!= _T('\0')) 
1677             while ((*str
!=_T('\0')) 
1678             && (!(ret_code
=wxMatchWild(pattern
, str
++, FALSE
)))) 
1681                 while (*str 
!= _T('\0')) 
1683                 while (*pattern 
!= _T('\0')) 
1690             if ((*pattern 
== _T('\0')) || (*pattern 
== _T(']'))) { 
1694             if (*pattern 
== _T('\\')) { 
1696                 if (*pattern 
== _T('\0')) { 
1701             if (*(pattern 
+ 1) == _T('-')) { 
1704                 if (*pattern 
== _T(']')) { 
1708                 if (*pattern 
== _T('\\')) { 
1710                     if (*pattern 
== _T('\0')) { 
1715                 if ((*str 
< c
) || (*str 
> *pattern
)) { 
1719             } else if (*pattern 
!= *str
) { 
1724             while ((*pattern 
!= _T(']')) && (*pattern 
!= _T('\0'))) { 
1725                 if ((*pattern 
== _T('\\')) && (*(pattern 
+ 1) != _T('\0'))) 
1729             if (*pattern 
!= _T('\0')) { 
1739             while ((*pattern 
!= CB
) && (*pattern 
!= _T('\0'))) { 
1742                 while (ok 
&& (*cp 
!= _T('\0')) && (*pattern 
!= _T('\0')) 
1743                 &&  (*pattern 
!= _T(',')) && (*pattern 
!= CB
)) { 
1744                     if (*pattern 
== _T('\\')) 
1746                     ok 
= (*pattern
++ == *cp
++); 
1748                 if (*pattern 
== _T('\0')) { 
1754                     while ((*pattern 
!= CB
) && (*pattern 
!= _T('\0'))) { 
1755                         if (*++pattern 
== _T('\\')) { 
1756                             if (*++pattern 
== CB
) 
1761                     while (*pattern
!=CB 
&& *pattern
!=_T(',') && *pattern
!=_T('\0')) { 
1762                         if (*++pattern 
== _T('\\')) { 
1763                             if (*++pattern 
== CB 
|| *pattern 
== _T(',')) 
1768                 if (*pattern 
!= _T('\0')) 
1773             if (*str 
== *pattern
) { 
1780     while (*pattern 
== _T('*')) 
1782     return ((*str 
== _T('\0')) && (*pattern 
== _T('\0'))); 
1788     #pragma warning(default:4706)   // assignment within conditional expression