 // ----------------------------------------------------------------------------------
 // Uio.h	
 // Uio.cp -- file i/o class
 // ----------------------------------------------------------------------------------
 
 #include "Uio.h"
 #include "TSpell.h"
 #include "UError.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
 
 //#define TEST
 
 #ifdef TEST
 #include <stdio.h>
 #endif
 
 Uio::Uio()
 {
 #ifdef _MACINTOSH_ 	

 	mMacFile.vRefNum = 0;
	mMacFile.parID = 0;		
	mMacFile.name[0] = 0;
	mRefNum = -1;
	
#else
	theFile = NULL;
#endif
 } // Uio
 
 Uio::Uio(FioParam *fileSpec)
 {
 #ifdef _MACINTOSH_ 	
	memcpy(&mMacFile,fileSpec,sizeof(FioParam));
 	mRefNum = -1;
#else
 	strcpy(theName,fileSpec);
#endif
  } // Uio
 
 #ifdef _MACINTOSH_ 	
 Uio::Uio(AliasHandle theAlias, Boolean wasChanged, FSSpec *fileSpec)
 {
	OSErr	err = ::ResolveAlias(fileSpec, theAlias, &mMacFile,
								&wasChanged);
	if (err)
		ErrorFunc(eOpening_File, SET);
	mRefNum = -1;
 } // Uio
    
#endif

 Uio::~Uio()
 {
 #ifdef _MACINTOSH_ 	
	if (mRefNum != -1)
	{	OSErr err = ::FSClose(mRefNum);
		mRefNum = -1;
		
		::FlushVol(nil, mMacFile.vRefNum);
		if (err)
			ErrorFunc(eWriting_File, SET);
	}
#else
	if (theFile != NULL)
		fclose(theFile);
#endif

 } // Uio
 
void  Uio::GetSpecifier(FioParam *fileSpec)
{
#ifdef _MACINTOSH_ 	

	*fileSpec = mMacFile;
	
#else
	fileSpec = theName;
#endif

}

void Uio::SetSpecifier(FioParam	*fileSpec)
{
#ifdef _MACINTOSH_ 	
	if (mRefNum != -1)
	{	OSErr err = ::FSClose(mRefNum);
		mRefNum = -1;
		
		::FlushVol(nil, mMacFile.vRefNum);
		if (err)
			ErrorFunc(eWriting_File, SET);
	}
	mMacFile = *fileSpec;
#else
	if (theFile != NULL)
		fclose(theFile);
	strcpy(theName,fileSpec);
#endif

}

#ifdef _MACINTOSH_ 

AliasHandle Uio::MakeAlias(FioParam *fileSpec)
{
	AliasHandle	theAlias;
	OSErr	err = ::NewAlias(fileSpec, &mMacFile, &theAlias);
	if (err)
	{	ErrorFunc(eWriting_File, SET);
		return NULL;
	}
	return theAlias;
}

#endif


#ifdef _MACINTOSH_ 
short Uio::GetRefNum()
{

	return mRefNum;
}

#else
FILE *Uio::GetRefNum() // bwh
{
	return theFile;
}

#endif

#ifdef _MACINTOSH_ 
void Uio::Create(OSType inCreator, OSType inFileType, ScriptCode	inScriptCode)
#else
void Uio::Create()
#endif
{
#ifdef _MACINTOSH_ 
	OSErr	err = ::FSpCreate(&mMacFile, inCreator, inFileType, inScriptCode);
	if ( (err == 0) || (err == -48))
	{	Open();
		return;
	}
	ErrorFunc(eWriting_File, SET);
#else
// TO DO
	theFile = fopen(theName,"w+b"); // bwh
	
	if (theFile == NULL)
		ErrorFunc(eWriting_File, SET); // bwh
#endif
}

 #ifdef _MACINTOSH_
short Uio::Open(char Permission)
#else
short Uio::Open()
#endif
{
#ifdef _MACINTOSH_

	OSErr	err = ::FSpOpenDF(&mMacFile, Permission, &mRefNum);
	if (err)
	{
		Create();
		ErrorFunc(eOpening_File, SET);
		return 0;
	}
	return mRefNum;

#else
	theFile = fopen(theName,"ab+"); // bwh
	if (theFile == NULL)
	{	ErrorFunc(eOpening_File, SET);
		return 0;
	}
	return 1; // bwh
#endif
}

void Uio::Close()
{
 #ifdef _MACINTOSH_ 	
	if (mRefNum != -1)
	{	OSErr err = ::FSClose(mRefNum);
		mRefNum = -1;
		
		::FlushVol(nil, mMacFile.vRefNum);
		if (err)
			ErrorFunc(eWriting_File, SET);
	}
#else
	fclose(theFile);
#endif
}

