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)) 
  47 #include <sys/types.h> 
  60 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) 
  67 #include <sys/unistd.h> 
  68 #define stricmp strcasecmp 
  71 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
  72                     // this (3.1 I believe) and how to test for it. 
  73                     // If this works for Borland 4.0 as well, then no worries. 
  79 // No, Cygwin doesn't appear to have fnmatch.h after all. 
  80 #if defined(HAVE_FNMATCH_H) 
  88 #define _MAXPATHLEN 500 
  90 extern char *wxBuffer
; 
  92 #if !USE_SHARED_LIBRARIES 
  93 IMPLEMENT_DYNAMIC_CLASS(wxPathList
, wxStringList
) 
  96 void wxPathList::Add (const wxString
& path
) 
  98   wxStringList::Add ((char *)(const char *)path
); 
 101 // Add paths e.g. from the PATH environment variable 
 102 void wxPathList::AddEnvList (const wxString
& envVariable
) 
 104   static const char PATH_TOKS
[] = 
 106         " ;"; // Don't seperate with colon in DOS (used for drive) 
 111   char *val 
= getenv (WXSTRINGCAST envVariable
); 
 114       char *s 
= copystring (val
); 
 115       char *token 
= strtok (s
, PATH_TOKS
); 
 119           Add (copystring (token
)); 
 122               if ((token 
= strtok ((char *) NULL
, PATH_TOKS
)) != NULL
) 
 123                 Add (wxString(token
)); 
 130 // Given a full filename (with path), ensure that that file can 
 131 // be accessed again USING FILENAME ONLY by adding the path 
 132 // to the list if not already there. 
 133 void wxPathList::EnsureFileAccessible (const wxString
& path
) 
 135   wxString 
path1(path
); 
 136   char *path_only 
= wxPathOnly (WXSTRINGCAST path1
); 
 139       if (!Member (wxString(path_only
))) 
 140             Add (wxString(path_only
)); 
 144 bool wxPathList::Member (const wxString
& path
) 
 146   for (wxNode 
* node 
= First (); node 
!= NULL
; node 
= node
->Next ()) 
 148       wxString 
path2((char *) node
->Data ()); 
 150 #if defined(__WINDOWS__) || defined(__VMS__) 
 152           path
.CompareTo (path2
, wxString::ignoreCase
) == 0 
 154       // Case sensitive File System  
 155           path
.CompareTo (path2
) == 0 
 163 wxString 
wxPathList::FindValidPath (const wxString
& file
) 
 165   if (wxFileExists (wxExpandPath(wxBuffer
, file
))) 
 166     return wxString(wxBuffer
); 
 168   char buf
[_MAXPATHLEN
]; 
 169   strcpy(buf
, wxBuffer
); 
 171   char *filename 
= IsAbsolutePath (buf
) ? wxFileNameFromPath (buf
) : (char *)buf
; 
 173   for (wxNode 
* node 
= First (); node
; node 
= node
->Next ()) 
 175       char *path 
= (char *) node
->Data (); 
 176       strcpy (wxBuffer
, path
); 
 177       char ch 
= wxBuffer
[strlen(wxBuffer
)-1]; 
 178       if (ch 
!= '\\' && ch 
!= '/') 
 179         strcat (wxBuffer
, "/"); 
 180       strcat (wxBuffer
, filename
); 
 182       Unix2DosFilename (wxBuffer
); 
 184       if (wxFileExists (wxBuffer
)) 
 186         return wxString(wxBuffer
);      // Found! 
 190   return wxString("");                  // Not found 
 193 wxString 
wxPathList::FindAbsoluteValidPath (const wxString
& file
) 
 195   wxString f 
= FindValidPath(file
); 
 196   if (wxIsAbsolutePath(f
)) 
 201     wxGetWorkingDirectory(buf
, 499); 
 202     int len 
