home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / filefn.cpp < prev    next >
C/C++ Source or Header  |  2002-11-22  |  51KB  |  1,816 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        filefn.cpp
  3. // Purpose:     File- and directory-related functions
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     29/01/98
  7. // RCS-ID:      $Id: filefn.cpp,v 1.159.2.6 2002/11/21 21:49:20 RR Exp $
  8. // Copyright:   (c) 1998 Julian Smart
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "filefn.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26. #include "wx/defs.h"
  27.  
  28. #ifdef __BORLANDC__
  29.     #pragma hdrstop
  30. #endif
  31.  
  32. #include "wx/utils.h"
  33. #include "wx/intl.h"
  34. #include "wx/file.h"
  35. #include "wx/filename.h"
  36. #include "wx/dir.h"
  37.  
  38. // there are just too many of those...
  39. #ifdef __VISUALC__
  40.     #pragma warning(disable:4706)   // assignment within conditional expression
  41. #endif // VC++
  42.  
  43. #include <ctype.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #if !defined(__WATCOMC__)
  48.     #if !(defined(_MSC_VER) && (_MSC_VER > 800))
  49.         #include <errno.h>
  50.     #endif
  51. #endif
  52.  
  53. #if defined(__WXMAC__)
  54.   #include  "wx/mac/private.h"  // includes mac headers
  55. #endif
  56.  
  57. #include <time.h>
  58.  
  59. #ifndef __MWERKS__
  60.     #include <sys/types.h>
  61.     #include <sys/stat.h>
  62. #else
  63.     #include <stat.h>
  64.     #include <unistd.h>
  65.     #include <unix.h>
  66. #endif
  67.  
  68. #ifdef __UNIX__
  69.     #include <unistd.h>
  70.     #include <dirent.h>
  71.     #include <fcntl.h>
  72. #endif
  73.  
  74. #ifdef __WXPM__
  75.     #include <process.h>
  76.     #include "wx/os2/private.h"
  77. #endif
  78. #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) && !defined(__WXWINE__)
  79. #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
  80.     #include <direct.h>
  81.     #include <dos.h>
  82.     #include <io.h>
  83. #endif // __WINDOWS__
  84. #endif // native Win compiler
  85.  
  86. #if defined(__DOS__)
  87.     #ifdef __WATCOMC__
  88.         #include <direct.h>
  89.         #include <dos.h>
  90.         #include <io.h>
  91.     #endif
  92.     #ifdef __DJGPP__
  93.         #include <unistd.h>
  94.     #endif
  95. #endif
  96.  
  97. #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
  98.                     // this (3.1 I believe) and how to test for it.
  99.                     // If this works for Borland 4.0 as well, then no worries.
  100.     #include <dir.h>
  101. #endif
  102.  
  103. #ifdef __SALFORDC__
  104.     #include <dir.h>
  105.     #include <unix.h>
  106. #endif
  107.  
  108. #include "wx/log.h"
  109.  
  110. // No, Cygwin doesn't appear to have fnmatch.h after all.
  111. #if defined(HAVE_FNMATCH_H)
  112.     #include "fnmatch.h"
  113. #endif
  114.  
  115. #ifdef __WINDOWS__
  116.     #include <windows.h>
  117.     #include "wx/msw/mslu.h"
  118.  
  119.     // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path()
  120.     //
  121.     // note that it must be included after <windows.h>
  122.     #ifdef __GNUWIN32__
  123.         #ifdef __CYGWIN__
  124.             #include <sys/cygwin.h>
  125.         #endif
  126.  
  127.         #ifndef __TWIN32__
  128.             #include <sys/unistd.h>
  129.         #endif
  130.     #endif // __GNUWIN32__
  131. #endif // __WINDOWS__
  132.  
  133. // TODO: Borland probably has _wgetcwd as well?
  134. #ifdef _MSC_VER
  135.     #define HAVE_WGETCWD
  136. #endif
  137.  
  138. // ----------------------------------------------------------------------------
  139. // constants
  140. // ----------------------------------------------------------------------------
  141.  
  142. #ifndef _MAXPATHLEN
  143.     #define _MAXPATHLEN 1024
  144. #endif
  145.  
  146. #ifdef __WXMAC__
  147. #    include "MoreFiles.h"
  148. #    include "MoreFilesExtras.h"
  149. #    include "FullPath.h"
  150. #    include "FSpCompat.h"
  151. #endif
  152.  
  153. // ----------------------------------------------------------------------------
  154. // private globals
  155. // ----------------------------------------------------------------------------
  156.  
  157. // MT-FIXME: get rid of this horror and all code using it
  158. static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN];
  159.  
  160. #if defined(__VISAGECPP__) && __IBMCPP__ >= 400
  161. //
  162. // VisualAge C++ V4.0 cannot have any external linkage const decs
  163. // in headers included by more than one primary source
  164. //
  165. const off_t wxInvalidOffset = (off_t)-1;
  166. #endif
  167.  
  168. // ----------------------------------------------------------------------------
  169. // macros
  170. // ----------------------------------------------------------------------------
  171.  
  172. // we need to translate Mac filenames before passing them to OS functions
  173. #define OS_FILENAME(s) (s.fn_str())
  174.  
  175. // ============================================================================
  176. // implementation
  177. // ============================================================================
  178.  
  179. #ifdef wxNEED_WX_UNISTD_H
  180.  
  181. WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf )
  182. {
  183.     return stat( wxConvFile.cWX2MB( file_name ), buf );
  184. }
  185.  
  186. WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode )
  187. {
  188.     return access( wxConvFile.cWX2MB( pathname ), mode );
  189. }
  190.  
  191. WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode )
  192. {
  193.     return open( wxConvFile.cWX2MB( pathname ), flags, mode );
  194. }
  195.  
  196. #endif
  197.    // wxNEED_WX_UNISTD_H
  198.  
  199. // ----------------------------------------------------------------------------
  200. // wxPathList
  201. // ----------------------------------------------------------------------------
  202.  
  203. IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
  204.  
  205. void wxPathList::Add (const wxString& path)
  206. {
  207.     wxStringList::Add (WXSTRINGCAST path);
  208. }
  209.  
  210. // Add paths e.g. from the PATH environment variable
  211. void wxPathList::AddEnvList (const wxString& envVariable)
  212. {
  213.   static const wxChar PATH_TOKS[] =
  214. #ifdef __WINDOWS__
  215.         wxT(" ;"); // Don't seperate with colon in DOS (used for drive)
  216. #else
  217.         wxT(" :;");
  218. #endif
  219.  
  220.   wxChar *val = wxGetenv (WXSTRINGCAST envVariable);
  221.   if (val && *val)
  222.     {
  223.       wxChar *s = copystring (val);
  224.       wxChar *save_ptr, *token = wxStrtok (s, PATH_TOKS, &save_ptr);
  225.  
  226.       if (token)
  227.       {
  228.           Add (copystring (token));
  229.           while (token)
  230.           {
  231.               if ((token = wxStrtok ((wxChar *) NULL, PATH_TOKS, &save_ptr)) != NULL)
  232.                   Add (wxString(token));
  233.           }
  234.       }
  235.  
  236.       // suppress warning about unused variable save_ptr when wxStrtok() is a
  237.       // macro which throws away its third argument
  238.       save_ptr = token;
  239.  
  240.       delete [] s;
  241.     }
  242. }
  243.  
  244. // Given a full filename (with path), ensure that that file can
  245. // be accessed again USING FILENAME ONLY by adding the path
  246. // to the list if not already there.
  247. void wxPathList::EnsureFileAccessible (const wxString& path)
  248. {
  249.     wxString path_only(wxPathOnly(path));
  250.     if ( !path_only.IsEmpty() )
  251.     {
  252.         if ( !Member(path_only) )
  253.             Add(path_only);
  254.     }
  255. }
  256.  
  257. bool wxPathList::Member (const wxString& path)
  258. {
  259.   for (wxNode * node = First (); node != NULL; node = node->Next ())
  260.   {
  261.       wxString path2((wxChar *) node->Data ());
  262.       if (
  263. #if defined(__WINDOWS__) || defined(__VMS__) || defined (__WXMAC__)
  264.       // Case INDEPENDENT
  265.           path.CompareTo (path2, wxString::ignoreCase) == 0
  266. #else
  267.       // Case sensitive File System
  268.           path.CompareTo (path2) == 0
  269. #endif
  270.         )
  271.         return TRUE;
  272.   }
  273.   return FALSE;
  274. }
  275.  
  276. wxString wxPathList::FindValidPath (const wxString& file)
  277. {
  278.   if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer, file)))
  279.     return wxString(wxFileFunctionsBuffer);
  280.  
  281.   wxChar buf[_MAXPATHLEN];
  282.   wxStrcpy(buf, wxFileFunctionsBuffer);
  283.  
  284.   wxChar *filename = (wxChar*) NULL; /* shut up buggy egcs warning */
  285.   filename = wxIsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (wxChar *)buf;
  286.  
  287.   for (wxNode * node = First (); node; node = node->Next ())
  288.     {
  289.       wxChar *path = (wxChar *) node->Data ();
  290.       wxStrcpy (wxFileFunctionsBuffer, path);
  291.       wxChar ch = wxFileFunctionsBuffer[wxStrlen(wxFileFunctionsBuffer)-1];
  292.       if (ch != wxT('\\') && ch != wxT('/'))
  293.         wxStrcat (wxFileFunctionsBuffer, wxT("/"));
  294.       wxStrcat (wxFileFunctionsBuffer, filename);
  295. #ifdef __WINDOWS__
  296.       wxUnix2DosFilename (wxFileFunctionsBuffer);
  297. #endif
  298.       if (wxFileExists (wxFileFunctionsBuffer))
  299.       {
  300.         return wxString(wxFileFunctionsBuffer);        // Found!
  301.       }
  302.     }                                // for()
  303.  
  304.   return wxString(wxT(""));                    // Not found
  305. }
  306.  
  307. wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
  308. {
  309.     wxString f = FindValidPath(file);
  310.     if ( wxIsAbsolutePath(f) )
  311.         return f;
  312.  
  313.     wxString buf;
  314.     wxGetWorkingDirectory(wxStringBuffer(buf, _MAXPATHLEN), _MAXPATHLEN);
  315.  
  316.     if ( !wxEndsWithPathSeparator(buf) )
  317.     {
  318.         buf += wxFILE_SEP_PATH;
  319.     }
  320.     buf += f;
  321.  
  322.     return buf;
  323. }
  324.  
  325. bool
  326. wxFileExists (const wxString& filename)
  327. {
  328.     // we must use GetFileAttributes() instead of the ANSI C functions because
  329.     // it can cope with network (UNC) paths unlike them
  330. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  331.     DWORD ret = ::GetFileAttributes(filename);
  332.  
  333.     return (ret != (DWORD)-1) && !(ret & FILE_ATTRIBUTE_DIRECTORY);
  334. #else // !__WIN32__
  335.     wxStructStat st;
  336.     return wxStat(filename, &st) == 0 && (st.st_mode & S_IFREG);
  337. #endif // __WIN32__/!__WIN32__
  338. }
  339.  
  340. bool
  341. wxIsAbsolutePath (const wxString& filename)
  342. {
  343.     if (filename != wxT(""))
  344.     {
  345. #if defined(__WXMAC__) && !defined(__DARWIN__)
  346.         // Classic or Carbon CodeWarrior like
  347.         // Carbon with Apple DevTools is Unix like
  348.  
  349.         // This seems wrong to me, but there is no fix. since
  350.         // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt"
  351.         // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR.
  352.         if (filename.Find(':') != wxNOT_FOUND && filename[0] != ':')
  353.             return TRUE ;
  354. #else
  355.         // Unix like or Windows
  356.         if (filename[0] == wxT('/'))
  357.             return TRUE;
  358. #endif
  359. #ifdef __VMS__
  360.         if ((filename[0] == wxT('[') && filename[1] != wxT('.')))
  361.             return TRUE;
  362. #endif
  363. #ifdef __WINDOWS__
  364.         // MSDOS like
  365.         if (filename[0] == wxT('\\') || (wxIsalpha (filename[0]) && filename[1] == wxT(':')))
  366.             return TRUE;
  367. #endif
  368.     }
  369.     return FALSE ;
  370. }
  371.  
  372. /*
  373.  * Strip off any extension (dot something) from end of file,
  374.  * IF one exists. Inserts zero into buffer.
  375.  *
  376.  */
  377.  
  378. void wxStripExtension(wxChar *buffer)
  379. {
  380.   int len = wxStrlen(buffer);
  381.   int i = len-1;
  382.   while (i > 0)
  383.   {
  384.     if (buffer[i] == wxT('.'))
  385.     {
  386.       buffer[i] = 0;
  387.       break;
  388.     }
  389.     i --;
  390.   }
  391. }
  392.  
  393. void wxStripExtension(wxString& buffer)
  394. {
  395.   size_t len = buffer.Length();
  396.   size_t i = len-1;
  397.   while (i > 0)
  398.   {
  399.     if (buffer.GetChar(i) == wxT('.'))
  400.     {
  401.       buffer = buffer.Left(i);
  402.       break;
  403.     }
  404.     i --;
  405.   }
  406. }
  407.  
  408. // Destructive removal of /./ and /../ stuff
  409. wxChar *wxRealPath (wxChar *path)
  410. {
  411. #ifdef __WXMSW__
  412.   static const wxChar SEP = wxT('\\');
  413.   wxUnix2DosFilename(path);
  414. #else
  415.   static const wxChar SEP = wxT('/');
  416. #endif
  417.   if (path[0] && path[1]) {
  418.     /* MATTHEW: special case "/./x" */
  419.     wxChar *p;
  420.     if (path[2] == SEP && path[1] == wxT('.'))
  421.       p = &path[0];
  422.     else
  423.       p = &path[2];
  424.     for (; *p; p++)
  425.       {
  426.         if (*p == SEP)
  427.           {
  428.             if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0')))
  429.               {
  430.                 wxChar *q;
  431.                 for (q = p - 1; q >= path && *q != SEP; q--);
  432.                 if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP)
  433.                     && (q - 1 <= path || q[-1] != SEP))
  434.                   {
  435.                     wxStrcpy (q, p + 3);
  436.                     if (path[0] == wxT('\0'))
  437.                       {
  438.                         path[0] = SEP;
  439.                         path[1] = wxT('\0');
  440.                       }
  441. #ifdef __WXMSW__
  442.                     /* Check that path[2] is NULL! */
  443.                     else if (path[1] == wxT(':') && !path[2])
  444.                       {
  445.                         path[2] = SEP;
  446.                         path[3] = wxT('\0');
  447.                       }
  448. #endif
  449.                     p = q - 1;
  450.                   }
  451.               }
  452.             else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0')))
  453.               wxStrcpy (p, p + 2);
  454.           }
  455.       }
  456.   }
  457.   return path;
  458. }
  459.  
  460. // Must be destroyed
  461. wxChar *wxCopyAbsolutePath(const wxString& filename)
  462. {
  463.   if (filename == wxT(""))
  464.     return (wxChar *) NULL;
  465.  
  466.   if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) {
  467.     wxChar  buf[_MAXPATHLEN];
  468.     buf[0] = wxT('\0');
  469.     wxGetWorkingDirectory(buf, WXSIZEOF(buf));
  470.     wxChar ch = buf[wxStrlen(buf) - 1];
  471. #ifdef __WXMSW__
  472.     if (ch != wxT('\\') && ch != wxT('/'))
  473.         wxStrcat(buf, wxT("\\"));
  474. #else
  475.     if (ch != wxT('/'))
  476.         wxStrcat(buf, wxT("/"));
  477. #endif
  478.     wxStrcat(buf, wxFileFunctionsBuffer);
  479.     return copystring( wxRealPath(buf) );
  480.   }
  481.   return copystring( wxFileFunctionsBuffer );
  482. }
  483.  
  484. /*-
  485.  Handles:
  486.    ~/ => home dir
  487.    ~user/ => user's home dir
  488.    If the environment variable a = "foo" and b = "bar" then:
  489.    Unix:
  490.         $a        =>        foo
  491.         $a$b        =>        foobar
  492.         $a.c        =>        foo.c
  493.         xxx$a        =>        xxxfoo
  494.         ${a}!        =>        foo!
  495.         $(b)!        =>        bar!
  496.         \$a        =>        \$a
  497.    MSDOS:
  498.         $a        ==>        $a
  499.         $(a)        ==>        foo
  500.         $(a)$b        ==>        foo$b
  501.         $(a)$(b)==>        foobar
  502.         test.$$        ==>        test.$$
  503.  */
  504.  
  505. /* input name in name, pathname output to buf. */
  506.  
  507. wxChar *wxExpandPath(wxChar *buf, const wxChar *name)
  508. {
  509.     register wxChar *d, *s, *nm;
  510.     wxChar          lnm[_MAXPATHLEN];
  511.     int             q;
  512.  
  513.     // Some compilers don't like this line.
  514. //    const wxChar    trimchars[] = wxT("\n \t");
  515.  
  516.     wxChar      trimchars[4];
  517.     trimchars[0] = wxT('\n');
  518.     trimchars[1] = wxT(' ');
  519.     trimchars[2] = wxT('\t');
  520.     trimchars[3] = 0;
  521.  
  522. #ifdef __WXMSW__
  523.      const wxChar     SEP = wxT('\\');
  524. #else
  525.      const wxChar     SEP = wxT('/');
  526. #endif
  527.     buf[0] = wxT('\0');
  528.     if (name == NULL || *name == wxT('\0'))
  529.         return buf;
  530.     nm = copystring(name); // Make a scratch copy
  531.     wxChar *nm_tmp = nm;
  532.  
  533.     /* Skip leading whitespace and cr */
  534.     while (wxStrchr((wxChar *)trimchars, *nm) != NULL)
  535.         nm++;
  536.     /* And strip off trailing whitespace and cr */
  537.     s = nm + (q = wxStrlen(nm)) - 1;
  538.     while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL)
  539.         *s = wxT('\0');
  540.  
  541.     s = nm;
  542.     d = lnm;
  543. #ifdef __WXMSW__
  544.     q = FALSE;
  545. #else
  546.     q = nm[0] == wxT('\\') && nm[1] == wxT('~');
  547. #endif
  548.  
  549.     /* Expand inline environment variables */
  550. #ifdef __VISAGECPP__
  551.     while (*d)
  552.     {
  553.       *d++ = *s;
  554.       if(*s == wxT('\\'))
  555.       {
  556.         *(d - 1) = *++s;
  557.         if (*d)
  558.         {
  559.           s++;
  560.           continue;
  561.         }
  562.         else
  563.            break;
  564.       }
  565.       else
  566. #else
  567.     while ((*d++ = *s) != 0) {
  568. #  ifndef __WXMSW__
  569.         if (*s == wxT('\\')) {
  570.             if ((*(d - 1) = *++s)) {
  571.                 s++;
  572.                 continue;
  573.             } else
  574.                 break;
  575.         } else
  576. #  endif
  577. #endif
  578. #ifdef __WXMSW__
  579.         if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')')))
  580. #else
  581.         if (*s++ == wxT('$'))
  582. #endif
  583.         {
  584.             register wxChar  *start = d;
  585.             register int     braces = (*s == wxT('{') || *s == wxT('('));
  586.             register wxChar  *value;
  587.             while ((*d++ = *s) != 0)
  588.                 if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) )
  589.                     break;
  590.                 else
  591.                     s++;
  592.             *--d = 0;
  593.             value = wxGetenv(braces ? start + 1 : start);
  594.             if (value) {
  595.                 for ((d = start - 1); (*d++ = *value++) != 0;);
  596.                 d--;
  597.                 if (braces && *s)
  598.                     s++;
  599.             }
  600.         }
  601.     }
  602.  
  603.     /* Expand ~ and ~user */
  604.     nm = lnm;
  605.     if (nm[0] == wxT('~') && !q)
  606.     {
  607.         /* prefix ~ */
  608.         if (nm[1] == SEP || nm[1] == 0)
  609.         {        /* ~/filename */
  610.         // FIXME: wxGetUserHome could return temporary storage in Unicode mode
  611.             if ((s = WXSTRINGCAST wxGetUserHome(wxT(""))) != NULL) {
  612.                 if (*++nm)
  613.                     nm++;
  614.             }
  615.         } else
  616.         {                /* ~user/filename */
  617.             register wxChar  *nnm;
  618.             register wxChar  *home;
  619.             for (s = nm; *s && *s != SEP; s++);
  620.             int was_sep; /* MATTHEW: Was there a separator, or NULL? */
  621.             was_sep = (*s == SEP);
  622.             nnm = *s ? s + 1 : s;
  623.             *s = 0;
  624.         // FIXME: wxGetUserHome could return temporary storage in Unicode mode
  625.             if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) {
  626.                if (was_sep) /* replace only if it was there: */
  627.                    *s = SEP;
  628.                 s = NULL;
  629.             } else {
  630.                 nm = nnm;
  631.                 s = home;
  632.             }
  633.         }
  634.     }
  635.  
  636.     d = buf;
  637.     if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */
  638.         /* Copy home dir */
  639.         while (wxT('\0') != (*d++ = *s++))
  640.           /* loop */;
  641.         // Handle root home
  642.         if (d - 1 > buf && *(d - 2) != SEP)
  643.           *(d - 1) = SEP;
  644.     }
  645.     s = nm;
  646.     while ((*d++ = *s++) != 0);
  647.     delete[] nm_tmp; // clean up alloc
  648.     /* Now clean up the buffer */
  649.     return wxRealPath(buf);
  650. }
  651.  
  652. /* Contract Paths to be build upon an environment variable
  653.    component:
  654.  
  655.    example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib
  656.  
  657.    The call wxExpandPath can convert these back!
  658.  */
  659. wxChar *
  660. wxContractPath (const wxString& filename, const wxString& envname, const wxString& user)
  661. {
  662.   static wxChar dest[_MAXPATHLEN];
  663.  
  664.   if (filename == wxT(""))
  665.     return (wxChar *) NULL;
  666.  
  667.   wxStrcpy (dest, WXSTRINGCAST filename);
  668. #ifdef __WXMSW__
  669.   wxUnix2DosFilename(dest);
  670. #endif
  671.  
  672.   // Handle environment
  673.   const wxChar *val = (const wxChar *) NULL;
  674.   wxChar *tcp = (wxChar *) NULL;
  675.   if (envname != WXSTRINGCAST NULL && (val = wxGetenv (WXSTRINGCAST envname)) != NULL &&
  676.      (tcp = wxStrstr (dest, val)) != NULL)
  677.     {
  678.         wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val));
  679.         *tcp++ = wxT('$');
  680.         *tcp++ = wxT('{');
  681.         wxStrcpy (tcp, WXSTRINGCAST envname);
  682.         wxStrcat (tcp, wxT("}"));
  683.         wxStrcat (tcp, wxFileFunctionsBuffer);
  684.     }
  685.  
  686.   // Handle User's home (ignore root homes!)
  687.   size_t len = 0;
  688.   if ((val = wxGetUserHome (user)) != NULL &&
  689.       (len = wxStrlen(val)) > 2 &&
  690.       wxStrncmp(dest, val, len) == 0)
  691.     {
  692.       wxStrcpy(wxFileFunctionsBuffer, wxT("~"));
  693.       if (user != wxT(""))
  694.              wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user);
  695.       wxStrcat(wxFileFunctionsBuffer, dest + len);
  696.       wxStrcpy (dest, wxFileFunctionsBuffer);
  697.     }
  698.  
  699.   return dest;
  700. }
  701.  
  702. // Return just the filename, not the path (basename)
  703. wxChar *wxFileNameFromPath (wxChar *path)
  704. {
  705.     wxString p = path;
  706.     wxString n = wxFileNameFromPath(p);
  707.  
  708.     return path + p.length() - n.length();
  709. }
  710.  
  711. wxString wxFileNameFromPath (const wxString& path)
  712. {
  713.     wxString name, ext;
  714.     wxFileName::SplitPath(path, NULL, &name, &ext);
  715.  
  716.     wxString fullname = name;
  717.     if ( !ext.empty() )
  718.     {
  719.         fullname << wxFILE_SEP_EXT << ext;
  720.     }
  721.  
  722.     return fullname;
  723. }
  724.  
  725. // Return just the directory, or NULL if no directory
  726. wxChar *
  727. wxPathOnly (wxChar *path)
  728. {
  729.     if (path && *path)
  730.     {
  731.         static wxChar buf[_MAXPATHLEN];
  732.  
  733.         // Local copy
  734.         wxStrcpy (buf, path);
  735.  
  736.         int l = wxStrlen(path);
  737.         int i = l - 1;
  738.  
  739.         // Search backward for a backward or forward slash
  740.         while (i > -1)
  741.         {
  742. #if defined(__WXMAC__) && !defined(__DARWIN__)
  743.             // Classic or Carbon CodeWarrior like
  744.             // Carbon with Apple DevTools is Unix like
  745.             if (path[i] == wxT(':') )
  746.             {
  747.                 buf[i] = 0;
  748.                 return buf;
  749.             }
  750. #else
  751.             // Unix like or Windows
  752.             if (path[i] == wxT('/') || path[i] == wxT('\\'))
  753.             {
  754.                 buf[i] = 0;
  755.                 return buf;
  756.             }
  757. #endif
  758. #ifdef __VMS__
  759.             if (path[i] == wxT(']'))
  760.             {
  761.                 buf[i+1] = 0;
  762.                 return buf;
  763.             }
  764. #endif
  765.             i --;
  766.         }
  767.  
  768. #if defined(__WXMSW__) || defined(__WXPM__)
  769.         // Try Drive specifier
  770.         if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
  771.         {
  772.             // A:junk --> A:. (since A:.\junk Not A:\junk)
  773.             buf[2] = wxT('.');
  774.             buf[3] = wxT('\0');
  775.             return buf;
  776.         }
  777. #endif
  778.     }
  779.     return (wxChar *) NULL;
  780. }
  781.  
  782. // Return just the directory, or NULL if no directory
  783. wxString wxPathOnly (const wxString& path)
  784. {
  785.     if (path != wxT(""))
  786.     {
  787.         wxChar buf[_MAXPATHLEN];
  788.  
  789.         // Local copy
  790.         wxStrcpy (buf, WXSTRINGCAST path);
  791.  
  792.         int l = path.Length();
  793.         int i = l - 1;
  794.  
  795.         // Search backward for a backward or forward slash
  796.         while (i > -1)
  797.         {
  798. #if defined(__WXMAC__) && !defined(__DARWIN__)
  799.             // Classic or Carbon CodeWarrior like
  800.             // Carbon with Apple DevTools is Unix like
  801.             if (path[i] == wxT(':') )
  802.             {
  803.                 buf[i] = 0;
  804.                 return wxString(buf);
  805.             }
  806. #else
  807.             // Unix like or Windows
  808.             if (path[i] == wxT('/') || path[i] == wxT('\\'))
  809.             {
  810.                 buf[i] = 0;
  811.                 return wxString(buf);
  812.             }
  813. #endif
  814. #ifdef __VMS__
  815.             if (path[i] == wxT(']'))
  816.             {
  817.                 buf[i+1] = 0;
  818.                 return wxString(buf);
  819.             }
  820. #endif
  821.             i --;
  822.         }
  823.  
  824. #if defined(__WXMSW__) || defined(__WXPM__)
  825.         // Try Drive specifier
  826.         if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
  827.         {
  828.             // A:junk --> A:. (since A:.\junk Not A:\junk)
  829.             buf[2] = wxT('.');
  830.             buf[3] = wxT('\0');
  831.             return wxString(buf);
  832.         }
  833. #endif
  834.     }
  835.     return wxString(wxT(""));
  836. }
  837.  
  838. // Utility for converting delimiters in DOS filenames to UNIX style
  839. // and back again - or we get nasty problems with delimiters.
  840. // Also, convert to lower case, since case is significant in UNIX.
  841.  
  842. #if defined(__WXMAC__)
  843. wxString wxMacFSSpec2MacFilename( const FSSpec *spec )
  844. {
  845. #ifdef __DARWIN__
  846.     int         i;
  847.     int         j;
  848.     OSErr       theErr;
  849.     OSStatus    theStatus;
  850.     Boolean     isDirectory = false;
  851.     Str255    theParentPath = "\p";
  852.     FSSpec      theParentSpec;
  853.     FSRef       theParentRef;
  854.     char        theFileName[FILENAME_MAX];
  855.     char        thePath[FILENAME_MAX];
  856.  
  857.     strcpy(thePath, "");
  858.  
  859.     // GD: Separate file name from path and make a FSRef to the parent
  860.     //     directory. This is necessary since FSRefs cannot reference files
  861.     //     that have not yet been created.
  862.     //     Based on example code from Apple Technical Note TN2022
  863.     //       http://developer.apple.com/technotes/tn/tn2022.html
  864.  
  865.     // check whether we are converting a directory
  866.     isDirectory = ((spec->name)[spec->name[0]] == ':');
  867.     // count length of file name
  868.     for (i = spec->name[0] - (isDirectory ? 1 : 0); ((spec->name[i] != ':') && (i > 0)); i--);
  869.     // copy file name
  870.     //   prepend path separator since it will later be appended to the path
  871.     theFileName[0] = wxFILE_SEP_PATH;
  872.     for (j = i + 1; j <= spec->name[0] - (isDirectory ? 1 : 0); j++) {
  873.         theFileName[j - i] = spec->name[j];
  874.     }
  875.     theFileName[j - i] = '\0';
  876.     // copy path if any
  877.     for (j = 1; j <= i; j++) {
  878.         theParentPath[++theParentPath[0]] = spec->name[j];
  879.     }
  880.     theErr = FSMakeFSSpec(spec->vRefNum, spec->parID, theParentPath, &theParentSpec);
  881.     if (theErr == noErr) {
  882.         // convert the FSSpec to an FSRef
  883.         theErr = FSpMakeFSRef(&theParentSpec, &theParentRef);
  884.     }
  885.     if (theErr == noErr) {
  886.         // get the POSIX path associated with the FSRef
  887.         theStatus = FSRefMakePath(&theParentRef,
  888.                                   (UInt8 *)thePath, sizeof(thePath));
  889.     }
  890.     if (theStatus == noErr) {
  891.         // append file name to path
  892.         //   includes previously prepended path separator
  893.         strcat(thePath, theFileName);
  894.     }
  895.  
  896.     // create path string for return value
  897.     wxString result( thePath ) ;
  898. #else
  899.     Handle    myPath ;
  900.     short     length ;
  901.  
  902.     // get length of path and allocate handle
  903.     FSpGetFullPath( spec , &length , &myPath ) ;
  904.     ::SetHandleSize( myPath , length + 1 ) ;
  905.     ::HLock( myPath ) ;
  906.     (*myPath)[length] = 0 ;
  907.     if ((length > 0) && ((*myPath)[length-1] == ':'))
  908.         (*myPath)[length-1] = 0 ;
  909.  
  910.     // create path string for return value
  911.     wxString result( (char*) *myPath ) ;
  912.  
  913.     // free allocated handle
  914.     ::HUnlock( myPath ) ;
  915.     ::DisposeHandle( myPath ) ;
  916. #endif
  917.  
  918.     return result ;
  919. }
  920. #ifndef __DARWIN__
  921. // Mac file names are POSIX (Unix style) under Darwin
  922. // therefore the conversion functions below are not needed
  923.  
  924. static char sMacFileNameConversion[ 1000 ] ;
  925.  
  926. #endif
  927. void wxMacFilename2FSSpec( const char *path , FSSpec *spec )
  928. {
  929.     OSStatus err = noErr ;
  930. #ifdef __DARWIN__
  931.     FSRef theRef;
  932.  
  933.     // get the FSRef associated with the POSIX path
  934.     err = FSPathMakeRef((const UInt8 *) path, &theRef, NULL);
  935.     // convert the FSRef to an FSSpec
  936.     err = FSGetCatalogInfo(&theRef, kFSCatInfoNone, NULL, NULL, spec, NULL);
  937. #else
  938.     if ( strchr( path , ':' ) == NULL )
  939.     {
  940.         // try whether it is a volume / or a mounted volume
  941.         strncpy( sMacFileNameConversion , path , 1000 ) ;
  942.         sMacFileNameConversion[998] = 0 ;
  943.         strcat( sMacFileNameConversion , ":" ) ;
  944.         err = FSpLocationFromFullPath( strlen(sMacFileNameConversion) , sMacFileNameConversion , spec ) ;
  945.     }
  946.     else
  947.     {
  948.         err = FSpLocationFromFullPath( strlen(path) , path , spec ) ;
  949.     }
  950. #endif
  951. }
  952.  
  953. #ifndef __DARWIN__
  954.  
  955. wxString wxMac2UnixFilename (const char *str)
  956. {
  957.     char *s = sMacFileNameConversion ;
  958.     strcpy( s , str ) ;
  959.     if (s)
  960.     {
  961.         memmove( s+1 , s ,strlen( s ) + 1) ;
  962.         if ( *s == ':' )
  963.             *s = '.' ;
  964.         else
  965.             *s = '/' ;
  966.  
  967.         while (*s)
  968.         {
  969.             if (*s == ':')
  970.                 *s = '/';
  971.             else
  972.                 *s = wxTolower(*s);        // Case INDEPENDENT
  973.             s++;
  974.         }
  975.     }
  976.     return wxString(sMacFileNameConversion) ;
  977. }
  978.  
  979. wxString wxUnix2MacFilename (const char *str)
  980. {
  981.     char *s = sMacFileNameConversion ;
  982.     strcpy( s , str ) ;
  983.     if (s)
  984.     {
  985.         if ( *s == '.' )
  986.         {
  987.             // relative path , since it goes on with slash which is translated to a :
  988.             memmove( s , s+1 ,strlen( s ) ) ;
  989.         }
  990.         else if ( *s == '/' )
  991.         {
  992.             // absolute path -> on mac just start with the drive name
  993.             memmove( s , s+1 ,strlen( s ) ) ;
  994.         }
  995.         else
  996.         {
  997.             wxASSERT_MSG( 1 , "unkown path beginning" ) ;
  998.         }
  999.         while (*s)
  1000.         {
  1001.             if (*s == '/' || *s == '\\')
  1002.             {
  1003.                 // convert any back-directory situations
  1004.                 if ( *(s+1) == '.' && *(s+2) == '.' && ( (*(s+3) == '/' || *(s+3) == '\\') ) )
  1005.                 {
  1006.                     *s = ':';
  1007.                     memmove( s+1 , s+3 ,strlen( s+3 ) + 1 ) ;
  1008.                 }
  1009.                 else
  1010.                     *s = ':';
  1011.             }
  1012.             s++ ;
  1013.         }
  1014.     }
  1015.     return wxString (sMacFileNameConversion) ;
  1016. }
  1017.  
  1018. wxString wxMacFSSpec2UnixFilename( const FSSpec *spec )
  1019. {
  1020.     return wxMac2UnixFilename( wxMacFSSpec2MacFilename( spec) ) ;
  1021. }
  1022.  
  1023. void wxUnixFilename2FSSpec( const char *path , FSSpec *spec )
  1024. {
  1025.     wxString var = wxUnix2MacFilename( path ) ;
  1026.     wxMacFilename2FSSpec( var , spec ) ;
  1027. }
  1028. #endif // ! __DARWIN__
  1029.  
  1030. #endif // __WXMAC__
  1031.  
  1032. void
  1033. wxDos2UnixFilename (char *s)
  1034. {
  1035.   if (s)
  1036.     while (*s)
  1037.       {
  1038.         if (*s == '\\')
  1039.           *s = '/';
  1040. #ifdef __WXMSW__
  1041.         else
  1042.           *s = wxTolower (*s);        // Case INDEPENDENT
  1043. #endif
  1044.         s++;
  1045.       }
  1046. }
  1047.  
  1048. void
  1049. #if defined(__WXMSW__) || defined(__WXPM__)
  1050. wxUnix2DosFilename (wxChar *s)
  1051. #else
  1052. wxUnix2DosFilename (wxChar *WXUNUSED(s) )
  1053. #endif
  1054. {
  1055. // Yes, I really mean this to happen under DOS only! JACS
  1056. #if defined(__WXMSW__) || defined(__WXPM__)
  1057.   if (s)
  1058.     while (*s)
  1059.       {
  1060.         if (*s == wxT('/'))
  1061.           *s = wxT('\\');
  1062.         s++;
  1063.       }
  1064. #endif
  1065. }
  1066.  
  1067. // Concatenate two files to form third
  1068. bool
  1069. wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
  1070. {
  1071.   wxString outfile;
  1072.   if ( !wxGetTempFileName( wxT("cat"), outfile) )
  1073.       return FALSE;
  1074.  
  1075.   FILE *fp1 = (FILE *) NULL;
  1076.   FILE *fp2 = (FILE *) NULL;
  1077.   FILE *fp3 = (FILE *) NULL;
  1078.   // Open the inputs and outputs
  1079.   if ((fp1 = wxFopen ( file1, wxT("rb"))) == NULL ||
  1080.       (fp2 = wxFopen ( file2, wxT("rb"))) == NULL ||
  1081.       (fp3 = wxFopen ( outfile, wxT("wb"))) == NULL)
  1082.     {
  1083.       if (fp1)
  1084.         fclose (fp1);
  1085.       if (fp2)
  1086.         fclose (fp2);
  1087.       if (fp3)
  1088.         fclose (fp3);
  1089.       return FALSE;
  1090.     }
  1091.  
  1092.   int ch;
  1093.   while ((ch = getc (fp1)) != EOF)
  1094.     (void) putc (ch, fp3);
  1095.   fclose (fp1);
  1096.  
  1097.   while ((ch = getc (fp2)) != EOF)
  1098.     (void) putc (ch, fp3);
  1099.   fclose (fp2);
  1100.  
  1101.   fclose (fp3);
  1102.   bool result = wxRenameFile(outfile, file3);
  1103.   return result;
  1104. }
  1105.  
  1106. // Copy files
  1107. bool
  1108. wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
  1109. {
  1110. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  1111.     // CopyFile() copies file attributes and modification time too, so use it
  1112.     // instead of our code if available
  1113.     //
  1114.     // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite
  1115.     if ( !::CopyFile(file1, file2, !overwrite) )
  1116.     {
  1117.         wxLogSysError(_("Failed to copy the file '%s' to '%s'"),
  1118.                       file1.c_str(), file2.c_str());
  1119.  
  1120.         return FALSE;
  1121.     }
  1122. #elif defined(__WXPM__)
  1123.     if ( ::DosCopy(file2, file2, overwrite ? DCPY_EXISTING : 0) != 0 )
  1124.         return FALSE;
  1125. #else // !Win32
  1126.  
  1127.     wxStructStat fbuf;
  1128.     // get permissions of file1
  1129.     if ( wxStat( file1.c_str(), &fbuf) != 0 )
  1130.     {
  1131.         // the file probably doesn't exist or we haven't the rights to read
  1132.         // from it anyhow
  1133.         wxLogSysError(_("Impossible to get permissions for file '%s'"),
  1134.                       file1.c_str());
  1135.         return FALSE;
  1136.     }
  1137.  
  1138.     // open file1 for reading
  1139.     wxFile fileIn(file1, wxFile::read);
  1140.     if ( !fileIn.IsOpened() )
  1141.         return FALSE;
  1142.  
  1143.     // remove file2, if it exists. This is needed for creating
  1144.     // file2 with the correct permissions in the next step
  1145.     if ( wxFileExists(file2)  && (!overwrite || !wxRemoveFile(file2)))
  1146.     {
  1147.         wxLogSysError(_("Impossible to overwrite the file '%s'"),
  1148.                       file2.c_str());
  1149.         return FALSE;
  1150.     }
  1151.  
  1152. #ifdef __UNIX__
  1153.     // reset the umask as we want to create the file with exactly the same
  1154.     // permissions as the original one
  1155.     mode_t oldUmask = umask( 0 );
  1156. #endif // __UNIX__
  1157.  
  1158.     // create file2 with the same permissions than file1 and open it for
  1159.     // writing
  1160.     
  1161.     wxFile fileOut;
  1162.     if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) )
  1163.         return FALSE;
  1164.  
  1165. #ifdef __UNIX__
  1166.     /// restore the old umask
  1167.     umask(oldUmask);
  1168. #endif // __UNIX__
  1169.  
  1170.     // copy contents of file1 to file2
  1171.     char buf[4096];
  1172.     size_t count;
  1173.     for ( ;; )
  1174.     {
  1175.         count = fileIn.Read(buf, WXSIZEOF(buf));
  1176.         if ( fileIn.Error() )
  1177.             return FALSE;
  1178.  
  1179.         // end of file?
  1180.         if ( !count )
  1181.             break;
  1182.  
  1183.         if ( fileOut.Write(buf, count) < count )
  1184.             return FALSE;
  1185.     }
  1186.  
  1187.     // we can expect fileIn to be closed successfully, but we should ensure
  1188.     // that fileOut was closed as some write errors (disk full) might not be
  1189.     // detected before doing this
  1190.     if ( !fileIn.Close() || !fileOut.Close() )
  1191.         return FALSE;
  1192.  
  1193. #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
  1194.     // no chmod in VA.  Should be some permission API for HPFS386 partitions
  1195.     // however
  1196.     if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 )
  1197.     {
  1198.         wxLogSysError(_("Impossible to set permissions for the file '%s'"),
  1199.                       file2.c_str());
  1200.         return FALSE;
  1201.     }
  1202. #endif // OS/2 || Mac
  1203. #endif // __WXMSW__ && __WIN32__
  1204.  
  1205.     return TRUE;
  1206. }
  1207.  
  1208. bool
  1209. wxRenameFile (const wxString& file1, const wxString& file2)
  1210. {
  1211.   // Normal system call
  1212.   if ( wxRename (file1, file2) == 0 )
  1213.     return TRUE;
  1214.  
  1215.   // Try to copy
  1216.   if (wxCopyFile(file1, file2)) {
  1217.     wxRemoveFile(file1);
  1218.     return TRUE;
  1219.   }
  1220.   // Give up
  1221.   return FALSE;
  1222. }
  1223.  
  1224. bool wxRemoveFile(const wxString& file)
  1225. {
  1226. #if defined(__VISUALC__) \
  1227.  || defined(__BORLANDC__) \
  1228.  || defined(__WATCOMC__) \
  1229.  || defined(__GNUWIN32__)
  1230.   int res = wxRemove(file);
  1231. #else
  1232.   int res = unlink(OS_FILENAME(file));
  1233. #endif
  1234.  
  1235.   return res == 0;
  1236. }
  1237.  
  1238. bool wxMkdir(const wxString& dir, int perm)
  1239. {
  1240. #if defined(__WXMAC__) && !defined(__UNIX__)
  1241.   return (mkdir( dir , 0 ) == 0);
  1242. #else // !Mac
  1243.     const wxChar *dirname = dir.c_str();
  1244.  
  1245.     // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too
  1246.     // for the GNU compiler
  1247. #if (!(defined(__WXMSW__) || defined(__WXPM__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WXWINE__) || defined(__WXMICROWIN__)
  1248.     if ( mkdir(wxFNCONV(dirname), perm) != 0 )
  1249. #elif defined(__WXPM__)
  1250.     if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's??
  1251. #elif defined(__DOS__)
  1252.   #if defined(__WATCOMC__)
  1253.     (void)perm;
  1254.     if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 )
  1255.   #elif defined(__DJGPP__)
  1256.     if ( mkdir(wxFNCONV(dirname), perm) != 0 )
  1257.   #else
  1258.     #error "Unsupported DOS compiler!"
  1259.   #endif
  1260. #else  // !MSW, !DOS and !OS/2 VAC++
  1261.     (void)perm;
  1262.     if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 )
  1263. #endif // !MSW/MSW
  1264.     {
  1265.         wxLogSysError(_("Directory '%s' couldn't be created"), dirname);
  1266.  
  1267.         return FALSE;
  1268.     }
  1269.  
  1270.     return TRUE;
  1271. #endif // Mac/!Mac
  1272. }
  1273.  
  1274. bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
  1275. {
  1276. #ifdef __VMS__
  1277.   return FALSE; //to be changed since rmdir exists in VMS7.x
  1278. #elif defined(__WXPM__)
  1279.   return (::DosDeleteDir((PSZ)dir.c_str()) == 0);
  1280. #else
  1281.  
  1282. #ifdef __SALFORDC__
  1283.   return FALSE; // What to do?
  1284. #else
  1285.   return (wxRmDir(OS_FILENAME(dir)) == 0);
  1286. #endif
  1287.  
  1288. #endif
  1289. }
  1290.  
  1291. // does the path exists? (may have or not '/' or '\\' at the end)
  1292. bool wxPathExists(const wxChar *pszPathName)
  1293. {
  1294.     wxString strPath(pszPathName);
  1295.  
  1296. #ifdef __WINDOWS__
  1297.     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
  1298.     // so remove all trailing backslashes from the path - but don't do this for
  1299.     // the pathes "d:\" (which are different from "d:") nor for just "\"
  1300.     while ( wxEndsWithPathSeparator(strPath) )
  1301.     {
  1302.         size_t len = strPath.length();
  1303.         if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) )
  1304.             break;
  1305.  
  1306.         strPath.Truncate(len - 1);
  1307.     }
  1308. #endif // __WINDOWS__
  1309.  
  1310. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  1311.     // stat() can't cope with network paths
  1312.     DWORD ret = ::GetFileAttributes(strPath);
  1313.  
  1314.     return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY);
  1315. #else // !__WIN32__
  1316.  
  1317.     wxStructStat st;
  1318. #ifndef __VISAGECPP__
  1319.     return wxStat(pszPathName, &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR);
  1320. #else
  1321.     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only
  1322.     return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR);
  1323. #endif
  1324.  
  1325. #endif // __WIN32__/!__WIN32__
  1326. }
  1327.  
  1328. // Get a temporary filename, opening and closing the file.
  1329. wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
  1330. {
  1331.     wxString filename = wxFileName::CreateTempFileName(prefix);
  1332.     if ( filename.empty() )
  1333.         return NULL;
  1334.  
  1335.     if ( buf )
  1336.         wxStrcpy(buf, filename);
  1337.     else
  1338.         buf = copystring(filename);
  1339.  
  1340.     return buf;
  1341. }
  1342.  
  1343. bool wxGetTempFileName(const wxString& prefix, wxString& buf)
  1344. {
  1345.     buf = wxFileName::CreateTempFileName(prefix);
  1346.  
  1347.     return !buf.empty();
  1348. }
  1349.  
  1350. // Get first file name matching given wild card.
  1351.  
  1352. static wxDir *gs_dir = NULL;
  1353. static wxString gs_dirPath;
  1354.  
  1355. wxString wxFindFirstFile(const wxChar *spec, int flags)
  1356. {
  1357.     wxSplitPath(spec, &gs_dirPath, NULL, NULL);
  1358.     if ( gs_dirPath.IsEmpty() )
  1359.         gs_dirPath = wxT(".");
  1360.     if ( gs_dirPath.Last() != wxFILE_SEP_PATH )
  1361.         gs_dirPath << wxFILE_SEP_PATH;
  1362.  
  1363.     if (gs_dir)
  1364.         delete gs_dir;
  1365.     gs_dir = new wxDir(gs_dirPath);
  1366.  
  1367.     if ( !gs_dir->IsOpened() )
  1368.     {
  1369.         wxLogSysError(_("Can not enumerate files '%s'"), spec);
  1370.         return wxEmptyString;
  1371.     }
  1372.  
  1373.     int dirFlags = 0;
  1374.     switch (flags)
  1375.     {
  1376.         case wxDIR:  dirFlags = wxDIR_DIRS; break;
  1377.         case wxFILE: dirFlags = wxDIR_FILES; break;
  1378.         default:     dirFlags = wxDIR_DIRS | wxDIR_FILES; break;
  1379.     }
  1380.  
  1381.     wxString result;
  1382.     gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags);
  1383.     if ( result.IsEmpty() )
  1384.     {
  1385.         wxDELETE(gs_dir);
  1386.         return result;
  1387.     }
  1388.  
  1389.     return gs_dirPath + result;
  1390. }
  1391.  
  1392. wxString wxFindNextFile()
  1393. {
  1394.     wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") );
  1395.  
  1396.     wxString result;
  1397.     gs_dir->GetNext(&result);
  1398.  
  1399.     if ( result.IsEmpty() )
  1400.     {
  1401.         wxDELETE(gs_dir);
  1402.         return result;
  1403.     }
  1404.  
  1405.     return gs_dirPath + result;
  1406. }
  1407.  
  1408.  
  1409. // Get current working directory.
  1410. // If buf is NULL, allocates space using new, else
  1411. // copies into buf.
  1412. wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
  1413. {
  1414.     if ( !buf )
  1415.     {
  1416.         buf = new wxChar[sz + 1];
  1417.     }
  1418.  
  1419.     bool ok = FALSE;
  1420.  
  1421.     // for the compilers which have Unicode version of _getcwd(), call it
  1422.     // directly, for the others call the ANSI version and do the translation
  1423. #if !wxUSE_UNICODE
  1424.     #define cbuf buf
  1425. #else // wxUSE_UNICODE
  1426.     bool needsANSI = TRUE;
  1427.  
  1428.     #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU
  1429.         // This is not legal code as the compiler 
  1430.         // is allowed destroy the wxCharBuffer.
  1431.         // wxCharBuffer c_buffer(sz);
  1432.         // char *cbuf = (char*)(const char*)c_buffer;
  1433.         char cbuf[_MAXPATHLEN];
  1434.     #endif
  1435.  
  1436.     #ifdef HAVE_WGETCWD
  1437.         #if wxUSE_UNICODE_MSLU
  1438.             if ( wxGetOsVersion() != wxWIN95 )
  1439.         #else
  1440.             char *cbuf = NULL; // never really used because needsANSI will always be FALSE
  1441.         #endif
  1442.             {
  1443.                 ok = _wgetcwd(buf, sz) != NULL;
  1444.                 needsANSI = FALSE;
  1445.             }
  1446.     #endif
  1447.  
  1448.     if ( needsANSI )
  1449. #endif // wxUSE_UNICODE
  1450.     {
  1451.     #ifdef _MSC_VER
  1452.         ok = _getcwd(cbuf, sz) != NULL;
  1453.     #elif defined(__WXMAC__) && !defined(__DARWIN__)
  1454.         FSSpec cwdSpec ;
  1455.         FCBPBRec pb;
  1456.         OSErr error;
  1457.         Str255  fileName ;
  1458.         pb.ioNamePtr = (StringPtr) &fileName;
  1459.         pb.ioVRefNum = 0;
  1460.         pb.ioRefNum = LMGetCurApRefNum();
  1461.         pb.ioFCBIndx = 0;
  1462.         error = PBGetFCBInfoSync(&pb);
  1463.         if ( error == noErr )
  1464.         {
  1465.             cwdSpec.vRefNum = pb.ioFCBVRefNum;
  1466.             cwdSpec.parID = pb.ioFCBParID;
  1467.             cwdSpec.name[0] = 0 ;
  1468.             wxString res = wxMacFSSpec2MacFilename( &cwdSpec ) ;
  1469.  
  1470.             strcpy( cbuf , res ) ;
  1471.             cbuf[res.length()]=0 ;
  1472.  
  1473.             ok = TRUE;
  1474.         }
  1475.         else
  1476.         {
  1477.             ok = FALSE;
  1478.         }
  1479.     #elif defined(__VISAGECPP__) || (defined (__OS2__) && defined (__WATCOMC__))
  1480.         APIRET rc;
  1481.         rc = ::DosQueryCurrentDir( 0 // current drive
  1482.                                   ,cbuf
  1483.                                   ,(PULONG)&sz
  1484.                                  );
  1485.         ok = rc != 0;
  1486.     #else // !Win32/VC++ !Mac !OS2
  1487.         ok = getcwd(cbuf, sz) != NULL;
  1488.     #endif // platform
  1489.  
  1490.     #if wxUSE_UNICODE
  1491.         // finally convert the result to Unicode if needed
  1492.         wxConvFile.MB2WC(buf, cbuf, sz);
  1493.     #endif // wxUSE_UNICODE
  1494.     }
  1495.  
  1496.     if ( !ok )
  1497.     {
  1498.         wxLogSysError(_("Failed to get the working directory"));
  1499.  
  1500.         // VZ: the old code used to return "." on error which didn't make any
  1501.         //     sense at all to me - empty string is a better error indicator
  1502.         //     (NULL might be even better but I'm afraid this could lead to
  1503.         //     problems with the old code assuming the return is never NULL)
  1504.         buf[0] = _T('\0');
  1505.     }
  1506.     else // ok, but we might need to massage the path into the right format
  1507.     {
  1508. #ifdef __DJGPP__
  1509.         // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths
  1510.         //     with / deliminers. We don't like that.
  1511.         for (wxChar *ch = buf; *ch; ch++)
  1512.         {
  1513.             if (*ch == wxT('/'))
  1514.                 *ch = wxT('\\');
  1515.         }
  1516. #endif // __DJGPP__
  1517.  
  1518. // MBN: we hope that in the case the user is compiling a GTK+/Motif app,
  1519. //      he needs Unix as opposed to Win32 pathnames
  1520. #if defined( __CYGWIN__ ) && defined( __WINDOWS__ )
  1521.         // another example of DOS/Unix mix (Cygwin)
  1522.         wxString pathUnix = buf;
  1523.         cygwin_conv_to_full_win32_path(pathUnix, buf);
  1524. #endif // __CYGWIN__
  1525.     }
  1526.  
  1527.     return buf;
  1528.  
  1529. #if !wxUSE_UNICODE
  1530.     #undef cbuf
  1531. #endif
  1532. }
  1533.  
  1534. wxString wxGetCwd()
  1535. {
  1536.     wxChar *buffer = new wxChar[_MAXPATHLEN];
  1537.     wxGetWorkingDirectory(buffer, _MAXPATHLEN);
  1538.     wxString str( buffer );
  1539.     delete [] buffer;
  1540.  
  1541.     return str;
  1542. }
  1543.  
  1544. bool wxSetWorkingDirectory(const wxString& d)
  1545. {
  1546. #if defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__)
  1547.   return (chdir(wxFNSTRINGCAST d.fn_str()) == 0);
  1548. #elif defined(__WXPM__)
  1549.   return (::DosSetCurrentDir((PSZ)d.c_str()) == 0);
  1550. #elif defined(__WINDOWS__)
  1551.  
  1552. #ifdef __WIN32__
  1553.   return (bool)(SetCurrentDirectory(d) != 0);
  1554. #else
  1555.   // Must change drive, too.
  1556.   bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':'));
  1557.   if (isDriveSpec)
  1558.   {
  1559.     wxChar firstChar = d[0];
  1560.  
  1561.     // To upper case
  1562.     if (firstChar > 90)
  1563.       firstChar = firstChar - 32;
  1564.  
  1565.     // To a drive number
  1566.     unsigned int driveNo = firstChar - 64;
  1567.     if (driveNo > 0)
  1568.     {
  1569.        unsigned int noDrives;
  1570.        _dos_setdrive(driveNo, &noDrives);
  1571.     }
  1572.   }
  1573.   bool success = (chdir(WXSTRINGCAST d) == 0);
  1574.  
  1575.   return success;
  1576. #endif
  1577.  
  1578. #endif
  1579. }
  1580.  
  1581. // Get the OS directory if appropriate (such as the Windows directory).
  1582. // On non-Windows platform, probably just return the empty string.
  1583. wxString wxGetOSDirectory()
  1584. {
  1585. #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
  1586.     wxChar buf[256];
  1587.     GetWindowsDirectory(buf, 256);
  1588.     return wxString(buf);
  1589. #else
  1590.     return wxEmptyString;
  1591. #endif
  1592. }
  1593.  
  1594. bool wxEndsWithPathSeparator(const wxChar *pszFileName)
  1595. {
  1596.     size_t len = wxStrlen(pszFileName);
  1597.  
  1598.     return len && wxIsPathSeparator(pszFileName[len - 1]);
  1599. }
  1600.  
  1601. // find a file in a list of directories, returns false if not found
  1602. bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile)
  1603. {
  1604.     // we assume that it's not empty
  1605.     wxCHECK_MSG( !wxIsEmpty(pszFile), FALSE,
  1606.                  _T("empty file name in wxFindFileInPath"));
  1607.  
  1608.     // skip path separator in the beginning of the file name if present
  1609.     if ( wxIsPathSeparator(*pszFile) )
  1610.         pszFile++;
  1611.  
  1612.     // copy the path (strtok will modify it)
  1613.     wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1];
  1614.     wxStrcpy(szPath, pszPath);
  1615.  
  1616.     wxString strFile;
  1617.     wxChar *pc, *save_ptr;
  1618.     for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr);
  1619.           pc != NULL;
  1620.           pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) )
  1621.     {
  1622.         // search for the file in this directory
  1623.         strFile = pc;
  1624.         if ( !wxEndsWithPathSeparator(pc) )
  1625.             strFile += wxFILE_SEP_PATH;
  1626.         strFile += pszFile;
  1627.  
  1628.         if ( wxFileExists(strFile) ) {
  1629.             *pStr = strFile;
  1630.             break;
  1631.         }
  1632.     }
  1633.  
  1634.     // suppress warning about unused variable save_ptr when wxStrtok() is a
  1635.     // macro which throws away its third argument
  1636.     save_ptr = pc;
  1637.  
  1638.     delete [] szPath;
  1639.  
  1640.     return pc != NULL;  // if true => we breaked from the loop
  1641. }
  1642.  
  1643. void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName,
  1644.                              wxString *pstrPath,
  1645.                              wxString *pstrName,
  1646.                              wxString *pstrExt)
  1647. {
  1648.     // it can be empty, but it shouldn't be NULL
  1649.     wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") );
  1650.  
  1651.     wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt);
  1652. }
  1653.  
  1654. time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)
  1655. {
  1656.     wxStructStat buf;
  1657.     wxStat( filename, &buf);
  1658.     
  1659.     return buf.st_mtime;
  1660. }
  1661.  
  1662.  
  1663. //------------------------------------------------------------------------
  1664. // wild character routines
  1665. //------------------------------------------------------------------------
  1666.  
  1667. bool wxIsWild( const wxString& pattern )
  1668. {
  1669.     wxString tmp = pattern;
  1670.     wxChar *pat = WXSTRINGCAST(tmp);
  1671.     while (*pat) 
  1672.     {
  1673.         switch (*pat++) 
  1674.         {
  1675.         case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'):
  1676.             return TRUE;
  1677.         case wxT('\\'):
  1678.             if (!*pat++)
  1679.                 return FALSE;
  1680.         }
  1681.     }
  1682.     return FALSE;
  1683. }
  1684.  
  1685. /*
  1686. * Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU>
  1687. *
  1688. * The match procedure is public domain code (from ircII's reg.c)
  1689. */
  1690.  
  1691. bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
  1692. {
  1693.         if (text.empty())
  1694.         {
  1695.                 /* Match if both are empty. */
  1696.                 return pat.empty();
  1697.         }
  1698.         
  1699.         const wxChar *m = pat.c_str(),
  1700.         *n = text.c_str(),
  1701.         *ma = NULL,
  1702.         *na = NULL,
  1703.         *mp = NULL,
  1704.         *np = NULL;
  1705.         int just = 0,
  1706.         pcount = 0,
  1707.         acount = 0,
  1708.         count = 0;
  1709.  
  1710.         if (dot_special && (*n == wxT('.')))
  1711.         {
  1712.                 /* Never match so that hidden Unix files 
  1713.                  * are never found. */
  1714.                 return FALSE;
  1715.         }
  1716.  
  1717.         for (;;)
  1718.         {
  1719.                 if (*m == wxT('*'))
  1720.                 {
  1721.                         ma = ++m;
  1722.                         na = n;
  1723.                         just = 1;
  1724.                         mp = NULL;
  1725.                         acount = count;
  1726.                 }
  1727.                 else if (*m == wxT('?'))
  1728.                 {
  1729.                         m++;
  1730.                         if (!*n++)
  1731.                         return FALSE;
  1732.                 }
  1733.                 else
  1734.                 {
  1735.                         if (*m == wxT('\\'))
  1736.                         {
  1737.                                 m++;
  1738.                                 /* Quoting "nothing" is a bad thing */
  1739.                                 if (!*m)
  1740.                                 return FALSE;
  1741.                         }
  1742.                         if (!*m)
  1743.                         {
  1744.                                 /*
  1745.                                 * If we are out of both strings or we just
  1746.                                 * saw a wildcard, then we can say we have a
  1747.                                 * match
  1748.                                 */
  1749.                                 if (!*n)
  1750.                                 return TRUE;
  1751.                                 if (just)
  1752.                                 return TRUE;
  1753.                                 just = 0;
  1754.                                 goto not_matched;
  1755.                         }
  1756.                         /*
  1757.                         * We could check for *n == NULL at this point, but
  1758.                         * since it's more common to have a character there,
  1759.                         * check to see if they match first (m and n) and
  1760.                         * then if they don't match, THEN we can check for
  1761.                         * the NULL of n
  1762.                         */
  1763.                         just = 0;
  1764.                         if (*m == *n)
  1765.                         {
  1766.                                 m++;
  1767.                                 if (*n == wxT(' '))
  1768.                                 mp = NULL;
  1769.                                 count++;
  1770.                                 n++;
  1771.                         }
  1772.                         else
  1773.                         {
  1774.  
  1775.                                 not_matched:
  1776.  
  1777.                                 /*
  1778.                                 * If there are no more characters in the
  1779.                                 * string, but we still need to find another
  1780.                                 * character (*m != NULL), then it will be
  1781.                                 * impossible to match it
  1782.                                 */
  1783.                                 if (!*n)
  1784.                                 return FALSE;
  1785.                                 if (mp)
  1786.                                 {
  1787.                                         m = mp;
  1788.                                         if (*np == wxT(' '))
  1789.                                         {
  1790.                                                 mp = NULL;
  1791.                                                 goto check_percent;
  1792.                                         }
  1793.                                         n = ++np;
  1794.                                         count = pcount;
  1795.                                 }
  1796.                                 else
  1797.                                 check_percent:
  1798.  
  1799.                                 if (ma)
  1800.                                 {
  1801.                                         m = ma;
  1802.                                         n = ++na;
  1803.                                         count = acount;
  1804.                                 }
  1805.                                 else
  1806.                                 return FALSE;
  1807.                         }
  1808.                 }
  1809.         }
  1810. }
  1811.  
  1812.  
  1813. #ifdef __VISUALC__
  1814.     #pragma warning(default:4706)   // assignment within conditional expression
  1815. #endif // VC++
  1816.