short Uio::eof()
{
 #ifdef _MACINTOSH_ 	
	if (GetLength() > GetPos())
		return FALSE;
	else
		return TRUE;
#else
	return feof(theFile);
#endif
}

// ----------------------------------------------------------------------------------
// USE SEEK_CUR, SEEK_END, SEEK_SET

void Uio::SetPos(long offset, short where)
{
 #ifdef _MACINTOSH_

	// metrowerks dependent!
	//#define SEEK_SET	0
	//#define SEEK_CUR	1
	//#define SEEK_END	2

	short theWhere[4] = { fsFromStart, fsFromMark, fsFromLEOF, fsAtMark };

	OSErr err = ::SetFPos(mRefNum, theWhere[where], offset);
	if (err)
		ErrorFunc(eReading_File, SET);
#else
	if (fseek(theFile, offset, where) != 0)
		ErrorFunc(eReading_File, SET);
#endif
}

long Uio::GetPos()
{
 #ifdef _MACINTOSH_
	long	thePos;
	OSErr err = ::GetFPos(mRefNum, &thePos);
	if (err)
		ErrorFunc(eReading_File, SET);
	
	return thePos;
#else
	return ftell(theFile);
#endif
}

#ifdef _MACINTOSH_

void Uio::SetLength(long theLength)
{
	OSErr err = ::SetEOF(mRefNum, theLength);
	if (err)
		ErrorFunc(eWriting_File, SET);
}

#endif

long Uio::GetLength()
{	
 #ifdef _MACINTOSH_ 	
	long theLength;
	OSErr err = ::GetEOF(mRefNum, &theLength);
	if (err)
	{	ErrorFunc(eReading_File, SET);
		return 0;
	}
	return(theLength);
#else
	SetPos(0L, SEEK_END);
	return GetPos();
#endif
}

#ifdef _MACINTOSH_ 	

void *Uio::ReadFile()
{
	void	*data = nil;
	
	long	fileLength;
	OSErr err = ::GetEOF(mRefNum, &fileLength);
	if (err)
	{	ErrorFunc(eReading_File, SET);
		return NULL;
	}

	data = (void *)::malloc(fileLength);
	err = ::SetFPos(mRefNum, fsFromStart, 0);
	err = ::FSRead(mRefNum, &fileLength, data);
	if (err)
		ErrorFunc(eReading_File, SET);
	
	return data;
}

long Uio::WriteFile(const void *buf, long count)
{
	long	written = count;
	
	OSErr err = ::SetFPos(mRefNum, fsFromStart, 0);
	if (err)
	{	ErrorFunc(eReading_File, SET);
		return 0;
	}

	err = ::FSWrite(mRefNum, &written, buf);
	::SetEOF(mRefNum, written);
	if (err)
	{	ErrorFunc(eWriting_File, SET);
		return 0;
	}
	
	::FlushVol(nil, mMacFile.vRefNum);
	if (err)
		ErrorFunc(eWriting_File, SET);

	
	return written;
}
#endif


long Uio::ReadData(void *buf, size_t count)
{
#ifdef _MACINTOSH_ 	

	long read = count;
	OSErr err = ::FSRead(mRefNum, &read, buf);
	if (err != 0)
	{	if (err == -39)
			return read; // reached eof
		if (err == -58)
			return read; // strange file system
		ErrorFunc(eReading_File, SET);
		return 0;
	}
	return read;

#else
	// Dependency so that it can't read more than 32K
	short read = fread(buf, 1, count, theFile);
	if (read == 0)
		ErrorFunc(eReading_File, SET);
	return read;
	
#endif

}

long Uio::WriteData(const void *buf, long count)
{
 #ifdef _MACINTOSH_ 	
	long written = count;
	OSErr err = ::FSWrite(mRefNum, &written, buf);
	if (err)
	{	ErrorFunc(eWriting_File, SET);
		return 0;
	}
	
	return written;
#else
	// Dependency so that it can't read more than 32K
	size_t written = fwrite(buf, 1, count, theFile);
	if (written == 0)
		ErrorFunc(eWriting_File, SET);
	return written;
#endif

}

