

#include "bdscio.h"

/*
	STDLIB1.C -- for BDS C v1.4 -- 6/28/80

	The files STDLIB*.C contain source for all DEFF.CRL
	functions which are written in C; Any functions which
	appear in DEFF.CRL but have no corresponding source
	were written in machine code and converted to .CRL
	format (as described in the User's Guide.)

	All functions written by Leor Zolman....who is
	soley responsible for their kludginess.

	Functions appearing in this file:

	fopen		getc		ungetc		getw
	fcreat		putc		putw
	fflush		fclose
	atoi
	strcat		strcmp		strcpy		strlen
	isalpha		isupper		islower		isdigit
	isspace		toupper		tolower
	qsort
	initw		initb		getval
	alloc *		free *
	abs		max		min

	* -- Compilation of alloc and free must be explicitly enabled by
	     swapping the commenting of the ALLOC_ON and ALLOC_OFF definitions
	     in BDSCIO.H.

*/


/*
	Buffered I/O for C:
*/

int fopen(filename,iobuf)
struct _buf *iobuf;
char *filename;
{
	if ((iobuf -> _fd = open(filename,0))<0) return ERROR;
	iobuf -> _nleft = 0;
	return iobuf -> _fd;
}


int getc(iobuf)
struct _buf *iobuf;
{
	int nsecs;
	if (iobuf == 0) return getchar();
	if (iobuf == 3) return bdos(3);
	if (iobuf -> _nleft--) return *iobuf -> _nextp++;
	if ((nsecs = read(iobuf -> _fd, iobuf -> _buff, NSECTS)) <= 0)
				return ERROR;
	iobuf -> _nleft = (NSECTS * SECSIZ - 1);
	iobuf -> _nextp = iobuf -> _buff;
	return *iobuf->_nextp++;
}

/*
	Buffered "unget" a character routine. Only ONE
	byte may be "ungotten" between consecutive "getc" calls.
*/

int ungetc(c, iobuf)
struct _buf *iobuf;
char c;
{
	if (iobuf == 0) return ungetch(c);
	if (iobuf -> _nleft == (NSECTS * SECSIZ)) return ERROR;
	*--iobuf -> _nextp = c;
	iobuf -> _nleft++;
	return OK;
}
	

int getw(iobuf)
struct _buf *iobuf;
{
	int a,b;	
	if (((a=getc(iobuf)) >= 0) && ((b= getc(iobuf)) >=0))
			return 256*b+a;
	return ERROR;
}


int fcreat(name,iobuf)
char *name;
struct _buf *iobuf;
{
	unlink(name);
	if ((iobuf -> _fd = creat(name)) < 0 ) return ERROR;
	iobuf -> _nextp = iobuf -> _buff;
	iobuf -> _nleft = (NSECTS * SECSIZ);
	return iobuf -> _fd;
}


int putc(c,iobuf)
char c;
struct _buf *iobuf;
{
	if (iobuf == 1) return putchar(c);
	if (iobuf == 2) return (bdos(5,c));
	if (iobuf == 3) return (bdos(4,c));
	if (iobuf -> _nleft--) return *iobuf -> _nextp++ = c;
	if ((write(iobuf -> _fd, iobuf -> _buff, NSECTS)) != NSECTS)
			return ERROR;
	iobuf -> _nleft = (NSECTS * SECSIZ - 1);
	iobuf -> _nextp = iobuf -> _buff;
	return *iobuf -> _nextp++ = c;
}


int putw(w,iobuf)
unsigned w;
struct _buf *iobuf;
{
	if ((putc(w%256,iobuf) >=0 ) && (putc(w / 256,iobuf) >= 0))
				return w;
	return ERROR;
}


int fflush(iobuf)
struct _buf *iobuf;
{
	int i;
	if (iobuf < 4) return OK;
	if (iobuf -> _nleft == (NSECTS * SECSIZ)) return OK;

	i = NSECTS - iobuf->_nleft / SECSIZ;
	if (write(iobuf -> _fd, iobuf -> _buff, i) != i)
			return ERROR;
	i = (i-1) * SECSIZ;

	if (iobuf -> _nleft) {
		movmem(iobuf->_buff + i, iobuf->_buff, SECSIZ);
		iobuf -> _nleft += i;
		iobuf -> _nextp -= i;
		return seek(iobuf->_fd, -1, 1);
	 }

	iobuf -> _nleft = (NSECTS * SECSIZ);
	iobuf -> _nextp = iobuf -> _buff;
	return OK;
}

int fclose(iobuf)
struct _buf *iobuf;
{
	return close(iobuf -> _fd);
}



/*
	Some string functions
*/


int atoi(n)
char *n;
{
	int val; 
	char c;
	int sign;
	val=0;
	sign=1;
	while ((c = *n) == '\t' || c== ' ') ++n;
	if (c== '-') {sign = -1; n++;}
	while (  isdigit(c = *n++)) val = val * 10 + c - '0';
	return sign*val;
}


char *strcat(s1,s2)
char *s1, *s2;
{
	char *temp; temp=s1;
	while(*s1) s1++;
	do *s1++ = *s2; while (*s2++);
	return temp;
}