= (int)strlen(buf
); 
 206     if (lastCh 
!= '/' && lastCh 
!= '\\') 
 214     strcat(buf
, (const char *)f
); 
 215     strcpy(wxBuffer
, buf
); 
 216     return wxString(wxBuffer
); 
 221 wxFileExists (const wxString
& filename
) 
 223 #ifdef __GNUWIN32__ // (fix a B20 bug) 
 224   if (GetFileAttributes(filename
) == 0xFFFFFFFF) 
 231   if (filename 
&& stat ((char *)(const char *)filename
, &stbuf
) == 0) 
 237 /* Vadim's alternative implementation 
 239 // does the file exist? 
 240 bool wxFileExists(const char *pszFileName) 
 243   return !access(pszFileName, 0) && 
 244          !stat(pszFileName, &st) && 
 245          (st.st_mode & S_IFREG); 
 250 wxIsAbsolutePath (const wxString
& filename
) 
 254       if (filename
[0] == '/' 
 256       || (filename
[0] == '[' && filename
[1] != '.') 
 260       || filename
[0] == '\\' || (isalpha (filename
[0]) && filename
[1] == ':') 
 269  * Strip off any extension (dot something) from end of file, 
 270  * IF one exists. Inserts zero into buffer. 
 274 void wxStripExtension(char *buffer
) 
 276   int len 
= strlen(buffer
); 
 280     if (buffer
[i
] == '.') 
 289 void wxStripExtension(wxString
& buffer
) 
 291   size_t len 
= buffer
.Length(); 
 295     if (buffer
.GetChar(i
) == '.') 
 297       buffer 
= buffer
.Left(i
); 
 304 // Destructive removal of /./ and /../ stuff 
 305 char *wxRealPath (char *path
) 
 308   static const char SEP 
= '\\'; 
 309   Unix2DosFilename(path
); 
 311   static const char SEP 
= '/'; 
 313   if (path
[0] && path
[1]) { 
 314     /* MATTHEW: special case "/./x" */ 
 316     if (path
[2] == SEP 
&& path
[1] == '.') 
 324             if (p
[1] == '.' && p
[2] == '.' && (p
[3] == SEP 
|| p
[3] == '\0')) 
 327                 for (q 
= p 
- 1; q 
>= path 
&& *q 
!= SEP
; q
--); 
 328                 if (q
[0] == SEP 
&& (q
[1] != '.' || q
[2] != '.' || q
[3] != SEP
) 
 329                     && (q 
- 1 <= path 
|| q
[-1] != SEP
)) 
 338                     /* Check that path[2] is NULL! */ 
 339                     else if (path
[1] == ':' && !path
[2]) 
 348             else if (p
[1] == '.' && (p
[2] == SEP 
|| p
[2] == '\0')) 
 357 char *wxCopyAbsolutePath(const wxString
& filename
) 
 360     return (char *) NULL
