filefn.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,984 行 · 第 1/4 页

CPP
1,984
字号
/////////////////////////////////////////////////////////////////////////////
// Name:        filefn.cpp
// Purpose:     File- and directory-related functions
// Author:      Julian Smart
// Modified by:
// Created:     29/01/98
// RCS-ID:      $Id: filefn.cpp,v 1.249.2.5 2006/02/27 15:16:37 VZ Exp $
// Copyright:   (c) 1998 Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "filefn.h"
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/defs.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include "wx/utils.h"
#include "wx/intl.h"
#include "wx/file.h" // This does include filefn.h
#include "wx/filename.h"
#include "wx/dir.h"

// there are just too many of those...
#ifdef __VISUALC__
    #pragma warning(disable:4706)   // assignment within conditional expression
#endif // VC++

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(__WATCOMC__)
    #if !(defined(_MSC_VER) && (_MSC_VER > 800))
        #include <errno.h>
    #endif
#endif

#if defined(__WXMAC__)
    #include  "wx/mac/private.h"  // includes mac headers
#endif

#include "wx/log.h"

#ifdef __WINDOWS__
    #include "wx/msw/private.h"
    #include "wx/msw/mslu.h"

    // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path()
    //
    // note that it must be included after <windows.h>
    #ifdef __GNUWIN32__
        #ifdef __CYGWIN__
            #include <sys/cygwin.h>
        #endif
    #endif // __GNUWIN32__

    // io.h is needed for _get_osfhandle()
    // Already included by filefn.h for many Windows compilers
    #if defined __MWERKS__ || defined __CYGWIN__
        #include <io.h>
    #endif
#endif // __WINDOWS__

#if defined(__VMS__)
    #include <fab.h>
#endif

// TODO: Borland probably has _wgetcwd as well?
#ifdef _MSC_VER
    #define HAVE_WGETCWD
#endif

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

#ifndef _MAXPATHLEN
    #define _MAXPATHLEN 1024
#endif

#ifdef __WXMAC__
#    include "MoreFilesX.h"
#endif

// ----------------------------------------------------------------------------
// private globals
// ----------------------------------------------------------------------------

// MT-FIXME: get rid of this horror and all code using it
static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN];

#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
//
// VisualAge C++ V4.0 cannot have any external linkage const decs
// in headers included by more than one primary source
//
const int wxInvalidOffset = -1;
#endif

// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------

// we need to translate Mac filenames before passing them to OS functions
#define OS_FILENAME(s) (s.fn_str())

// ============================================================================
// implementation
// ============================================================================

#ifdef wxNEED_WX_UNISTD_H

WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf )
{
    return stat( wxConvFile.cWX2MB( file_name ), buf );
}

WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode )
{
    return access( wxConvFile.cWX2MB( pathname ), mode );
}

WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode )
{
    return open( wxConvFile.cWX2MB( pathname ), flags, mode );
}

#endif
   // wxNEED_WX_UNISTD_H

// ----------------------------------------------------------------------------
// wxPathList
// ----------------------------------------------------------------------------

// IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)

static inline wxChar* MYcopystring(const wxString& s)
{
    wxChar* copy = new wxChar[s.length() + 1];
    return wxStrcpy(copy, s.c_str());
}

static inline wxChar* MYcopystring(const wxChar* s)
{
    wxChar* copy = new wxChar[wxStrlen(s) + 1];
    return wxStrcpy(copy, s);
}

void wxPathList::Add (const wxString& path)
{
    wxStringList::Add (WXSTRINGCAST path);
}

// Add paths e.g. from the PATH environment variable
void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable))
{
    // No environment variables on WinCE
#ifndef __WXWINCE__
    static const wxChar PATH_TOKS[] =
#if defined(__WINDOWS__) || defined(__OS2__)
        /*
        The space has been removed from the tokenizers, otherwise a
        path such as "C:\Program Files" would be split into 2 paths:
        "C:\Program" and "Files"
        */
//        wxT(" ;"); // Don't separate with colon in DOS (used for drive)
        wxT(";"); // Don't separate with colon in DOS (used for drive)
#else
        wxT(" :;");
#endif

    wxString val ;
    if (wxGetEnv (WXSTRINGCAST envVariable, &val))
    {
        wxChar *s = MYcopystring (val);
        wxChar *save_ptr, *token = wxStrtok (s, PATH_TOKS, &save_ptr);

        if (token)
        {
            Add(token);
            while (token)
            {
                if ( (token = wxStrtok ((wxChar *) NULL, PATH_TOKS, &save_ptr))
                    != NULL )
                {
                    Add(token);
                }
            }
        }

        // suppress warning about unused variable save_ptr when wxStrtok() is a
        // macro which throws away its third argument
        save_ptr = token;

        delete [] s;
    }
#endif // !__WXWINCE__
}

