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