int strcmp(s,t)
char s[], t[];
{
	int i;
	i = 0;
	while (s[i] == t[i])
		if (s[i++] == '\0')
			return 0;
	return s[i] - t[i];
}


char *strcpy(s1,s2)
char *s1, *s2;
{
	char *temp; temp=s1;
	while (*s1++ = *s2++);
	return temp;
}


int strlen(s)
char *s;
{
	int len;
	len=0;
	while (*s++) len++;
	return len;
}


/*
	Some character diddling functions
*/

int isalpha(c)
char c;
{
	return isupper(c) || islower(c);
}


int isupper(c)
char c;
{
	return c>='A' && c<='Z';
}


int islower(c)
char c;
{
	return c>='a' && c<='z';
}


int isdigit(c)
char c;
{
	return c>='0' && c<='9';
}


int isspace(c)
char c;
{
	return c==' ' || c=='\t' || c=='\n';
}


char toupper(c)
char c;
{
	return islower(c) ? c-32 : c;
}


char tolower(c)
char c;
{
	return isupper(c) ? c+32 : c;
}




/*
	Other stuff...
*/


/*
	This is the new qsort routine, utilizing the shell sort
	technique given in the Software Tools book (by Kernighan 
	& Plauger.)

	NOTE: this "qsort" function is different from the "qsort" given
	in some old releases (pre 1.32) -- here, the items are sorted
	in ASCENDING order. The old "qsort" sorted stuff in DESCENDING
	order, and was in part responsible for the atrocious play of
	the "Othello" program (it always made the WORST moves it could
	find...) 
*/

qsort(base, nel, width, compar)
char *base; int (*compar)();
{	int gap,ngap, i, j;
	int jd, t1, t2;
	t1 = nel * width;
	for (ngap = nel / 2; ngap > 0; ngap /= 2) {
	   gap = ngap * width;
	   t2 = gap + width;
	   jd = base + gap;
	   for (i = t2; i <= t1; i += width)
	      for (j =  i - t2; j >= 0; j -= gap) {
		if ((*compar)(base+j, jd+j) <=0) break;
			 _swp(width, base+j, jd+j);
	      }
	}
}

_swp(w,a,b)
char *a,*b;
int w;
{
	char tmp;
	while(w--) {tmp=*a; *a++=*b; *b++=tmp;}
}




/*
 	Initialization functions
*/


initw(var,string)
int *var;
char *string;
{
	int n;
	while ((n = getval(&string)) != -32760) *var++ = n;
}

initb(var,string)
char *var, *string;
{
	int n;
	while ((n = getval(&string)) != -32760) *var++ = n;
}

int getval(strptr)
char **strptr;
{
	int n;
	if (!**strptr) return -32760;
	n = atoi(*strptr);
	while (**strptr && *(*strptr)++ != ',');
	return n;
}



/*
	Storage allocation routines, taken from chapter 8 of K&R, but
	simplified to ignore the storage allignment problem and not
	bother with the "morecore" hack (a call to "sbrk" under CP/M is
	a relatively CHEAP operation, and can be done on every call to
	"alloc" without degrading efficiency.)

	Note that compilation of "alloc" and "free" is disabled until
	the "#define ALLOC_ON 1" statement is un-commented in the header
	file ("BDSCIO.H"). This is done so that the external storage
	required by alloc and free isn't declared unless the user
	actually needs the alloc and free functions. As soon as BDS C
	gets static variables, this kludge will go away.
*/


#ifdef ALLOC_ON		/* Compilation of alloc and free is enabled only
			   when the ALLOC_ON symbol is #defined in BDSCIO.H */

char *alloc(nbytes)
unsigned nbytes;
{
	struct _header *p, *q, *cp;
	int nunits; 
	nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
	if ((q = _allocp) == NULL) {
		_base._ptr = _allocp = q = &_base;
		_base._size = 0;
	 }
	for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
		if (p -> _size >= nunits) {
			if (p -> _size == nunits)
				q -> _ptr = p -> _ptr;
			else {
				p -> _size -= nunits;
				p += p -> _size;
				p -> _size = nunits;
			 }
			_allocp = q;
			return p + 1;
		 }
		if (p == _allocp) {
			if ((cp = sbrk(nunits * sizeof (_base))) == ERROR)
				return NULL;
			cp -> _size = nunits; 
			free(cp+1);	/* remember: pointer arithmetic! */
			p = _allocp;
		}
	 }
}


free(ap)
struct _header *ap;
{
	struct _header *p, *q;

	p = ap - 1;	/* No need for the cast when "ap" is a struct ptr */

	for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
		if (q >= q -> _ptr && (p > q || p < q -> _ptr))
			break;
	if (p + p -> _size == q -> _ptr) {
		p -> _size += q -> _ptr -> _size;
		p -> _ptr = q -> _ptr -> _ptr;
	 }
	else p -> _ptr = q -> _ptr;

	if (q + q -> _size == p) {
		q -> _size += p -> _size;
		q -> _ptr = p -> _ptr;
	 }
	else q -> _ptr = p;

	_allocp = q;
}

#endif



/*
	Now some really hairy functions to wrap things up:
*/

int abs(n)
{
	return (n<0) ? -n : n;
}

int max(a,b)
{
	return (a > b) ? a : b;
}

int min(a,b)
{
	return (a <= b) ? a : b;
}