// Given a full filename (with path), ensure that that file can
// be accessed again USING FILENAME ONLY by adding the path
// to the list if not already there.
void wxPathList::EnsureFileAccessible (const wxString& path)
{
    wxString path_only(wxPathOnly(path));
    if ( !path_only.empty() )
    {
        if ( !Member(path_only) )
            Add(path_only);
    }
}

bool wxPathList::Member (const wxString& path)
{
  for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext())
  {
      wxString path2( node->GetData() );
      if (
#if defined(__WINDOWS__) || defined(__OS2__) || defined(__VMS__) || defined(__WXMAC__)
      // Case INDEPENDENT
          path.CompareTo (path2, wxString::ignoreCase) == 0
#else
      // Case sensitive File System
          path.CompareTo (path2) == 0
#endif
        )
        return true;
  }
  return false;
}

wxString wxPathList::FindValidPath (const wxString& file)
{
  if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer, file)))
    return wxString(wxFileFunctionsBuffer);

  wxChar buf[_MAXPATHLEN];
  wxStrcpy(buf, wxFileFunctionsBuffer);

  wxChar *filename = wxIsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (wxChar *)buf;

  for (wxStringList::compatibility_iterator node = GetFirst(); node; node = node->GetNext())
    {
      const wxString path(node->GetData());
      wxStrcpy (wxFileFunctionsBuffer, path);
      wxChar ch = wxFileFunctionsBuffer[wxStrlen(wxFileFunctionsBuffer)-1];
      if (ch != wxT('\\') && ch != wxT('/'))
        wxStrcat (wxFileFunctionsBuffer, wxT("/"));
      wxStrcat (wxFileFunctionsBuffer, filename);
#ifdef __WINDOWS__
      wxUnix2DosFilename (wxFileFunctionsBuffer);
#endif
      if (wxFileExists (wxFileFunctionsBuffer))
      {
        return wxString(wxFileFunctionsBuffer);        // Found!
      }
    }                                // for()

  return wxEmptyString;                    // Not found
}

wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
{
    wxString f = FindValidPath(file);
    if ( f.empty() || wxIsAbsolutePath(f) )
        return f;

    wxString buf;
    wxGetWorkingDirectory(wxStringBuffer(buf, _MAXPATHLEN), _MAXPATHLEN);

    if ( !wxEndsWithPathSeparator(buf) )
    {
        buf += wxFILE_SEP_PATH;
    }
    buf += f;

    return buf;
}

bool
wxFileExists (const wxString& filename)
{
#if defined(__WXPALMOS__)
    return false;
#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
    // we must use GetFileAttributes() instead of the ANSI C functions because
    // it can cope with network (UNC) paths unlike them
    DWORD ret = ::GetFileAttributes(filename);

    return (ret != (DWORD)-1) && !(ret & FILE_ATTRIBUTE_DIRECTORY);
#else // !__WIN32__
    wxStructStat st;
#ifndef wxNEED_WX_UNISTD_H
    return (wxStat( filename.fn_str() , &st) == 0 && (st.st_mode & S_IFREG))
#ifdef __OS2__
      || (errno == EACCES) // if access is denied something with that name
                            // exists and is opened in exclusive mode.
#endif
      ;
#else
    return wxStat( filename , &st) == 0 && (st.st_mode & S_IFREG);
#endif
#endif // __WIN32__/!__WIN32__
}