long Uio :: Exist()
{
#ifdef _MACINTOSH_
	OSErr	err = ::FSpOpenDF(&mMacFile, fsCurPerm, &mRefNum);
	if (err)
	{	return FALSE;
	} else 
	{
		if (mRefNum != -1)
		{	OSErr err = ::FSClose(mRefNum);
			mRefNum = -1;
			
			::FlushVol(nil, mMacFile.vRefNum);
			if (err)
				ErrorFunc(eWriting_File, SET);
		} else
		{
			return FALSE;
		}
		
		return TRUE;

	}
	return FALSE;

#endif
#ifndef _MACINTOSH_ // Stdio version
	if(theFile != NULL) return TRUE;

	theFile = fopen(theName,"rb+");
	if(theFile != NULL) {
	 fclose(theFile);
	 return TRUE;
   }
	return FALSE;
#endif
}

#ifdef _MACINTOSHOS9_ 	

short Uio::GetFile(short numTypes, SFTypeList types)
{
	#pragma unused(numTypes, types)
	
	StandardFileReply	reply;

	return(FALSE);
	//StandardGetFile(nil, numTypes, types, &reply);
	if (reply.sfGood)
	{	
		SetSpecifier(&reply.sfFile);
		return TRUE;
	} else
		return FALSE;
}

short Uio::PutFile(ConstStr255Param prompt, ConstStr255Param defaultName)
{
	#pragma unused(prompt, defaultName)
	
	StandardFileReply	reply;
	
	return(FALSE);
	//StandardPutFile(prompt, defaultName, &reply);
	if (reply.sfGood)
	{	
		SetSpecifier(&reply.sfFile);
		return TRUE;
	} else
		return FALSE;
}

#endif

char * Uio::getstring(char *theString, long size)
{
	long	OldPos = GetPos();

	long textRead = ReadData( theString, size );
	if ( ErrorFunc(0, GET) < eNo_Err )
	{	return NULL;
	}
	
	if (textRead == 0)
		return NULL;
	
	short counter = 0;
	
	while ( (*(theString + counter) != '\n') && (*(theString + counter) != '\r') && (*(theString + counter) != '\0')
			&& (counter < size ) )
		counter++; 
	
	// check for lf/nl pair
	if ( counter < (size-1))
		if (( *(theString + counter +1) == '\n') || (*(theString + counter +1) == '\r' ))
			SetPos(OldPos + counter + 2, SEEK_SET); 	// advance cursor
	else
		SetPos(OldPos + counter + 1, SEEK_SET); // advance cursor
		
	*(theString + counter) = '\0';	
	
	return theString;
}

short Uio::putstring(char *theString)
{
	size_t size = strlen(theString);
	long amount = WriteData((void *)theString, size);
	return (amount == size);
}

char *Uio::GetWord()
{
	long	OldPos = GetPos();
	short CharCounter;

	char *theString = (char *)::malloc(255); // 1 for ending null
	if (theString == NULL) {
		ErrorFunc( eNo_Mem, SET);
		return NULL;
	}
	// Read in the word one character at a time
	for(CharCounter = 0; CharCounter <= 254; CharCounter++) {
		ReadData( &theString[CharCounter], 1);
		theString[CharCounter+1] = 0; // Null terminate the string...
		if(theString[CharCounter] == '\n' || theString[CharCounter] == '\r')
			break;
	}

	if ( ErrorFunc(0, GET) < eNo_Err )	{
		return NULL;
	}

	short counter = 0;

	// figure out what the length of the word is
	while ( !iscntrl(*(theString + counter)) && (counter < 255 ) )
		counter++;

	// check for lf/nl pair & reposition cursor
	if ( counter < 254)
	{	if (( *(theString + counter +1) == '\n') || (*(theString + counter +1) == '\r' ))
			SetPos(OldPos + counter + 2, SEEK_SET); 	// advance cursor
		else
			SetPos(OldPos + counter +1, SEEK_SET); // advance cursor

		if ( ErrorFunc(0, GET) < eNo_Err )
		{	// at end of file
			SetPos(0, SEEK_END);
			ErrorFunc(0, SET);	// clear the error
		}
	}

	*(theString + counter) = '\0';	// skip cntl char

	//OldPos = GetPos();

	theString = (char *)::realloc(theString, counter+1);	// resize string
	return theString;

}

void Uio::PutWord(char *Word)
{
	WriteData(Word, strlen(Word));
	WriteData("\n",1);

 #ifdef _MACINTOSH_

	::FlushVol(nil, mMacFile.vRefNum);
#else
	fflush(theFile); // bwh
#endif
}

#ifdef TEST

main()
{	Uio	File;
	
	
	File.GetFile(1, types);
	File.Open();
	long	length = File.GetLength();
	
	char *Word;
	
	while (File.GetPos() < length)
	{	File.getstring(Word, 255);
		printf("String: %s\n");
	}

}

#endif
