

#include "bdscio.h"

/*
	STDLIB1.C -- for BDS C v1.45 -- LZ, 11/6/81

	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		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:
*/

#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)
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 == 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++;
}

/*
	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 == STD_IN) return ungetch(c);
	if ((iobuf < 7) || 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;
{
	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 <= 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;
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;
{
	if (iobuf < 4) return OK;
	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.)

	"Qsort" has been fixed on 4/10/81 to handle data arrays bigger
	than 32K. (Ints were used instead of unsigneds in previous 
	versions.)

	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)();
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 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;
}

