This commit is contained in:
Glenn Maynard
2003-12-04 08:25:59 +00:00
parent 78c96b7cad
commit ea0ba6fcb9
9 changed files with 761 additions and 81 deletions
+220 -44
View File
@@ -7,14 +7,15 @@
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
Chris Danford
Steve Checkoway
Steve Checkoway
Glenn Maynard
-----------------------------------------------------------------------------
*/
#include "global.h"
#include "RageFile.h"
#include "RageUtil.h"
#include "RageFileDriver.h"
void FixSlashesInPlace( CString &sPath )
{
@@ -31,45 +32,76 @@ CString FixSlashes( CString sPath )
void CollapsePath( CString &sPath )
{
CStringArray as;
split( sPath, SLASH, as );
for( unsigned i=0; i<as.size(); i++ )
{
if( as[i] == ".." )
CStringArray as;
split( sPath, SLASH, as );
for( unsigned i=0; i<as.size(); i++ )
{
as.erase( as.begin()+i-1 );
as.erase( as.begin()+i-1 );
i -= 2;
if( as[i] == ".." )
{
as.erase( as.begin()+i-1 );
as.erase( as.begin()+i-1 );
i -= 2;
}
}
}
sPath = join( SLASH, as );
sPath = join( SLASH, as );
}
RageFile::RageFile()
{
m_File = NULL;
m_BufUsed = 0;
m_EOF = false;
m_FilePos = 0;
}
RageFile::RageFile( const CString& path, RageFile::OpenMode mode )
{
mFP = NULL;
m_File = NULL;
m_BufUsed = 0;
m_EOF = false;
m_FilePos = 0;
Open(path, mode);
}
CString RageFile::GetPath() const
{
if ( !IsOpen() )
return "";
return m_File->GetDisplayPath();
}
bool RageFile::Open( const CString& path, RageFile::OpenMode mode )
{
ASSERT( FILEMAN );
Close();
mPath = path;
FixSlashesInPlace(mPath);
mFP = fopen( mPath, mode == READ? "r":"w" );
m_Path = path;
FixSlashesInPlace(m_Path);
m_Mode = mode;
m_EOF = false;
m_FilePos = 0;
ResetBuf();
return mFP == NULL;
int error;
m_File = FILEMAN->Open( path, mode, *this, error );
if( m_File == NULL )
{
SetError( strerror(error) );
return false;
}
return true;
}
void RageFile::Close()
{
if (IsOpen())
fclose(mFP);
mFP = NULL;
delete m_File;
m_File = NULL;
}
void RageFile::ResetBuf()
@@ -80,21 +112,37 @@ void RageFile::ResetBuf()
/* Read up to the next \n, and return it in out. Strip the \n. If the \n is
* preceded by a \r (DOS newline), strip that, too. */
void RageFile::GetLine( CString &out )
int RageFile::GetLine( CString &out )
{
out = "";
if (!IsOpen())
RageException::Throw("\"%s\" is not open.", mPath.c_str());
if ( !IsOpen() )
RageException::Throw("\"%s\" is not open.", m_Path.c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading", GetPath().c_str());
bool GotData = false;
while( 1 )
{
bool done = false;
/* Find the end of the block we'll move to out. */
char *p = (char *) memchr( m_pBuf, '\n', m_BufUsed );
bool ReAddCR = false;
if( p == NULL )
{
/* Hack: If the last character of the buffer is \r, then it's likely that an
* \r\n has been split across buffers. Move everything else, then move the
* \r to the beginning of the buffer and handle it the next time around the loop. */
if( m_pBuf[m_BufUsed-1] == '\r' )
{
ReAddCR = true;
--m_BufUsed;
}
p = m_pBuf+m_BufUsed; /* everything */
}
else
done = true;
@@ -107,22 +155,54 @@ void RageFile::GetLine( CString &out )
if( done )
++p; /* skip \n */
m_BufUsed -= p-m_pBuf;
m_pBuf = p;
const int used = p-m_pBuf;
if( used )
{
m_BufUsed -= used;
m_FilePos += used;
GotData = true;
m_pBuf = p;
}
}
if( ReAddCR )
{
ASSERT( m_BufUsed == 0 );
m_pBuf = m_Buffer;
m_Buffer[m_BufUsed] = '\r';
++m_BufUsed;
}
if( done )
break;
/* We need more data. That implies that we moved everything. */
ASSERT( !m_BufUsed );
/* We need more data. */
m_pBuf = m_Buffer;
size_t size = Read( m_pBuf, sizeof(m_Buffer) );
if( size <= 0 )
const int size = m_File->Read( m_pBuf+m_BufUsed, sizeof(m_Buffer)-m_BufUsed );
/* If we've read data already, then don't mark EOF yet. Wait until the
* next time we're called. */
if( size == 0 && !GotData )
{
m_EOF = true;
return 0;
}
if( size < 0 )
return -1; // error
if( size == 0 )
break; // EOF or error
m_BufUsed += size;
}
return GotData? 1:0;
}
CString RageFile::GetLine()
{
CString ret;
GetLine( ret );
return ret;
}
#if defined(_WIN32)
@@ -133,46 +213,142 @@ void RageFile::GetLine( CString &out )
int RageFile::PutLine( const CString &str )
{
if( Write(str.data(), str.size()) == -1 )
if( Write(str) == -1 )
return -1;
return Write( NEWLINE, strlen(NEWLINE) );
return Write( CString(NEWLINE) );
}
int RageFile::Read( void *buffer, size_t bytes )
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", mPath.c_str());
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading", GetPath().c_str());
int ret = 0;
int FromBuffer = min( (int) bytes, m_BufUsed );
memcpy( buffer, m_pBuf, FromBuffer );
ret += FromBuffer;
buffer = (char *) buffer + FromBuffer;
m_FilePos += FromBuffer;
bytes -= FromBuffer;
m_BufUsed -= FromBuffer;
m_pBuf += FromBuffer;
buffer = (char *) buffer + FromBuffer;
if( bytes )
{
int FromFile = fread( buffer, 1L, bytes, mFP );
int FromFile = m_File->Read( buffer, bytes );
if( FromFile < 0 )
return -1;
if( FromFile == 0 )
m_EOF = true;
ret += FromFile;
m_FilePos += FromFile;
}
return ret;
}
int RageFile::Write(const void *buffer, size_t bytes)
int RageFile::Write( const void *buffer, size_t bytes )
{
if (!IsOpen())
RageException::Throw("\"%s\" is not open.", mPath.c_str());
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
return fwrite(buffer, 1L, bytes, mFP);
if( m_Mode != WRITE )
RageException::Throw("\"%s\" is not open for writing", GetPath().c_str());
return m_File->Write( buffer, bytes );
}
CString RageFile::GetLine()
int RageFile::Seek( int offset )
{
CString ret;
GetLine( ret );
return ret;
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str());
m_EOF = false;
/* If the new position is within the buffer, just eat the buffered data. */
int FromBuffer = offset - m_FilePos;
if( 0 < FromBuffer && FromBuffer <= m_BufUsed )
{
m_FilePos += FromBuffer;
m_BufUsed -= FromBuffer;
m_pBuf += FromBuffer;
return m_FilePos;
}
/* It's not. Clear the buffer and do a real seek. */
ResetBuf();
int pos = m_File->Seek( offset );
if( pos == -1 )
return -1;
m_FilePos = pos;
return pos;
}
int RageFile::SeekCur( int offset )
{
ASSERT( offset >= 0 );
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str());
if( !offset || m_EOF )
return m_FilePos;
int FromBuffer = min( offset, m_BufUsed );
m_FilePos += FromBuffer;
offset -= FromBuffer;
m_BufUsed -= FromBuffer;
m_pBuf += FromBuffer;
if( offset )
{
int pos = m_File->SeekCur( offset );
if( pos == -1 )
return -1;
m_FilePos = pos;
}
return m_FilePos;
}
int RageFile::GetFileSize()
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading; can't GetFileSize", GetPath().c_str());
return m_File->GetFileSize();
}
void RageFile::Rewind()
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_Mode != READ )
RageException::Throw("\"%s\" is not open for reading; can't GetFileSize", GetPath().c_str());
m_EOF = false;
m_File->Rewind();
}
+51 -36
View File
@@ -7,61 +7,76 @@
Desc: Encapsulates C and C++ file classes to deal with arch-specific oddities.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
Chris Danford
Steve Checkoway
Glenn Maynard
-----------------------------------------------------------------------------
*/
#include <cstdio>
// call FixSlashes on any path that came from the user
void FixSlashesInPlace( CString &sPath );
CString FixSlashes( CString sPath );
void CollapsePath( CString &sPath );
class RageFileObj;
class RageFile
{
friend class RageFileObj;
public:
enum OpenMode { READ, WRITE };
RageFile();
RageFile( const CString& path, OpenMode mode = READ );
~RageFile() { Close(); }
const CString &GetRealPath() const { return m_Path; }
CString GetPath() const;
bool Open( const CString& path, OpenMode mode = READ );
void Close();
bool IsOpen() const { return m_File != NULL; }
bool AtEOF() const { return m_EOF; }
CString GetError() const { return m_Error; }
void ClearError() { m_Error = ""; }
int Tell() const { return m_FilePos; }
int Seek( int offset );
int SeekCur( int offset );
int GetFileSize();
void Rewind();
/* Raw I/O: */
int Write( const void *buffer, size_t bytes );
int Write( const CString& string ) { return Write( string.data(), string.size() ); }
int Read( void *buffer, size_t bytes );
int Read( const CString &buffer, size_t bytes );
/* Line-based I/O: */
CString GetLine();
int GetLine( CString &out );
int PutLine( const CString &str );
protected:
void SetError( const CString &err ) { m_Error = err; } /* called by RageFileObj::SetError */
private:
FILE *mFP;
CString mPath;
void ResetBuf();
RageFileObj *m_File;
CString m_Path;
OpenMode m_Mode;
CString m_Error;
bool m_EOF;
int m_FilePos;
enum { BSIZE = 256 };
char m_Buffer[BSIZE];
char *m_pBuf;
int m_BufUsed;
void ResetBuf();
public:
enum OpenMode { READ, WRITE };
RageFile() : mPath("") { mFP = NULL; }
RageFile( const CString& path, OpenMode mode = READ );
~RageFile() { Close(); }
bool Open( const CString& path, OpenMode mode = READ );
void Close();
bool IsOpen() { return (mFP != NULL); }
bool AtEOF() { return (feof(mFP) != 0); }
int GetError() { return ferror(mFP); }
void ClearError() { clearerr(mFP); }
long Tell() { return ftell(mFP); }
bool Seek(long offset) { return !fseek(mFP, offset, SEEK_SET); }
void Rewind() { rewind(mFP); }
/* Raw I/O: */
// GetLine() strips new lines
bool PutString(const CString& string) { return fputs(string, mFP) >= 0; }
int Read(void *buffer, size_t bytes);
int Write(const void *buffer, size_t bytes);
int PutLine( const CString &str );
/* Line-based I/O: */
CString GetLine();
void GetLine( CString &out );
};
#endif
+65
View File
@@ -0,0 +1,65 @@
#include "global.h"
#include "RageFileDriver.h"
void RageFileObj::SetError( const CString &err )
{
parent.SetError( err );
}
int RageFileObj::Seek( int offset )
{
const int OldPos = parent.Tell();
if( offset < OldPos )
parent.Rewind();
else
offset -= OldPos;
char buf[256];
while( offset )
{
/* Must call parent.Read: */
int got = parent.Read( buf, min( (int) sizeof(buf), offset ) );
if( got == -1 )
return -1;
if( got == 0 )
break;
offset -= got;
}
return parent.Tell();
}
int RageFileObj::SeekCur( int offset )
{
return Seek( parent.Tell() + offset );
}
int RageFileObj::GetFileSize()
{
int OldPos = parent.Tell();
parent.Rewind();
char buf[256];
int ret = 0;
while( 1 )
{
/* Must call parent.Read: */
int got = parent.Read( buf, sizeof(buf) );
if( got == -1 )
{
ret = -1;
break;
}
if( got == 0 )
break;
ret += got;
}
Seek( OldPos );
return ret;
}
/*
* Copyright (c) 2003 by the person(s) listed below. All rights reserved.
* Glenn Maynard
*/
+43
View File
@@ -0,0 +1,43 @@
#ifndef RAGE_FILE_DRIVER_H
#define RAGE_FILE_DRIVER_H
#include "RageFile.h"
#include "RageFileManager.h"
class RageFileObj;
class RageFileDriver
{
public:
virtual RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err ) = 0;
virtual RageFileManager::FileType GetFileType( CString sPath ) = 0;
virtual int GetFileSizeInBytes( CString sFilePath ) = 0;
virtual int GetFileModTime( CString sPath ) = 0;
};
class RageFileObj
{
protected:
RageFile &parent;
void SetError( const CString &err );
public:
RageFileObj( RageFile &p ): parent(p) { }
virtual ~RageFileObj() { }
void ClearError();
// virtual CString RealPath() const { return parent->GetPath(); }
virtual int Seek( int offset );
virtual int SeekCur( int offset );
virtual int GetFileSize();
virtual CString GetDisplayPath() const { return parent.GetRealPath(); }
/* Raw I/O: */
virtual int Read(void *buffer, size_t bytes) = 0;
virtual int Write(const void *buffer, size_t bytes) = 0;
virtual void Rewind() = 0;
};
#endif
+165
View File
@@ -0,0 +1,165 @@
#include "global.h"
#include "RageFileDriverDirect.h"
#include "RageUtil.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(WIN32)
#include <io.h>
#endif
#if !defined(O_BINARY)
#define O_BINARY 0
#endif
/* XXX: Drop FileDB and cache/resolve in here. */
#include "RageUtil_FileDB.h"
/* This driver handles direct file access. */
class RageFileObjDirect: public RageFileObj
{
private:
int fd;
public:
RageFileObjDirect( int fd, RageFile &p );
virtual ~RageFileObjDirect();
virtual int Read(void *buffer, size_t bytes);
virtual int Write(const void *buffer, size_t bytes);
virtual void Rewind();
virtual int Seek( int offset );
virtual int SeekCur( int offset );
virtual int GetFileSize();
};
RageFileDriverDirect::RageFileDriverDirect( CString root_ ):
root(root_)
{
}
RageFileObj *RageFileDriverDirect::Open( CString sPath, RageFile::OpenMode mode, RageFile &p, int &err )
{
ResolvePath( sPath );
int flags = O_BINARY;
if( mode == RageFile::READ )
flags |= O_RDONLY;
else
flags |= O_WRONLY|O_CREAT|O_TRUNC;
int fd = open( root + sPath, flags );
if( fd == -1 )
{
err = errno;
return NULL;
}
return new RageFileObjDirect( fd, p );
}
static bool DoStat(CString sPath, struct stat *st)
{
TrimRight(sPath, "/\\");
return stat(sPath.c_str(), st) != -1;
}
RageFileManager::FileType RageFileDriverDirect::GetFileType( CString sPath )
{
ResolvePath( sPath );
struct stat st;
if( !DoStat(sPath, &st) )
return RageFileManager::TYPE_NONE;
if( st.st_mode & S_IFDIR )
return RageFileManager::TYPE_DIR;
return RageFileManager::TYPE_FILE;
}
int RageFileDriverDirect::GetFileSizeInBytes( CString sPath )
{
struct stat st;
if( !DoStat(sPath, &st) )
return 0;
return st.st_size;
}
int RageFileDriverDirect::GetFileModTime( CString sPath )
{
struct stat st;
if( !DoStat(sPath, &st) )
return -1;
return st.st_mtime;
}
RageFileObjDirect::RageFileObjDirect( int fd_, RageFile &p ):
RageFileObj( p )
{
fd = fd_;
ASSERT( fd != -1 );
}
RageFileObjDirect::~RageFileObjDirect()
{
if( fd != -1 )
close( fd );
}
int RageFileObjDirect::Read( void *buf, size_t bytes )
{
int ret = read( fd, buf, bytes );
if( ret == -1 )
{
SetError( strerror(errno) );
return -1;
}
return ret;
}
int RageFileObjDirect::Write( const void *buf, size_t bytes )
{
int ret = write( fd, buf, bytes );
if( ret == -1 )
{
SetError( strerror(errno) );
return -1;
}
return ret;
}
void RageFileObjDirect::Rewind()
{
lseek( fd, 0, SEEK_SET );
}
int RageFileObjDirect::Seek( int offset )
{
return lseek( fd, offset, SEEK_SET );
}
int RageFileObjDirect::SeekCur( int offset )
{
return lseek( fd, offset, SEEK_CUR );
}
int RageFileObjDirect::GetFileSize()
{
const int OldPos = lseek( fd, 0, SEEK_CUR );
const int ret = lseek( fd, 0, SEEK_END );
lseek( fd, OldPos, SEEK_SET );
return ret;
}
/*
* Copyright (c) 2003 by the person(s) listed below. All rights reserved.
* Glenn Maynard
*/
+21
View File
@@ -0,0 +1,21 @@
#ifndef RAGE_FILE_DRIVER_DIRECT_H
#define RAGE_FILE_DRIVER_DIRECT_H
#include "RageFileDriver.h"
class RageFileDriverDirect: public RageFileDriver
{
public:
RageFileDriverDirect( CString root );
virtual ~RageFileDriverDirect() { }
RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err );
RageFileManager::FileType GetFileType( CString sPath );
int GetFileSizeInBytes( CString sFilePath );
int GetFileModTime( CString sPath );
private:
CString root;
};
#endif
+160
View File
@@ -0,0 +1,160 @@
#include "global.h"
#include "RageFileManager.h"
#include "RageFileDriver.h"
#include <errno.h>
RageFileManager *FILEMAN = NULL;
struct LoadedDriver
{
/* A loaded driver may have a base path, which modifies the path we
* pass to the driver. For example, if the base is "Songs/", and we
* want to send the path "Songs/Foo/Bar" to it, then we actually
* only send "Foo/Bar". The path "Themes/Foo" is out of the scope
* of the driver, and GetPath returns false. */
RageFileDriver *driver;
CString base;
CString GetPath( CString path );
};
static vector<LoadedDriver> g_Drivers;
RageFileManager::RageFileManager()
{
#if defined(XBOX)
RageFileManager::AddFS( "dir", ".", "" );
/* XXX: drop BASE_PATH and do this instead */
// RageFileManager::AddFS( "dir", "D:\\", "" );
#else
/* Paths relative to the CWD: */
RageFileManager::AddFS( "dir", ".", "" );
/* Absolute paths. This is rarely used, eg. by Alsa9Buf::GetSoundCardDebugInfo(). */
RageFileManager::AddFS( "dir", "/", "/" );
#endif
}
RageFileManager::~RageFileManager()
{
/* Note that drivers can use previously-loaded drivers, eg. to load a ZIP
* from the FS. Unload drivers in reverse order. */
for( int i = g_Drivers.size()-1; i >= 0; --i )
delete g_Drivers[i].driver;
}
CString LoadedDriver::GetPath( CString path )
{
if( base.size() == 0 )
return path;
/* Map all slashes to forward slash. */
path.Replace( "\\", "/" );
if( path.Left( base.size() ).CompareNoCase( base ) )
return ""; /* no match */
return path.Right( path.size() - base.size() );
}
#include "RageFileDriverDirect.h"
void RageFileManager::AddFS( CString Type, CString Root, CString Base )
{
if( Base.size() && Base.Right(1) != "/" )
Base += '/';
ASSERT( Root != "" );
if( Root.Right(1) != "/" )
Root += '/';
RageFileDriver *driver = NULL;
if( !Type.CompareNoCase("DIR") )
{
driver = new RageFileDriverDirect( Root );
}
if( !driver )
return;
LoadedDriver ld;
ld.driver = driver;
ld.base = Base;
g_Drivers.push_back( ld );
}
RageFileManager::FileType RageFileManager::GetFileType( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
FileType ret = g_Drivers[i].driver->GetFileType( p );
if( ret != TYPE_NONE )
return ret;
}
return TYPE_NONE;
}
int RageFileManager::GetFileSizeInBytes( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
int ret = g_Drivers[i].driver->GetFileSizeInBytes( p );
if( ret != -1 )
return ret;
}
return -1;
}
int RageFileManager::GetFileModTime( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
int ret = g_Drivers[i].driver->GetFileModTime( p );
if( ret != -1 )
return ret;
}
return -1;
}
/* Used only by RageFile: */
RageFileObj *RageFileManager::Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err )
{
err = ENOENT;
/* XXX: WRITE logic */
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString path = g_Drivers[i].GetPath( sPath );
if( path.size() == 0 )
continue;
int error;
RageFileObj *ret = g_Drivers[i].driver->Open( path, mode, p, error );
if( ret )
return ret;
/* ENOENT (File not found) is low-priority: if some other error
* was reported, return that instead. */
if( error != ENOENT )
err = error;
}
return NULL;
}
bool RageFileManager::IsAFile( const CString &sPath ) { return GetFileType(sPath) == TYPE_FILE; }
bool RageFileManager::IsADirectory( const CString &sPath ) { return GetFileType(sPath) == TYPE_DIR; }
bool RageFileManager::DoesFileExist( const CString &sPath ) { return GetFileType(sPath) != TYPE_NONE; }
+31
View File
@@ -0,0 +1,31 @@
#ifndef RAGE_FILE_MANAGER_H
#define RAGE_FILE_MANAGER_H
#include "RageFile.h"
class RageFileObj;
class RageFileManager
{
public:
RageFileManager();
~RageFileManager();
enum FileType { TYPE_FILE, TYPE_DIR, TYPE_NONE };
FileType GetFileType( const CString &sPath );
bool IsAFile( const CString &sPath );
bool IsADirectory( const CString &sPath );
bool DoesFileExist( const CString &sPath );
int GetFileSizeInBytes( const CString &sPath );
int GetFileModTime( const CString &sPath );
void AddFS( CString Type, CString RealPath, CString Root );
/* Used only by RageFile: */
RageFileObj *Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err );
};
extern RageFileManager *FILEMAN;
#endif
+5 -1
View File
@@ -51,7 +51,7 @@
#include "BannerCache.h"
#include "UnlockSystem.h"
#include "arch/ArchHooks/ArchHooks.h"
#include "RageFile.h"
#include "RageFileManager.h"
#include "Bookkeeper.h"
#include "LightsManager.h"
@@ -785,6 +785,9 @@ int main(int argc, char* argv[])
/* Whew--we should be able to crash safely now! */
/* Everything except LOG uses this to read and write files. Load this early. */
FILEMAN = new RageFileManager;
atexit(SDL_Quit); /* Clean up on exit */
/* Fire up the SDL, but don't actually start any subsystems.
@@ -957,6 +960,7 @@ int main(int argc, char* argv[])
SAFE_DELETE( FONT );
SAFE_DELETE( TEXTUREMAN );
SAFE_DELETE( DISPLAY );
SAFE_DELETE( FILEMAN );
SAFE_DELETE( LOG );
if( g_sErrorString != "" )