#include<stdlib.h>
#include<sys/bios.h>
#include<fcntl.h>
#include"ks.h"

#pragma noregalo


static int write_bytes( KSFile *fp, unsigned char *buf, int len )
{
	if( fp->location + len > fp->filesize )
		return -1;
	fp->location += len;
	while( len-- ){
		if( fp->size == KS_FILE_BUFSIZE ){
			write(fp->fd,fp->buf,KS_FILE_BUFSIZE);
			fp->pos = fp->buf;
			fp->size = 0;
		}
		*fp->pos++ = *buf++;
		fp->size++;
	}
	return 0;
}


static int read_byte( KSFile *fp )
{
	if( fp->location >= fp->filesize )
		return -1;

	if( fp->size == 0 ){
		fp->size = read(fp->fd,fp->buf,KS_FILE_BUFSIZE);
		if( fp->size < 0 ){
			fp->buf[0] = KEYCODE_FILEEND;
			fp->size = 1;
		}else if( fp->size < KS_FILE_BUFSIZE ){
			fp->buf[fp->size++] = KEYCODE_FILEEND;
			fp->eof = 1;
		}
		fp->pos = fp->buf;
	}
	if( *fp->pos == KEYCODE_FILEEND ){
		return -1;
	}

	fp->size--;
	fp->location++;
	return *fp->pos++;
}


KSFile *KSFileOpen( unsigned char far *path, int mode )
{
	KSFile *fp;
	struct stat statbuf;

	if( stat(path,&statbuf) != E_FS_SUCCESS )
		return NULL;

	fp = KSAllocate(sizeof(KSFile));
	if( fp == NULL )
		return NULL;

	if( (mode & 1) == KS_FILE_READ )
		fp->fd = open(path,FMODE_R,0);
	else
		fp->fd = open(path,FMODE_W,0);

	if( fp->fd < 0 ){
		KSFree(fp);
		return NULL;
	}

	fp->mode = mode;
	fp->perm = statbuf.mode;
	fp->filesize = (long)statbuf.count * 128;
	fp->location = 0;
	fp->pos = fp->buf;
	fp->size = 0;
	fp->eof = 0;

	return fp;
}



void KSFileClose( KSFile *fp )
{
	static unsigned char fend[1] = { KEYCODE_FILEEND };

	if( fp == NULL )
		return;

	if( (fp->mode & 1) == KS_FILE_WRITE ){
		write_bytes(fp,fend,1);
		if( fp->size > 0 )
			write(fp->fd,fp->buf,fp->size);
	}
	close(fp->fd);

	KSFree(fp);
}


unsigned KSFileWrite( KSFile *fp, unsigned far *buf, unsigned len )
{
	unsigned code;
	int crlf;
	long count;
	static unsigned char wrbuf[2];
	int wrlen;

	if( fp == NULL || (fp->mode & 1) != KS_FILE_WRITE )
		return 0;

	crlf = fp->mode & KS_FILE_CRLF;
	count = 0;

	while( len-- ){
		code = *buf++;
		if( code & 0x8000 ){
			wrbuf[0] = code >> 8;
			wrbuf[1] = code & 0xff;
			wrlen = 2;
		}else{
			code &= 0xff;
			if( crlf && code == KEYCODE_RETURN ){
				wrbuf[0] = 0x0d;
				wrbuf[1] = 0x0a;
				wrlen = 2;
			}else{
				wrbuf[0] = code;
				wrlen = 1;
			}
		}
		if( write_bytes(fp,wrbuf,wrlen) < 0 )
			break;
		count++;
	}
	return count;
}


unsigned KSFileRead( KSFile *fp, unsigned far *buf, unsigned len )
{
	int i;
	unsigned tmp;
	long count;

	count = 0;
	while( len-- ){
		i = read_byte(fp);
		if( i < 0 )
			break;
		if( i == 0x0d ){
			i = read_byte(fp);	/* void CR */
			if( i < 0 )
				break;
		}
		if( i & 0x80 ){
			tmp = i;
			i = read_byte(fp);
			if( i < 0 )
				break;
			*buf++ = tmp << 8 | i;
		}else{
			*buf++ = i;
		}
		count++;
	}

	return count;
}


int KSFileEOF( KSFile *fp )
{
	return fp->eof;
}
