/* -------------------------------------------------------------------- */
/*	FILEBUF.CPP 					Citadel 							*/
/*				Buffered file handling routines for ctdl				*/
/* -------------------------------------------------------------------- */
#include "ctdl.h"
#pragma hdrstop

void bufferedFlush(BFILE *file, Bool DumpBuffer)
	{
	if (file->buffer.dirty && file->buffer.inuse)
		{
		assert(file->buffer.buffer);
#ifdef WINCIT
		_llseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
		_lwrite(file->fhandle, (char *) file->buffer.buffer, file->buffer.buflen);
#else
		lseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
		_write(file->fhandle, file->buffer.buffer, file->buffer.buflen);
#endif
		file->buffer.dirty = FALSE;
		}

	if (DumpBuffer)
		{
		delete [] file->buffer.buffer;
		file->buffer.buffer = NULL;
		file->buffer.inuse = FALSE;
		file->buffer.dirty = FALSE;
		}
	}

/* seek an offset in a buffered file */
void bufferedSeek(BFILE *file, long where)
	{
	if (file)
		{
		file->fpointer = where;
		file->eof = FALSE;
		if (file->buffer.inuse &&
				(where >= file->buffer.bufstart) &&
				(where < file->buffer.bufstart + file->buffer.buflen))
			{
			file->level = (uint) (where - file->buffer.bufstart);
			}
		else
			{
			file->level = UINT_MAX;
			}
		}
	}

/* find the offset in a bufferd file */
long bufferedTell(BFILE *file)
	{
	if (file)
		{
		return (file->fpointer);
		}
	else
		{
		return (CERROR);
		}
	}

/* get a byte from the current offset of a buffered file - inc pointer */
/* return EOF on error or end of file */
int bufferedGetc(BFILE *file)
	{
	int i;

	if (file)
		{
		if (file->buffer.inuse && file->level < file->buffer.buflen)
			{
			i = file->buffer.buffer[file->level++];
			file->fpointer++;
			return (i);
			}
		else
			{
			bufferedFlush(file);

			if (!file->buffer.buffer)
				{
				compactMemory();
				if ((file->buffer.buffer = new uchar[cfg.filebufsize]) == NULL)
					{
					crashout(getmsg(787));
					}
				}

			file->buffer.bufstart = file->fpointer;

#ifdef WINCIT
			_llseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
			file->buffer.buflen = _lread(file->fhandle, (char *) file->buffer.buffer, cfg.filebufsize);
#else
			lseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
			file->buffer.buflen = _read(file->fhandle, file->buffer.buffer, cfg.filebufsize);
#endif

			file->buffer.inuse = TRUE;
			file->buffer.dirty = FALSE;

			if (file->buffer.buflen > 0)
				{
				i = file->buffer.buffer[0];
				file->level = 1;
				file->fpointer++;
				return (i);
				}
			else
				{
				file->level = UINT_MAX;
				file->eof = TRUE;
				return (EOF);
				}
			}
		}
	else
		{
		return (EOF);
		}
	}

/* return TRUE if last read was EOF */
int bufferedEof(BFILE *file)
	{
	if (file)
		{
		return (file->eof);
		}
	else
		{
		return (TRUE);
		}
	}

/* clear all errors associated with a buffered file */
void bufferedClearerr(BFILE *file)
	{
	if (file)
		{
		file->eof = FALSE;
		}
	}

/* open an existing file - crashout if it is not there */
BFILE *bufferedOpenExist(const char *filename)
	{
	if (debug)
		{
		doccr();
		cPrintf(getdbmsg(58), filename);
		doccr();
		}

	BFILE *newFile;

	compactMemory();

	if ((newFile = new BFILE) == NULL)
		{
		crashout(getmsg(788), filename);
		}

	memset(newFile, 0, sizeof(*newFile));

#ifdef WINCIT
	if ((newFile->fhandle = OpenFile(filename, &newFile->of, OF_READWRITE)) < 0)
#else
	if ((newFile->fhandle = _open(filename, O_RDWR)) < 0)
#endif
		{
		crashout(getmsg(789), filename, errno);
		}

	return (newFile);
	}

