/*
	STDLIB1.C -- for BDS C v1.50 -- 12/29/82
	Copyright (c) 1982 by Leor Zolman

	The files STDLIB1.C and STDLIB2.C contain the source for
	all functions in the DEFF.CRL library file.

	Functions appearing in this source file:

	fopen		getc		ungetc		getw
	fcreat		fappend		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

	* - The symbolic constant "MAX_QSORT_WIDTH" must be enlarged when
	    sorting objects of greater width than in the definition below.
*/


#include <bdscio.h>

#define 	MAX_QSORT_WIDTH	513		/* Largest object "qsort"
						   can sort	          */

/*
	Buffered I/O for C:
*/

#define STD_IN	0
#define STD_OUT 1
#define STD_ERR 4

#define DEV_LST 2
#define DEV_RDR 3
#define DEV_PUN 3


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


int getc(iobuf)
FILE *iobuf;
{
	int nsecs;
	if (iobuf == STD_IN) return getchar();
	if (iobuf == DEV_RDR) return bdos(3);
	if (!iobuf->_nleft--)		/* if buffer empty, fill it up first */
	 {
		if ((nsecs = read(iobuf -> _fd, iobuf -> _buff, NSECTS)) <= 0)
			return iobuf -> _nleft++;
		iobuf -> _nleft = nsecs * SECSIZ - 1;
		iobuf -> _nextp = iobuf -> _buff;
	 }
	return *iobuf->_nextp++;
}

int ungetc(c, iobuf)
FILE *iobuf;
char c;
{
	if (iobuf == STD_IN) return ungetch(c);
	if ((iobuf < 7) || iobuf -> _nleft == (NSECTS * SECSIZ)) return ERROR;
	*--iobuf -> _nextp = c;
	iobuf -> _nleft++;
	return OK;
}
	

int getw(iobuf)
FILE *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;
FILE *iobuf;
{
	if ((iobuf -> _fd = creat(name)) < 0 ) return ERROR;
	iobuf -> _nextp = iobuf -> _buff;
	iobuf -> _nleft = (NSECTS * SECSIZ);
	iobuf -> _flags = _WRITE;
	return iobuf -> _fd;
}


/*
	Fappend: Open a text file for buffered output, appending onto the end:
*/

int fappend(name, iobuf)
char *name;
FILE *iobuf;
{
	int i, fd;
	if ((fd = open(name,2)) == ERROR)
		return fcreat(name, iobuf);
	if (!(i = cfsize(fd)))
	{
		close(fd);
		return fcreat(name, iobuf);
	}
	if (seek(fd, -1, 2) == ERROR || read(fd, iobuf->_buff, 1) < 1)
	{
		close(fd);
		return ERROR;
	}
	seek(fd, -1, 2);
	for (i = 0; i < SECSIZ; i++)
		if (iobuf->_buff[i] == CPMEOF)
			break;
	iobuf -> _fd = fd;
	iobuf -> _nextp = iobuf -> _buff + i;
	iobuf -> _nleft = (NSECTS * SECSIZ) - i;
	iobuf -> _flags = _WRITE;
	return fd;
}


int putc(c,iobuf)
char c;
FILE *iobuf;
{
	if (iobuf <= 4)			/* handle special device codes: */
	 {
		switch (iobuf)
		 {
			case STD_OUT: return putchar(c);  /* std output */
			case DEV_LST: return (bdos(5,c)); /* list dev.  */
			case DEV_PUN: return (bdos(4,c)); /* to punch   */
			case STD_ERR: if (c == '\n')	  /* to std err */
						bdos(2,'\r');
				      return bdos(2,c);
		 }	
	 }
	if (!iobuf -> _nleft--)		/*   if buffer full, flush it 	*/
	 {
		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;
FILE *iobuf;
{
	if ((putc(w%256,iobuf) >=0 ) && (putc(w / 256,iobuf) >= 0))
				return w;
	return ERROR;
}


int fflush(iobuf)
FILE *iobuf;
{
	int i;
	if (iobuf < 4) return OK;
	if (!(iobuf->_flags & _WRITE))
		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)
FILE *iobuf;
{
	if (iobuf < 4) return OK;
	fflush(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;
}



qsort(base, nel, width, compar)
char *base; int (*compar)();
unsigned width,nel;
{	int i, j;
	unsigned gap, ngap, t1;
	int jd, 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;
unsigned w;
{
	char swapbuf[MAX_QSORT_WIDTH];
	movmem(a,swapbuf,w);
	movmem(b,a,w);
	movmem(swapbuf,b,w);
}


/*
 	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 functions:
*/

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) {
			_allocp = q;
			if (p -> _size == nunits)
				_allocp->_ptr = p->_ptr;
			else {
				q = _allocp->_ptr = p + nunits;
				q->_ptr = p->_ptr;
				q->_size = p->_size - nunits;
				p -> _size = nunits;
			 }
			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;
}


/*
	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;
}

