/* Copyright (C) 1981,1982 by Manx Software Systems */
/* Copyright (C) 1981  Thomas Fenwick */
#include "libc.h"
#define maxfile 5

static FILE Cbuffs[maxfile];
int errno;

fopen(name,mode)
char *name,*mode;
{
	register FILE *i;
	register int k;
	char *alloc();

	i = Cbuffs;
	while ( i->_flags ) {
		if ( ++i >= Cbuffs+maxfile )
			return (NULL);
	}

	k = mode[1] == '+';
	switch ( *mode ) {
	case 'r':
		if ( (i->_unit = open(name, k?2:0)) == -1 )
			return (NULL);
		i->_flags = k ? _WRITE|_READ|_FILE : _READ|_FILE;
		i->_curpos = 0;
		break;

	case 'w':
		if ( (i->_unit = open(name,1)) == -1 )
			return (NULL);
		i->_flags = k ? _ATEND|_WRITE|_READ|_FILE : _ATEND|_WRITE|_FILE;
		i->_curpos = 0;
		break;
	
	case 'a':
		if ( (i->_unit = open(name,2)) == -1
				&& (i->_unit = open(name,1)) == -1 )
			return (NULL);
		i->_flags = k ? _WRITE|_READ|_FILE : _WRITE|_FILE;
		i->_curpos = fsize(i->_unit);
		break;

	default:
		return NULL;
	}

	if ( i->_buff == 0 )
		if ( (i->_buff = alloc(_BUFSIZ)) == 0 ) {
			fclose(i);
			return NULL;
		}
	i->_bend =  /* nothing in buffer */
	i->_bp = i->_buff;
	return (i);
}

fclose(ptr)
register FILE *ptr;
{
	if ( ptr->_flags ) {
		if ( ptr->_flags&_DIRTY )	/* if modifed flush buffer */
			flush_(ptr,0);
		close(ptr->_unit);
	}
	ptr->_flags = 0;
	return;
}

closall_()		/* called by exit to close any open files */
{
	register FILE *fp;

	for ( fp = Cbuffs ; fp < Cbuffs+maxfile ; )
		fclose(fp++);
}

getc(ptr)
register FILE *ptr;
{
	register int len;

	if ( ptr->_bp >= ptr->_bend ) {
		if ((ptr->_flags&_ATEND) 
				|| (len = read(ptr->_unit,ptr->_buff,_BUFSIZ)) <= 0)
			return EOF;
		ptr->_curpos += (ptr->_bend - ptr->_buff + _SCTMASK) >> _SCTSHFT;
		ptr->_bp = ptr->_buff;
		ptr->_bend = ptr->_buff + len;
		ptr->_flags &= ~_DIRTY;
	}
	return *ptr->_bp++ & 255;
}

getw(stream)
FILE *stream;
{
	register int x1,x2;

	if ( (x1 = getc(stream)) == EOF || (x2 = getc(stream)) == EOF )
		return EOF;
	return (x2<<8) | x1;
}

fread(buffer,size,number,stream)
register char *buffer; unsigned size; int number;
FILE *stream;
{
	int total;
	register int c,i;

	for ( total = 0 ; total < number ; ++total ) {
		for ( i = size ; i ; --i ) {
			if ( (c = getc(stream)) == EOF )
				return total;
			*buffer++ = c;
		}
	}
	return total;
}

putc(c,ptr)
int c; register FILE *ptr;
{
	if ( ptr->_bp >= ptr->_bend ) {
		if ( flush_(ptr,1) )
			return EOF;
	}
	*ptr->_bp++ = c;
	ptr->_flags |= _DIRTY;
	return (c&255);
}

putw(w,stream)
register unsigned w;
FILE *stream;
{
	if ( putc(w&0x0ff,stream) < 0 ) 
		return EOF;
	else if ( putc((w>>8)&0x0ff,stream) < 0 )
		return EOF;
	return w;
}

fwrite(buffer,size,number,stream)
register char *buffer; unsigned size,number;
FILE *stream;
{
	register unsigned i,max;

	max = size * number;
	for ( i = 0 ; i < max ; ++i ) {
		if ( putc(*buffer++,stream) == EOF )
			return 0;
	}
	return number;
}

fillbf(ptr)
register FILE *ptr;
{
	register int len;

	return 0;
}

fflush(ptr)
FILE *ptr;
{
	return flush_(ptr,0);
}

flush_(ptr,flag)
register FILE *ptr;
{
	register int size;

	if ( ptr->_flags & _DIRTY ) {
		size = (ptr->_bp - ptr->_buff + _SCTMASK) & ~_SCTMASK;
		posit(ptr->_unit,ptr->_curpos);
		write(ptr->_unit, ptr->_buff, size);
		ptr->_flags &= ~_DIRTY;
		if ( flag )
			ptr->_curpos += size >> _SCTSHFT;
	}
	if ( flag ) {
		clear(ptr->_buff,_BUFSIZ,_FILLC);
		if ( (ptr->_flags&_ATEND) == 0 ) {
			if ( (size = read(ptr->_unit, ptr->_buff, _BUFSIZ)) < 0 )
				return EOF;
			if ( size == 0 )
				ptr->_flags |= _ATEND;
		}
		ptr->_bp = ptr->_buff;
		ptr->_bend = ptr->_buff + _BUFSIZ;
	}
	return 0;
}

ungetc(c,ptr)
int c; register FILE *ptr;
{
	if ( c == EOF || ptr->_bp <= ptr->_buff )
		return EOF;
	*--ptr->_bp = c;
	return c;
}

iseek(stream,pos,mode)
register FILE *stream;
{
	register int i, offset;

	if ( flush_(stream,0) )
		return EOF;

	switch ( mode ) {
	case 0:
		stream->_curpos = (unsigned)pos >> _SCTSHFT;
		offset = pos & _SCTMASK;
		break;
	case 1:
		pos += stream->_bp - stream->_buff;
		goto adjust;
	case 2:
		stream->_curpos = fsize(stream->_unit);
adjust:
		stream->_curpos += pos/_SCTSIZE;
		offset = pos % _SCTSIZE;
		break;
	}

	stream->_flags &= ~_ATEND;
	posit(stream->_unit,stream->_curpos);
	i = read(stream->_unit, stream->_buff, _SCTSIZE);
	stream->_bp = stream->_buff + offset;
	stream->_bend = stream->_buff + i;
	if (i <= 0) {
		stream->_flags |= _ATEND;
		if (i < 0 || offset != 0)
			return EOF;
	}
	return 0;
}

itell(stream)
register FILE *stream;
{
	return (stream->_curpos << _SCTSHFT) + (stream->_bp - stream->_buff);
}