bool
wxIsAbsolutePath (const wxString& filename)
{
    if (!filename.empty())
    {
#if defined(__WXMAC__) && !defined(__DARWIN__)
        // Classic or Carbon CodeWarrior like
        // Carbon with Apple DevTools is Unix like

        // This seems wrong to me, but there is no fix. since
        // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt"
        // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR.
        if (filename.Find(':') != wxNOT_FOUND && filename[0] != ':')
            return true ;
#else
        // Unix like or Windows
        if (filename[0] == wxT('/'))
            return true;
#endif
#ifdef __VMS__
        if ((filename[0] == wxT('[') && filename[1] != wxT('.')))
            return true;
#endif
#if defined(__WINDOWS__) || defined(__OS2__)
        // MSDOS like
        if (filename[0] == wxT('\\') || (wxIsalpha (filename[0]) && filename[1] == wxT(':')))
            return true;
#endif
    }
    return false ;
}

/*
 * Strip off any extension (dot something) from end of file,
 * IF one exists. Inserts zero into buffer.
 *
 */

void wxStripExtension(wxChar *buffer)
{
    int len = wxStrlen(buffer);
    int i = len-1;
    while (i > 0)
    {
        if (buffer[i] == wxT('.'))
        {
            buffer[i] = 0;
            break;
        }
        i --;
    }
}

void wxStripExtension(wxString& buffer)
{
    //RN:  Be careful about the handling the case where
    //buffer.Length() == 0
    for(size_t i = buffer.Length() - 1; i != wxString::npos; --i)
    {
        if (buffer.GetChar(i) == wxT('.'))
        {
          buffer = buffer.Left(i);
          break;
        }
    }
}

// Destructive removal of /./ and /../ stuff
wxChar *wxRealPath (wxChar *path)
{
#ifdef __WXMSW__
  static const wxChar SEP = wxT('\\');
  wxUnix2DosFilename(path);
#else
  static const wxChar SEP = wxT('/');
#endif
  if (path[0] && path[1]) {
    /* MATTHEW: special case "/./x" */
    wxChar *p;
    if (path[2] == SEP && path[1] == wxT('.'))
      p = &path[0];
    else
      p = &path[2];
    for (; *p; p++)
      {
        if (*p == SEP)
          {
            if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0')))
              {
                wxChar *q;
                for (q = p - 1; q >= path && *q != SEP; q--)
                {
                    // Empty
                }

                if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP)
                    && (q - 1 <= path || q[-1] != SEP))
                  {
                    wxStrcpy (q, p + 3);
                    if (path[0] == wxT('\0'))
                      {
                        path[0] = SEP;
                        path[1] = wxT('\0');
                      }
#if defined(__WXMSW__) || defined(__OS2__)
                    /* Check that path[2] is NULL! */
                    else if (path[1] == wxT(':') && !path[2])
                      {
                        path[2] = SEP;
                        path[3] = wxT('\0');
                      }
#endif
                    p = q - 1;
                  }
              }
            else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0')))
              wxStrcpy (p, p + 2);
          }
      }
  }
  return path;
}

// Must be destroyed
wxChar *wxCopyAbsolutePath(const wxString& filename)
{
  if (filename.empty())
    return (wxChar *) NULL;

  if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) {
    wxChar  buf[_MAXPATHLEN];
    buf[0] = wxT('\0');
    wxGetWorkingDirectory(buf, WXSIZEOF(buf));
    wxChar ch = buf[wxStrlen(buf) - 1];
#ifdef __WXMSW__
    if (ch != wxT('\\') && ch != wxT('/'))
        wxStrcat(buf, wxT("\\"));
#else
    if (ch != wxT('/'))
        wxStrcat(buf, wxT("/"));
#endif
    wxStrcat(buf, wxFileFunctionsBuffer);
    return MYcopystring( wxRealPath(buf) );
  }
  return MYcopystring( wxFileFunctionsBuffer );
}

/*-
 Handles:
   ~/ => home dir
   ~user/ => user's home dir
   If the environment variable a = "foo" and b = "bar" then:
   Unix:
        $a        =>        foo
        $a$b        =>        foobar
        $a.c        =>        foo.c
        xxx$a        =>        xxxfoo
        ${a}!        =>        foo!
        $(b)!        =>        bar!
        \$a        =>        \$a
   MSDOS:
        $a        ==>        $a
        $(a)        ==>        foo
        $(a)$b        ==>        foo$b
        $(a)$(b)==>        foobar
        test.$$        ==>        test.$$
 */

/* input name in name, pathname output to buf. */

wxChar *wxExpandPath(wxChar *buf, const wxChar *name)
{
    register wxChar *d, *s, *nm;
    wxChar          lnm[_MAXPATHLEN];
    int             q;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?