; 
 362   if (! IsAbsolutePath(wxExpandPath(wxBuffer
, filename
))) { 
 363     char    buf
[_MAXPATHLEN
]; 
 365     wxGetWorkingDirectory(buf
, sizeof(buf
)/sizeof(char)); 
 366     char ch 
= buf
[strlen(buf
) - 1]; 
 368     if (ch 
!= '\\' && ch 
!= '/') 
 374     strcat(buf
, wxBuffer
); 
 375     return copystring( wxRealPath(buf
) ); 
 377   return copystring( wxBuffer 
); 
 383    ~user/ => user's home dir 
 384    If the environment variable a = "foo" and b = "bar" then: 
 401 /* input name in name, pathname output to buf. */ 
 403 char *wxExpandPath(char *buf
, const char *name
) 
 405     register char  *d
, *s
, *nm
; 
 406     char            lnm
[_MAXPATHLEN
]; 
 409     // Some compilers don't like this line. 
 410 //    const char      trimchars[] = "\n \t"; 
 419      const char     SEP 
= '\\'; 
 421      const char     SEP 
= '/'; 
 424     if (name 
== NULL 
|| *name 
== '\0') 
 426     nm 
= copystring(name
); // Make a scratch copy 
 429     /* Skip leading whitespace and cr */ 
 430     while (strchr((char *)trimchars
, *nm
) != NULL
) 
 432     /* And strip off trailing whitespace and cr */ 
 433     s 
= nm 
+ (q 
= strlen(nm
)) - 1; 
 434     while (q
-- && strchr((char *)trimchars
, *s
) != NULL
) 
 442     q 
= nm
[0] == '\\' && nm
[1] == '~'; 
 445     /* Expand inline environment variables */ 
 446     while ((*d
++ = *s
)) { 
 449             if ((*(d 
- 1) = *++s
)) { 
 457         if (*s
++ == '$' && (*s 
== '{' || *s 
== ')')) 
 462             register char  *start 
= d
; 
 463             register int   braces 
= (*s 
== '{' || *s 
== '('); 
 464             register char  *value
; 
 466                 if (braces 
? (*s 
== '}' || *s 
== ')') : !(isalnum(*s
) || *s 
== '_') ) 
 471             value 
= getenv(braces 
? start 
+ 1 : start
); 
 473                 for ((d 
= start 
- 1); (*d
++ = *value
++);); 
 481     /* Expand ~ and ~user */ 
 484     if (nm
[0] == '~' && !q
) 
 487         if (nm
[1] == SEP 
|| nm
[1] == 0) 
 489             if ((s 
= wxGetUserHome("")) != NULL
) { 
 494         {               /* ~user/filename */ 
 497             for (s 
= nm
; *s 
&& *s 
!= SEP
; s
++); 
 498             int was_sep
; /* MATTHEW: Was there a separator, or NULL? */ 
 499             was_sep 
= (*s 
== SEP
); 
 500             nnm 
= *s 
? s 
+ 1 : s
; 
 502             if ((home 
= wxGetUserHome(wxString(nm 
+ 1))) == NULL
) { 
 503                if (was_sep
) /* replace only if it was there: */ 
 514     if (s 
&& *s
) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 
 516         while ('\0' != (*d
++ = *s
++)) 
 519         if (d 
- 1 > buf 
&& *(d 
- 2) != SEP
) 
 523     while ((*d
++ = *s
++)); 
 525     delete[] nm_tmp
; // clean up alloc 
 526     /* Now clean up the buffer */ 
 527     return wxRealPath(buf
); 
 531 /* Contract Paths to be build upon an environment variable 
 534    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 
 536    The call wxExpandPath can convert these back! 
 539 wxContractPath (const wxString
& filename
, const wxString
& envname
, const wxString
& user
) 
 541   static char dest
[_MAXPATHLEN
]; 
 544     return (char *) NULL
; 
 546   strcpy (dest
, WXSTRINGCAST filename
); 
 548   Unix2DosFilename(dest
); 
 551   // Handle environment 
 552   char *val 
= (char *) NULL
; 
 553   char *tcp 
= (char *) NULL
; 
 554   if (envname 
!= WXSTRINGCAST NULL 
&& (val 
= getenv (WXSTRINGCAST envname
)) != NULL 
&& 
 555      (tcp 
= strstr (dest
, val
)) != NULL
) 
 557         strcpy (wxBuffer
, tcp 
+ strlen (val
)); 
 560         strcpy (tcp
, WXSTRINGCAST envname
); 
 562         strcat (tcp
, wxBuffer
); 
 565   // Handle User's home (ignore root homes!) 
 567   if ((val 
= wxGetUserHome (user
)) != NULL 
&& 
 568       (len 
= strlen(val
)) > 2 && 
 569       strncmp(dest
, val
, len
) == 0) 
 571       strcpy(wxBuffer
, "~"); 
 573         strcat(wxBuffer
, user
); 
 575 //      strcat(wxBuffer, "\\"); 
 577 //      strcat(wxBuffer, "/"); 
 579       strcat(wxBuffer
, dest 
+ len
); 
 580       strcpy (dest
, wxBuffer
); 
 586 // Return just the filename, not the path 
 588 char *wxFileNameFromPath (char *path
) 
 594       tcp 
= path 
+ strlen (path
); 
 595       while (--tcp 
>= path
) 
 597           if (*tcp 
== '/' || *tcp 
== '\\' 
 599      || *tcp 
== ':' || *tcp 
== ']') 
 606       if (isalpha (*path
) && *(path 
+ 1) == ':') 
 613 wxString 
wxFileNameFromPath (const wxString
& path1
) 
 618       char *path 
= WXSTRINGCAST path1 
; 
 621       tcp 
= path 
+ strlen (path
); 
 622       while (--tcp 
>= path
) 
 624             if (*tcp 
== '/' || *tcp 
== '\\' 
 626         || *tcp 
== ':' || *tcp 
== ']') 
 630                 return wxString(tcp 
+ 1); 
 633       if (isalpha (*path
) && *(path 
+ 1) == ':') 
 634             return wxString(path 
+ 2); 
 640 // Return just the directory, or NULL if no directory 
 642 wxPathOnly (char *path
) 
 646       static char buf
[_MAXPATHLEN
]; 
 651       int l 
= strlen(path
); 
 656       // Search backward for a backward or forward slash 
 657       while (!done 
&& i 
> -1) 
 660         if (path
[i
] == '/' || path
[i
] == '\\' || path
[i
] == ']') 
 675       // Try Drive specifier 
 676       if (isalpha (buf
[0]) && buf
[1] == ':') 
 678           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 686   return (char *) NULL
; 
 689 // Return just the directory, or NULL if no directory 
 690 wxString 
wxPathOnly (const wxString
& path
) 
 694       char buf
[_MAXPATHLEN
]; 
 697       strcpy (buf
, WXSTRINGCAST path
); 
 699       int l 
= path
.Length(); 
 704       // Search backward for a backward or forward slash 
 705       while (!done 
&& i 
> -1) 
 708         if (path
[i
] == '/' || path
[i
] == '\\' || path
[i
] == ']') 
 717           return wxString(buf
); 
 723       // Try Drive specifier 
 724       if (isalpha (buf
[0]) && buf
[1] == ':') 
 726           // A:junk --> A:. (since A:.\junk Not A:\junk) 
 729           return wxString(buf
); 
 737 // Utility for converting delimiters in DOS filenames to UNIX style 
 738 // and back again - or we get nasty problems with delimiters. 
 739 // Also, convert to lower case, since case is significant in UNIX. 
 742 wxDos2UnixFilename (char *s
) 
 751           *s 
= wxToLower (*s
);  // Case INDEPENDENT 
 759 wxUnix2DosFilename (char *s
) 
 761 wxUnix2DosFilename (char *WXUNUSED(s
)) 
 764 // Yes, I really mean this to happen under DOS only! JACS 
 776 // Concatenate two files to form third 
 778 wxConcatFiles (const wxString
& file1
, const wxString
& file2
, const wxString
& file3
) 
 780   char *outfile 
= wxGetTempFileName("cat"); 
 782   FILE *fp1 
= (FILE *) NULL
; 
 783   FILE *fp2 
= (FILE *) NULL
; 
 784   FILE *fp3 
= (FILE *) NULL
; 
 785   // Open the inputs and outputs 
 786   if ((fp1 
= fopen (WXSTRINGCAST file1
, "rb")) == NULL 
|| 
 787       (fp2 
= fopen (WXSTRINGCAST file2
, "rb")) == NULL 
|| 
 788       (fp3 
= fopen (outfile
, "wb")) == NULL
) 
 800   while ((ch 
= getc (fp1
)) != EOF
) 
 801     (void) putc (ch
, fp3
); 
 804   while ((ch 
= getc (fp2
)) != EOF
) 
 805     (void) putc (ch
, fp3
); 
 809   bool result 
= wxRenameFile(outfile
, file3
); 
 816 wxCopyFile (const wxString
& file1
, const wxString
& file2
) 
 822   if ((fd1 
= fopen (WXSTRINGCAST file1
, "rb")) == NULL
) 
 824   if ((fd2 
= fopen (WXSTRINGCAST file2
, "wb")) == NULL
) 
 830   while ((ch 
= getc (fd1
)) != EOF
) 
 831     (void) putc (ch
, fd2
); 
 839 wxRenameFile (const wxString
& file1
, const wxString
& file2
) 
 841   // Normal system call 
 842   if (0 == rename (WXSTRINGCAST file1
, WXSTRINGCAST file2
)) 
 845   if (wxCopyFile(file1
, file2
)) { 
 853 bool wxRemoveFile(const wxString
& file
) 
 855 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) 
 856   int flag 
= remove(WXSTRINGCAST file
); 
 858   int flag 
= unlink(WXSTRINGCAST file
); 
 863 bool wxMkdir(const wxString
& dir
) 
 865 #if defined(__WXSTUBS__) 
 867 #elif defined(__VMS__) 
 869 #elif (defined(__GNUWIN32__) && !defined(__MINGW32__)) || !defined(__WXMSW__) 
 870   return (mkdir (WXSTRINGCAST dir
, S_IRUSR 
| S_IWUSR 
| S_IXUSR 
| S_IRGRP 
| S_IXGRP 
| S_IROTH 
| S_IXOTH
) == 0); 
 872   return (mkdir(WXSTRINGCAST dir
) == 0); 
 876 bool wxRmdir(const wxString
& dir
, int WXUNUSED(flags
)) 
 881   return (rmdir(WXSTRINGCAST dir
) == 0); 
 886 bool wxDirExists(const wxString
& dir
) 
 890 #elif !defined(__WXMSW__) 
 892   return (stat(dir
, &sbuf
) != -1) && S_ISDIR(sbuf
.st_mode
) ? TRUE 
: FALSE
; 
 895   /* MATTHEW: [6] Always use same code for Win32, call FindClose */ 
 896 #if defined(__WIN32__) 
 897   WIN32_FIND_DATA fileInfo
; 
 900   struct ffblk fileInfo
; 
 902   struct find_t fileInfo
; 
 906 #if defined(__WIN32__) 
 907         HANDLE h 
= FindFirstFile((LPTSTR
) WXSTRINGCAST dir
,(LPWIN32_FIND_DATA
)&fileInfo
); 
 909         if (h
==INVALID_HANDLE_VALUE
) 
 913          return ((fileInfo
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
) == FILE_ATTRIBUTE_DIRECTORY
); 
 916   // In Borland findfirst has a different argument 
 917   // ordering from _dos_findfirst. But _dos_findfirst 
 918   // _should_ be ok in both MS and Borland... why not? 
 920   return ((findfirst(WXSTRINGCAST dir
, &fileInfo
, _A_SUBDIR
) == 0  && (fileInfo
.ff_attrib 
& _A_SUBDIR
) != 0)); 
 922   return (((_dos_findfirst(WXSTRINGCAST dir
, _A_SUBDIR
, &fileInfo
) == 0) && (fileInfo
.attrib 
& _A_SUBDIR
)) != 0); 
 931 // does the path exists? (may have or not '/' or '\\' at the end) 
 932 bool wxPathExists(const char *pszPathName
) 
 934   // Windows API returns -1 from stat for "c:\dir\" if "c:\dir" exists 
 935   // OTOH, we should change "d:" to "d:\" and leave "\" as is. 
 936   wxString 
strPath(pszPathName
); 
 937   if ( wxEndsWithPathSeparator(pszPathName
) && pszPathName
[1] != '\0' ) 
 938     strPath
.Last() = '\0'; 
 941   return stat(strPath
, &st
) == 0 && (st
.st_mode 
& S_IFDIR
); 
 944 // Get a temporary filename, opening and closing the file. 
 945 char *wxGetTempFileName(const wxString
& prefix
, char *buf
) 
 951   ::GetTempFileName(0, WXSTRINGCAST prefix
, 0, tmp
); 
 954   char tmpPath
[MAX_PATH
]; 
 955   ::GetTempPath(MAX_PATH
, tmpPath
); 
 956   ::GetTempFileName(tmpPath
, WXSTRINGCAST prefix
, 0, tmp
); 
 958   if (buf
) strcpy(buf
, tmp
); 
 959   else buf 
= copystring(tmp
); 
 963   static short last_temp 
= 0;   // cache last to speed things a bit 
 964   // At most 1000 temp files to a process! We use a ring count. 
 965   char tmp
[100]; // FIXME static buffer 
 967   for (short suffix 
= last_temp 
+ 1; suffix 
!= last_temp
; ++suffix 
%= 1000) 
 969       sprintf (tmp
, "/tmp/%s%d.%03x", WXSTRINGCAST prefix
, (int) getpid (), (int) suffix
); 
 970       if (!wxFileExists( tmp 
)) 
 972           // Touch the file to create it (reserve name) 
 973           FILE *fd 
= fopen (tmp
, "w"); 
 980             buf 
= copystring( tmp 
); 
 984   cerr 
<< _("wxWindows: error finding temporary file name.\n"); 
 986   return (char *) NULL
; 
 990 // Get first file name matching given wild card. 
 994 // Get first file name matching given wild card. 
 995 // Flags are reserved for future use. 
 998 static DIR *wxDirStream 
= (DIR *) NULL
; 
 999 static char *wxFileSpec 
= (char *) NULL
; 
1000 static int wxFindFileFlags 
= 0; 
1003 char *wxFindFirstFile(const char *spec
, int flags
) 
1007     closedir(wxDirStream
); // edz 941103: better housekeping 
1009   wxFindFileFlags 
= flags
; 
1012     delete[] wxFileSpec
; 
1013   wxFileSpec 
= copystring(spec
); 
1015   // Find path only so we can concatenate 
1016   // found file onto path 
1017   char *p 
= wxPathOnly(wxFileSpec
); 
1019   /* MATTHEW: special case: path is really "/" */ 
1020   if (p 
&& !*p 
&& *wxFileSpec 
== '/') 
1022   /* MATTHEW: p is NULL => Local directory */ 
1026   if ((wxDirStream
=opendir(p
))==NULL
) 
1027     return (char *) NULL
; 
1029  /* MATTHEW: [5] wxFindNextFile can do the rest of the work */ 
1030   return wxFindNextFile(); 
1033   return (char *) NULL
; 
1036 char *wxFindNextFile(void) 
1039   static char buf
[400]; // FIXME static buffer 
1041   /* MATTHEW: [2] Don't crash if we read too many times */ 
1043     return (char *) NULL
; 
1045   // Find path only so we can concatenate 
1046   // found file onto path 
1047   char *p 
= wxPathOnly(wxFileSpec
); 
1048   char *n 
= wxFileNameFromPath(wxFileSpec
); 
1050   /* MATTHEW: special case: path is really "/" */ 
1051   if (p 
&& !*p 
&& *wxFileSpec 
== '/') 
1055   struct dirent 
*nextDir
; 
1056   for (nextDir 
= readdir(wxDirStream
); nextDir 
!= NULL
; nextDir 
= readdir(wxDirStream
)) 
1059     /* MATTHEW: [5] Only return "." and ".." when they match, and only return 
1060        directories when flags & wxDIR */ 
1061     if (wxMatchWild(n
, nextDir
->d_name
)) { 
1067         if (strcmp(p
, "/") != 0) 
1070       strcat(buf
, nextDir
->d_name
); 
1072       if ((strcmp(nextDir
->d_name
, ".") == 0) || 
1073           (strcmp(nextDir
->d_name
, "..") == 0)) { 
1074         if (wxFindFileFlags 
&& !(wxFindFileFlags 
& wxDIR
)) 
1078         isdir 
= wxDirExists(buf
); 
1080       if (!wxFindFileFlags
 
1081           || ((wxFindFileFlags 
& wxDIR
) && isdir
) 
1082           || ((wxFindFileFlags 
& wxFILE
) && !isdir
)) 
1086   closedir(wxDirStream
); 
1087   wxDirStream 
= (DIR *) NULL
; 
1091   return (char *) NULL
; 
1094 #elif defined(__WXMSW__) 
1097 HANDLE wxFileStrucHandle 
= INVALID_HANDLE_VALUE
; 
1098 WIN32_FIND_DATA wxFileStruc
; 
1101 static struct ffblk wxFileStruc
; 
1103 static struct _find_t wxFileStruc
; 
1106 static wxString wxFileSpec 
= ""; 
1107 static int wxFindFileFlags
; 
1109 char *wxFindFirstFile(const char *spec
, int flags
) 
1112   wxFindFileFlags 
= flags
; /* MATTHEW: [5] Remember flags */ 
1114   // Find path only so we can concatenate 
1115   // found file onto path 
1116   wxString 
path1(wxFileSpec
); 
1117   char *p 
= wxPathOnly(WXSTRINGCAST path1
); 
1118   if (p 
&& (strlen(p
) > 0)) 
1119          strcpy(wxBuffer
, p
); 
1124   if (wxFileStrucHandle 
!= INVALID_HANDLE_VALUE
) 
1125          FindClose(wxFileStrucHandle
); 
1127   wxFileStrucHandle 
= ::FindFirstFile(WXSTRINGCAST spec
, &wxFileStruc
); 
1129   if (wxFileStrucHandle 
== INVALID_HANDLE_VALUE
) 
1132   bool isdir 
= !!(wxFileStruc
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1134   if (isdir 
&& !(flags 
& wxDIR
)) 
1135          return wxFindNextFile(); 
1136   else if (!isdir 
&& flags 
&& !(flags 
& wxFILE
)) 
1137          return wxFindNextFile(); 
1139   if (wxBuffer
[0] != 0) 
1140          strcat(wxBuffer
, "\\"); 
1141   strcat(wxBuffer
, wxFileStruc
.cFileName
); 
1145   int flag 
= _A_NORMAL
; 
1146   if (flags 
& wxDIR
) /* MATTHEW: [5] Use & */ 
1150   if (findfirst(WXSTRINGCAST spec
, &wxFileStruc
, flag
) == 0) 
1152   if (_dos_findfirst(WXSTRINGCAST spec
, flag
, &wxFileStruc
) == 0) 
1155     /* MATTHEW: [5] Check directory flag */ 
1159     attrib 
= wxFileStruc
.ff_attrib
; 
1161     attrib 
= wxFileStruc
.attrib
; 
1164     if (attrib 
& _A_SUBDIR
) { 
1165       if (!(wxFindFileFlags 
& wxDIR
)) 
1166         return wxFindNextFile(); 
1167     } else if (wxFindFileFlags 
&& !(wxFindFileFlags 
& wxFILE
)) 
1168                 return wxFindNextFile(); 
1170          if (wxBuffer
[0] != 0) 
1171                 strcat(wxBuffer
, "\\"); 
1174          strcat(wxBuffer
, wxFileStruc
.ff_name
); 
1176          strcat(wxBuffer
, wxFileStruc
.name
); 
1185 char *wxFindNextFile(void) 
1187   // Find path only so we can concatenate 
1188   // found file onto path 
1189   wxString 
p2(wxFileSpec
); 
1190   char *p 
= wxPathOnly(WXSTRINGCAST p2
); 
1191   if (p 
&& (strlen(p
) > 0)) 
1192          strcpy(wxBuffer
, p
); 
1199   if (wxFileStrucHandle 
== INVALID_HANDLE_VALUE
) 
1202   bool success 
= (FindNextFile(wxFileStrucHandle
, &wxFileStruc
) != 0); 
1204                 FindClose(wxFileStrucHandle
); 
1205       wxFileStrucHandle 
= INVALID_HANDLE_VALUE
; 
1209   bool isdir 
= !!(wxFileStruc
.dwFileAttributes 
& FILE_ATTRIBUTE_DIRECTORY
); 
1211   if (isdir 
&& !(wxFindFileFlags 
& wxDIR
)) 
1213   else if (!isdir 
&& wxFindFileFlags 
&& !(wxFindFileFlags 
& wxFILE
)) 
1216   if (wxBuffer
[0] != 0) 
1217     strcat(wxBuffer
, "\\"); 
1218   strcat(wxBuffer
, wxFileStruc
.cFileName
); 
1223   if (findnext(&wxFileStruc
) == 0) 
1225   if (_dos_findnext(&wxFileStruc
) == 0) 
1228     /* MATTHEW: [5] Check directory flag */ 
1232     attrib 
= wxFileStruc
.ff_attrib
; 
1234     attrib 
= wxFileStruc
.attrib
; 
1237     if (attrib 
& _A_SUBDIR
) { 
1238       if (!(wxFindFileFlags 
& wxDIR
)) 
1240     } else if (wxFindFileFlags 
&& !(wxFindFileFlags 
& wxFILE
)) 
1244          if (wxBuffer
[0] != 0) 
1245       strcat(wxBuffer
, "\\"); 
1247          strcat(wxBuffer
, wxFileStruc
.ff_name
); 
1249          strcat(wxBuffer
, wxFileStruc
.name
); 
1261 // Get current working directory. 
1262 // If buf is NULL, allocates space using new, else 
1264 char *wxGetWorkingDirectory(char *buf
, int sz
) 
1267     buf 
= new char[sz
+1]; 
1269   if (_getcwd(buf
, sz
) == NULL
) { 
1271   if (getcwd(buf
, sz
) == NULL
) { 
1279 bool wxSetWorkingDirectory(const wxString
& d
) 
1282   return (chdir(d
) == 0); 
1283 #elif defined(__WINDOWS__) 
1286   return (bool)(SetCurrentDirectory(d
) != 0); 
1288   // Must change drive, too. 
1289   bool isDriveSpec 
= ((strlen(d
) > 1) && (d
[1] == ':')); 
1292     char firstChar 
= d
[0]; 
1296       firstChar 
= firstChar 
- 32; 
1298     // To a drive number 
1299     unsigned int driveNo 
= firstChar 
- 64; 
1302        unsigned int noDrives
; 
1303        _dos_setdrive(driveNo
, &noDrives
); 
1306   bool success 
= (chdir(WXSTRINGCAST d
) == 0); 
1314 bool wxEndsWithPathSeparator(const char *pszFileName
) 
1316   size_t len 
= Strlen(pszFileName
); 
1320     return wxIsPathSeparator(pszFileName
[len 
- 1]); 
1323 // find a file in a list of directories, returns false if not found 
1324 bool wxFindFileInPath(wxString 
*pStr
, const char *pszPath
, const char *pszFile
) 
1326   // we assume that it's not empty 
1327   wxCHECK_MSG( !IsEmpty(pszFile
), FALSE
,  
1328                _("empty file name in wxFindFileInPath")); 
1330   // skip path separator in the beginning of the file name if present 
1331   if ( wxIsPathSeparator(*pszFile
) ) 
1334   // copy the path (strtok will modify it) 
1335   char *szPath 
= new char[strlen(pszPath
) + 1]; 
1336   strcpy(szPath
, pszPath
); 
1340   for ( pc 
= strtok(szPath
, PATH_SEP
); pc
; pc 
= strtok((char *) NULL
, PATH_SEP
) ) { 
1341     // search for the file in this directory 
1343     if ( !wxEndsWithPathSeparator(pc
) ) 
1344       strFile 
+= FILE_SEP_PATH
; 
1347     if ( FileExists(strFile
) ) { 
1355   return pc 
!= NULL
;  // if true => we breaked from the loop 
1358 void WXDLLEXPORT 
wxSplitPath(const char *pszFileName
, 
1363   wxCHECK_RET( pszFileName
, _("NULL file name in wxSplitPath") ); 
1365   const char *pDot 
= strrchr(pszFileName
, FILE_SEP_EXT
); 
1366   const char *pSepUnix 
= strrchr(pszFileName
, FILE_SEP_PATH_UNIX
); 
1367   const char *pSepDos 
= strrchr(pszFileName
, FILE_SEP_PATH_DOS
); 
1369   // take the last of the two 
1370   size_t nPosUnix 
= pSepUnix 
? pSepUnix 
- pszFileName 
: 0; 
1371   size_t nPosDos 
= pSepDos 
? pSepDos 
- pszFileName 
: 0; 
1372   if ( nPosDos 
> nPosUnix 
) 
1374 //  size_t nLen = Strlen(pszFileName); 
1377     *pstrPath 
= wxString(pszFileName
, nPosUnix
); 
1379     size_t nPosDot 
= pDot 
- pszFileName
; 
1381       *pstrName 
= wxString(pszFileName 
+ nPosUnix 
+ 1, nPosDot 
- nPosUnix
); 
1383       *pstrExt 
= wxString(pszFileName 
+ nPosDot 
+ 1); 
1387       *pstrName 
= wxString(pszFileName 
+ nPosUnix 
+ 1); 
1393 //------------------------------------------------------------------------ 
1394 // wild character routines 
1395 //------------------------------------------------------------------------ 
1397 bool wxIsWild( const wxString
& pattern 
) 
1399   wxString tmp 
= pattern
; 
1400   char *pat 
= WXSTRINGCAST(tmp
); 
1403         case '?': case '*': case '[': case '{': 
1413 bool wxMatchWild( const wxString
& pat
, const wxString
& text
, bool dot_special 
) 
1415 #if defined(HAVE_FNMATCH_H) 
1418       return fnmatch(pat
.c_str(), text
.c_str(), FNM_PERIOD
) == 0; 
1420       return fnmatch(pat
.c_str(), text
.c_str(), 0) == 0; 
1424 // #pragma error Broken implementation of wxMatchWild() -- needs fixing! 
1427     * WARNING: this code is broken! 
1430   wxString tmp1 
= pat
; 
1431   char *pattern 
= WXSTRINGCAST(tmp1
); 
1432   wxString tmp2 
= text
; 
1433   char *str 
= WXSTRINGCAST(tmp2
); 
1436     bool done 
= FALSE
, ret_code
, ok
; 
1437     // Below is for vi fans 
1438     const char OB 
= '{', CB 
= '}'; 
1440     // dot_special means '.' only matches '.' 
1441     if (dot_special 
&& *str 
== '.' && *pattern 
!= *str
) 
1444     while ((*pattern 
!= '\0') && (!done
) 
1445     && (((*str
=='\0')&&((*pattern
==OB
)||(*pattern
=='*')))||(*str
!='\0'))) { 
1449             if (*pattern 
!= '\0') 
1456             && (!(ret_code
=wxMatchWild(pattern
, str
++, FALSE
)))) 
1459                 while (*str 
!= '\0') 
1461                 while (*pattern 
!= '\0') 
1468             if ((*pattern 
== '\0') || (*pattern 
== ']')) { 
1472             if (*pattern 
== '\\') { 
1474                 if (*pattern 
== '\0') { 
1479             if (*(pattern 
+ 1) == '-') { 
1482                 if (*pattern 
== ']') { 
1486                 if (*pattern 
== '\\') { 
1488                     if (*pattern 
== '\0') { 
1493                 if ((*str 
< c
) || (*str 
> *pattern
)) { 
1497             } else if (*pattern 
!= *str
) { 
1502             while ((*pattern 
!= ']') && (*pattern 
!= '\0')) { 
1503                 if ((*pattern 
== '\\') && (*(pattern 
+ 1) != '\0')) 
1507             if (*pattern 
!= '\0') { 
1517             while ((*pattern 
!= CB
) && (*pattern 
!= '\0')) { 
1520                 while (ok 
&& (*cp 
!= '\0') && (*pattern 
!= '\0') 
1521                 &&  (*pattern 
!= ',') && (*pattern 
!= CB
)) { 
1522                     if (*pattern 
== '\\') 
1524                     ok 
= (*pattern
++ == *cp
++); 
1526                 if (*pattern 
== '\0') { 
1532                     while ((*pattern 
!= CB
) && (*pattern 
!= '\0')) { 
1533                         if (*++pattern 
== '\\') { 
1534                             if (*++pattern 
== CB
) 
1539                     while (*pattern
!=CB 
&& *pattern
!=',' && *pattern
!='\0') { 
1540                         if (*++pattern 
== '\\') { 
1541                             if (*++pattern 
== CB 
|| *pattern 
== ',') 
1546                 if (*pattern 
!= '\0') 
1551             if (*str 
== *pattern
) { 
1558     while (*pattern 
== '*') 
1560     return ((*str 
== '\0') && (*pattern 
== '\0')); 
1566     #pragma warning(default:4706)   // assignment within conditional expression