/*	TFile.cpp
 *
 *		The encapsulation of all my I/O routines
 */

/*  XT - An example text editor application built with the YAAF library
 *
 *	PUBLIC DOMAIN: The source kit of 'xt' has been placed into the
 *	public domain by the author, William Edward Woody, on the hope
 *	that the source kit will provide a useful example of using the
 *	YAAF Library.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XConfig.h>
#include "TFile.h"

#if OPT_XWIN
#include <fcntl.h>
#endif

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

/*	TFile::TFile
 *
 *		Specify a single file
 */

TFile::TFile(long refNum)
{
	fRefNum = refNum;
}

#if OPT_MACOS

TFile::TFile(FSSpec *file)
{
	short refNum;
	OSErr err;
	
	fRefNum = -1;
	err = ::FSpOpenDF(file,fsRdWrPerm,&refNum);
	if (err) {
		if (err == fnfErr) {
			err = ::FSpCreate(file,'XTED','TEXT',0);
			if (err) return;
			
			err = ::FSpOpenDF(file,fsRdWrPerm,&refNum);
			if (err) return;
		} else return;
	}
	
	fRefNum = refNum;
}

#endif

#if OPT_WINOS

TFile::TFile(char *name)
{
	fRefNum = (long)::CreateFile(name,
								 GENERIC_READ | GENERIC_WRITE,
								 0,				// no shared file access
								 NULL,			// no security
								 OPEN_ALWAYS,	// always open, create if not there
								 FILE_ATTRIBUTE_NORMAL |
								 	FILE_FLAG_WRITE_THROUGH |
								 	FILE_FLAG_SEQUENTIAL_SCAN,
								 NULL);
}

#endif

#if OPT_XWIN

TFile::TFile(char *name)
{
	fRefNum = (long)::open(name,O_RDWR | O_CREAT,0666);	// default read/write perm
}

#endif

/*	TFile::~TFile
 *
 *		Close the file
 */

TFile::~TFile()
{
#if OPT_MACOS
	if (fRefNum != -1) FSClose((short)fRefNum);
#endif

#if OPT_WINOS
	if (INVALID_HANDLE_VALUE != (HANDLE)fRefNum) {
		CloseHandle((HANDLE)fRefNum);
	}
#endif

#if OPT_XWIN
	if (fRefNum != -1) ::close((int)fRefNum);
#endif
}

/************************************************************************/
/*																		*/
/*	File I/O															*/
/*																		*/
/************************************************************************/

/*	TFile::IsOpenFile
 *
 *		Used to verify if the file is actually valid
 */

bool TFile::IsOpenFile()
{
#if OPT_MACOS
	return (fRefNum != -1);
#endif

#if OPT_WINOS
	return (INVALID_HANDLE_VALUE != (HANDLE)fRefNum);
#endif

#if OPT_XWIN
	return (fRefNum != -1);
#endif
}

/*	TFile::GetFilePos
 *
 *		Get the current position in the file
 */

long TFile::GetFilePos()
{
#if OPT_MACOS
	long pos;
	::GetFPos((short)fRefNum,&pos);
	return pos;
#endif

#if OPT_WINOS
	DWORD pos;
	
	pos = ::SetFilePointer((HANDLE)fRefNum,
						   0,
						   NULL,
						   FILE_CURRENT);
	return (long)pos;
#endif

#if OPT_XWIN
	return ::lseek((int)fRefNum,0L,SEEK_CUR);
#endif
}

/*	TFile::SetFilePos
 *
 *		Set the file position
 */

void TFile::SetFilePos(long pos)
{
#if OPT_MACOS
	::SetFPos((short)fRefNum,fsFromStart,pos);
#endif

#if OPT_WINOS
	::SetFilePointer((HANDLE)fRefNum,
					 pos,
					 NULL,
					 FILE_BEGIN);
#endif

#if OPT_XWIN
	::lseek((int)fRefNum,pos,SEEK_SET);
#endif
}

/*	TFile::GetEOF
 *
 *		Get the end of file of this file
 */

long TFile::GetEOF()
{
#if OPT_MACOS
	long pos;
	
	::GetEOF((short)fRefNum,&pos);
	return pos;
#endif

#if OPT_WINOS
	return (long)::GetFileSize((HANDLE)fRefNum,NULL);
#endif

#if OPT_XWIN
	long pos;
	long opos;
	
	opos = GetFilePos();
	pos = ::lseek((int)fRefNum,0L,SEEK_END);
	SetFilePos(opos);
	return pos;
#endif
}

/*	TFile::SetEOF
 *
 *		Set the end of file for this file
 */

void TFile::SetEOF(long eof)
{
#if OPT_MACOS
	::SetEOF((short)fRefNum,eof);
#endif

#if OPT_WINOS
	long pos;
	
	pos = GetFilePos();
	if (pos > eof) SetFilePos(eof);
	::SetEndOfFile((HANDLE)fRefNum);
#endif

#if OPT_XWIN
	long pos;
	
	pos = GetFilePos();
	if (pos > eof) SetFilePos(eof);
	::ftruncate((int)fRefNum,eof);
#endif
}

/*	TFile::Read
 *
 *		Read data from this file
 */

long TFile::Read(long len, void *data)
{
#if OPT_MACOS
	OSErr err;
	
	err = ::FSRead((short)fRefNum,&len,(Ptr)data);
	if (err) {
		/* Mac EOFErr is a special case... */
		if (err == eofErr) return len;
		return -1;
	}
	return len;
#endif

#if OPT_WINOS
	DWORD rlen;
	
	if (!ReadFile((HANDLE)fRefNum,
				  data,
				  (DWORD)len,
				  &rlen,
				  NULL))
		return -1;
	
	return (long)rlen;
#endif

#if OPT_XWIN
	return ::read((int)fRefNum,data,len);
#endif
}

/*	TFile::Write
 *
 *		Write data to the file
 */

long TFile::Write(long len, const void *data)
{
#if OPT_MACOS
	OSErr err;
	
	err = ::FSWrite((short)fRefNum,&len,(Ptr)data);
	if (err) return -1;
	return len;
#endif

#if OPT_WINOS
	DWORD rlen;
	
	if (!WriteFile((HANDLE)fRefNum,
				   data,
				   (DWORD)len,
				   &rlen,
				   NULL))
		return -1;

	return (long)rlen;
#endif

#if OPT_XWIN
	return ::write((int)fRefNum,data,len);
#endif
}
