Files
wxWidgets/src/common/file.cpp
Vadim Zeitlin c86f1403c3 globally renamed uint to size_t. This has _not_ been checked under Windows,
although I changed msw files also, so please wait until this evening if you
want to be sure that it compiles. This change should fix 64 bit compilation
problems, but it would be nice to test it...


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@591 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1998-08-18 15:36:12 +00:00

484 lines
11 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: file.cpp
// Purpose: wxFile - encapsulates low-level "file descriptor"
// wxTempFile
// Author: Vadim Zeitlin
// Modified by:
// Created: 29/01/98
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "file.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/defs.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// standard
#if defined(__WXMSW__) && !defined(__GNUWIN32__)
#include <io.h>
#define WIN32_LEAN_AND_MEAN
#define NOSERVICE
#define NOIME
#define NOATOM
#define NOGDI
#define NOGDICAPMASKS
#define NOMETAFILE
#define NOMINMAX
#define NOMSG
#define NOOPENFILE
#define NORASTEROPS
#define NOSCROLL
#define NOSOUND
#define NOSYSMETRICS
#define NOTEXTMETRIC
#define NOWH
#define NOCOMM
#define NOKANJI
#define NOCRYPT
#define NOMCX
#include <windows.h> // for GetTempFileName
#elif (defined(__UNIX__) || defined(__GNUWIN32__))
#include <unistd.h>
#elif (defined(__WXSTUBS__))
// Have to ifdef this for different environments
#include <io.h>
#else
#error "Please specify the header with file functions declarations."
#endif //Win/UNIX
#include <stdio.h> // SEEK_xxx constants
#include <fcntl.h> // O_RDONLY &c
#include <sys/types.h> // needed for stat
#include <sys/stat.h> // stat
// Microsoft compiler loves underscores, feed them to it
#ifdef _MSC_VER
// functions
#define open _open
#define close _close
#define read _read
#define write _write
#define lseek _lseek
#define fsync _commit
#define access _access
#define eof _eof
// types
#define stat _stat
// constants
#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
#define O_RDWR _O_RDWR
#define O_EXCL _O_EXCL
#define O_CREAT _O_CREAT
#define O_BINARY _O_BINARY
#define S_IFDIR _S_IFDIR
#define S_IFREG _S_IFREG
#define W_OK 2
#define R_OK 4
#else
#define tell(fd) lseek(fd, 0, SEEK_CUR)
#endif //_MSC_VER
#ifdef __BORLANDC__
#define W_OK 2
#define R_OK 4
#endif
// there is no distinction between text and binary files under Unix
#ifdef __UNIX__
#define O_BINARY (0)
#endif //__UNIX__
// wxWindows
#include <wx/string.h>
#include <wx/intl.h>
#include <wx/file.h>
#include <wx/log.h>
#ifndef MAX_PATH
#define MAX_PATH 512
#endif
// ============================================================================
// implementation of wxFile
// ============================================================================
// ----------------------------------------------------------------------------
// static functions
// ----------------------------------------------------------------------------
bool wxFile::Exists(const char *name)
{
struct stat st;
return !access(name, 0) && !stat(name, &st) && (st.st_mode & S_IFREG);
}
bool wxFile::Access(const char *name, OpenMode mode)
{
int how;
switch ( mode ) {
case read:
how = R_OK;
break;
case write:
how = W_OK;
break;
default:
wxFAIL_MSG("bad wxFile::Access mode parameter.");
}
return access(name, how) == 0;
}
// ----------------------------------------------------------------------------
// opening/closing
// ----------------------------------------------------------------------------
// ctors
wxFile::wxFile(const char *szFileName, OpenMode mode)
{
m_fd = fd_invalid;
m_error = FALSE;
Open(szFileName, mode);
}
// dtor
wxFile::~wxFile()
{
Close();
}
// create the file, fail if it already exists and bOverwrite
bool wxFile::Create(const char *szFileName, bool bOverwrite, int access)
{
// if bOverwrite we create a new file or truncate the existing one,
// otherwise we only create the new file and fail if it already exists
int fd = open(szFileName, O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
if ( fd == -1 ) {
wxLogSysError(_("can't create file '%s'"), szFileName);
return FALSE;
}
else {
Attach(fd);
return TRUE;
}
}
// open the file
bool wxFile::Open(const char *szFileName, OpenMode mode, int access)
{
int flags = O_BINARY;
switch ( mode ) {
case read:
flags |= O_RDONLY;
break;
case write:
flags |= O_WRONLY | O_CREAT | O_TRUNC;
break;
case write_append:
flags |= O_WRONLY | O_APPEND;
break;
case read_write:
flags |= O_RDWR;
break;
}
int fd = open(szFileName, flags, access);
if ( fd == -1 ) {
wxLogSysError(_("can't open file '%s'"), szFileName);
return FALSE;
}
else {
Attach(fd);
return TRUE;
}
}
// close
bool wxFile::Close()
{
if ( IsOpened() ) {
if ( close(m_fd) == -1 ) {
wxLogSysError(_("can't close file descriptor %d"), m_fd);
m_fd = fd_invalid;
return FALSE;
}
else
m_fd = fd_invalid;
}
return TRUE;
}
// ----------------------------------------------------------------------------
// read/write
// ----------------------------------------------------------------------------
// read
off_t wxFile::Read(void *pBuf, off_t nCount)
{
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
int iRc = ::read(m_fd, pBuf, nCount);
if ( iRc == -1 ) {
wxLogSysError(_("can't read from file descriptor %d"), m_fd);
return wxInvalidOffset;
}
else
return (size_t)iRc;
}
// write
size_t wxFile::Write(const void *pBuf, size_t nCount)
{
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
int iRc = ::write(m_fd, pBuf, nCount);
if ( iRc == -1 ) {
wxLogSysError(_("can't write to file descriptor %d"), m_fd);
m_error = TRUE;
return 0;
}
else
return iRc;
}
// flush
bool wxFile::Flush()
{
if ( IsOpened() ) {
// @@@ fsync() is not ANSI (BSDish)
// if ( fsync(m_fd) == -1 ) { // TODO
if (TRUE) {
wxLogSysError(_("can't flush file descriptor %d"), m_fd);
return FALSE;
}
}
return TRUE;
}
// ----------------------------------------------------------------------------
// seek
// ----------------------------------------------------------------------------
// seek
off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
{
wxASSERT( IsOpened() );
int flag = -1;
switch ( mode ) {
case wxFromStart:
flag = SEEK_SET;
break;
case wxFromCurrent:
flag = SEEK_CUR;
break;
case wxFromEnd:
flag = SEEK_END;
break;
default:
wxFAIL_MSG(_("unknown seek origin"));
}
int iRc = lseek(m_fd, ofs, flag);
if ( iRc == -1 ) {
wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
return wxInvalidOffset;
}
else
return (off_t)iRc;
}
// get current off_t
off_t wxFile::Tell() const
{
wxASSERT( IsOpened() );
int iRc = tell(m_fd);
if ( iRc == -1 ) {
wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
return wxInvalidOffset;
}
else
return (off_t)iRc;
}
// get current file length
off_t wxFile::Length() const
{
wxASSERT( IsOpened() );
#ifdef _MSC_VER
int iRc = _filelength(m_fd);
#else
int iRc = tell(m_fd);
if ( iRc != -1 ) {
// @ have to use const_cast :-(
int iLen = ((wxFile *)this)->SeekEnd();
if ( iLen != -1 ) {
// restore old position
if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
// error
iLen = -1;
}
}
iRc = iLen;
}
#endif //_MSC_VER
if ( iRc == -1 ) {
wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
return wxInvalidOffset;
}
else
return (off_t)iRc;
}
// is end of file reached?
bool wxFile::Eof() const
{
wxASSERT( IsOpened() );
int iRc;
#if defined(__UNIX__) || defined(__GNUWIN32__)
// @@ this doesn't work, of course, on unseekable file descriptors
off_t ofsCur = Tell(),
ofsMax = Length();
if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
iRc = -1;
else
iRc = ofsCur == ofsMax;
#else // Windows and "native" compiler
iRc = eof(m_fd);
#endif // Windows/Unix
switch ( iRc ) {
case 1:
break;
case 0:
return FALSE;
case -1:
wxLogSysError(_("can't determine if the end of file is reached on \
descriptor %d"), m_fd);
break;
default:
wxFAIL_MSG(_("invalid eof() return value."));
}
return TRUE;
}
// ============================================================================
// implementation of wxTempFile
// ============================================================================
// ----------------------------------------------------------------------------
// construction
// ----------------------------------------------------------------------------
wxTempFile::wxTempFile(const wxString& strName)
{
Open(strName);
}
bool wxTempFile::Open(const wxString& strName)
{
m_strName = strName;
// we want to create the file in the same directory as strName because
// otherwise rename() in Commit() might not work (if the files are on
// different partitions for example). Unfortunately, the only standard
// (POSIX) temp file creation function tmpnam() can't do it.
#if defined(__UNIX__) || defined(__WXSTUBS__)
static const char *szMktempSuffix = "XXXXXX";
m_strTemp << strName << szMktempSuffix;
mktemp((char *)m_strTemp.c_str()); // will do because length doesn't change
#else // Windows
wxString strPath;
wxSplitPath(strName, &strPath, NULL, NULL);
if ( strPath.IsEmpty() )
strPath = '.'; // GetTempFileName will fail if we give it empty string
#ifdef __WIN32__
if ( !GetTempFileName(strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
#else
// Not sure why MSVC++ 1.5 header defines first param as BYTE - bug?
if ( !GetTempFileName((BYTE) (const char*) strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
#endif
wxLogLastError("GetTempFileName");
m_strTemp.UngetWriteBuf();
#endif // Windows/Unix
return m_file.Open(m_strTemp, wxFile::write);
}
// ----------------------------------------------------------------------------
// destruction
// ----------------------------------------------------------------------------
wxTempFile::~wxTempFile()
{
if ( IsOpened() )
Discard();
}
bool wxTempFile::Commit()
{
m_file.Close();
if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
return FALSE;
}
if ( rename(m_strTemp, m_strName) != 0 ) {
wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
return FALSE;
}
return TRUE;
}
void wxTempFile::Discard()
{
m_file.Close();
if ( remove(m_strTemp) != 0 )
wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
}