/* open a file - return NULL if it is not there */
BFILE *bufferedOpen(const char *filename)
	{
	if (debug)
		{
		doccr();
		cPrintf(getdbmsg(59), filename);
		}

	BFILE *newFile;

	compactMemory();

	if ((newFile = new BFILE) == NULL)
		{
		crashout(getmsg(788), filename);
		}

	memset(newFile, 0, sizeof(*newFile));

#ifdef WINCIT
	if ((newFile->fhandle = OpenFile(filename, &newFile->of, OF_READWRITE)) < 0)
#else
	if ((newFile->fhandle = _open(filename, O_RDWR)) < 0)
#endif
		{
		delete newFile;
		newFile = NULL;
		}

	if (debug)
		{
		cPrintf(newFile ? getdbmsg(13) : getdbmsg(14));
		doccr();
		}

	return (newFile);
	}

/* create a file - return NULL if we cannot */
BFILE *bufferedCreate(const char *filename)
	{
	if (debug)
		{
		doccr();
		cPrintf(getdbmsg(60), filename);
		}

	BFILE *newFile;

	compactMemory();

	if ((newFile = new BFILE) == NULL)
		{
		crashout(getmsg(788), filename);
		}

	memset(newFile, 0, sizeof(*newFile));

#ifdef WINCIT
	if ((newFile->fhandle = OpenFile(filename, &newFile->of,
			OF_CREATE | OF_READWRITE | OF_SHARE_EXCLUSIVE)) < 0)
#else
	if ((newFile->fhandle = open(filename, O_CREAT | O_RDWR | O_TRUNC,
			S_IREAD | S_IWRITE)) < 0)
#endif
		{
		delete newFile;
		newFile = NULL;
		}

	if (debug)
		{
		cPrintf(newFile ? getdbmsg(13) : getdbmsg(14));
		doccr();
		}

	return (newFile);
	}

/* close a file */
void bufferedClose(BFILE *file)
	{
	if (file)
		{
		bufferedFlush(file, TRUE);
#ifdef WINCIT
		_lclose(file->fhandle);
#else
		_close(file->fhandle);
#endif

		delete file;
		}
	}

int bufferedPutc(int c, BFILE *file)
	{
	if (file)
		{
		if (file->buffer.inuse && file->level < file->buffer.buflen)
			{
			file->buffer.buffer[file->level++] = (char) c;
			file->fpointer++;
			file->buffer.dirty = TRUE;
			}
		else
			{
			bufferedFlush(file);

			if (!file->buffer.buffer)
				{
				compactMemory();
				if ((file->buffer.buffer = new uchar[cfg.filebufsize]) == NULL)
					{
					crashout(getmsg(787));
					winRet (FALSE);
					}
				}

			file->buffer.bufstart = file->fpointer;

#ifdef WINCIT
			_llseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
			file->buffer.buflen = _lread(file->fhandle, (char *) file->buffer.buffer, cfg.filebufsize);
#else
			lseek(file->fhandle, file->buffer.bufstart, SEEK_SET);
			file->buffer.buflen = _read(file->fhandle, file->buffer.buffer, cfg.filebufsize);
#endif

			file->buffer.inuse = TRUE;

			if (file->buffer.buflen > 0)
				{
				file->buffer.dirty = TRUE;
				file->buffer.buffer[0] = (char) c;
				file->level = 1;
				file->fpointer++;
				}
			else
				{
				file->buffer.dirty = FALSE;
				file->level = UINT_MAX;
				return (FALSE);
				}
			}
		return (TRUE);
		}
	return (FALSE);
	}


/* remove the file's buffer */
static void unbuffer(BFILE *file)
	{
	if (file)
		{
		bufferedFlush(file, TRUE);
		}
	}

/* right now this disables buffering. this should be fixed some day. */
size_t bufferedWrite(void *buf, size_t len, BFILE *file)
	{
	if (file)
		{
		unbuffer(file);
#ifdef WINCIT
		return (_lwrite(file->fhandle, buf, len));
#else
		return (_write(file->fhandle, buf, len));
#endif
		}
	else
		{
		return (0);
		}
	}

#ifdef WINCIT
extern void bufferedWinCloseTmp(BFILE *file)
	{
	if (file)
		{
		file->DOSfpointer = _llseek(file->fhandle, 0, SEEK_CUR);
		_lclose(file->fhandle);

		file->fhandle = 0;
		}
	}

extern void bufferedWinReOpen(BFILE *file)
	{
	if (file)
		{
		file->fhandle = OpenFile("poo", &file->of, OF_READWRITE | OF_REOPEN);
		_llseek(file->fhandle, file->DOSfpointer, SEEK_SET);
		}
	}
#endif
