/*
	Full K&R malloc() and free() for AZTEC C II

This module adapted for the CP/M environment from source code in Brian
W. Kernighan and Dennis M. Ritchie's "The C Programming Language" by
William C. Colley III -- 4 OCT 1982.

This module implements the functions alloc(), morecore(), xsbrk(), and
free() as per pp. 173-7 of Kernighan and Ritchie.  Since xsbrk() is
responsible for preventing collision between the allocated data and
the stack, it must know how much space to leave for the stack.  Thus,
a function rsvstk() is provided to override the default 1024 bytes.

The functions in this package are:

	char *alloc(nb)			allocates a block of nb bytes and
	unsigned nb;			returns a pointer to it.  If no such
					block is available, the value NULL (0)
					is returned.

	free(blk)			Attaches the storage allocation block
	char *blk;			blk to the free list.  Returns no
					meaningful value.

	HEADER *morecore(nb)		Gets a storage allocation block of
	unsigned nb;			size nb from the heap and returns a
					pointer to it.  Returns NULL (0) if
					not enough space is available.

	char *xsbrk(nb)			Gets nb bytes from the heap.  Returns
	unsigned nb;			a pointer to the bytes or -1 if not
					enough bytes are available.

	char *xsettop(nb)		Gets nb bytes from the heap.  Returns
	unsigned nb;			a pointer to the bytes or NULL (0) if
					not enough bytes are available.

	rsvstk(stk)			Changes the minimum allowable remaining
	unsigned stk;			stack size at a call to xsbrk() to stk
					bytes.  Default value is 1024 bytes.
*/

#define	NULL	0

union header {
	struct {
		union header *ptr;
		unsigned size;
		} s;
	long l;
};

typedef union header HEADER;

static HEADER base, *allocp = NULL;

char *alloc(nb)
unsigned nb;
{
	HEADER *morecore();
	register HEADER *p, *q;
	register unsigned nu;

	nu = ((nb + 3) >> 2) + 1;
	if ((q = allocp) == NULL) {
		base.s.ptr = allocp = q = &base;
		base.s.size = 1;
		}
	for (p = q->s.ptr; ; q = p, p = p->s.ptr) {
		if (p->s.size >= nu) {
			if (p->s.size == nu) q->s.ptr = p->s.ptr;
			else {
				p->s.size -= nu;
				p += p->s.size;
				p->s.size = nu;
				}
			allocp = q;  return (char *)(p + 1);
			}
		if (p == allocp)
			if ((p = morecore(nu)) == NULL) return NULL;
		}
}

HEADER *morecore(nu)
unsigned nu;
{
	char *xsbrk();
	register char *cp;
	register HEADER *up;

	if ((int)(cp = xsbrk(nu << 2)) == -1) return NULL;
	up = (HEADER *)cp;
	up->s.size = nu;
	free((char *)(up + 1));
	return allocp;
}

free(blk)
char *blk;
{
	register HEADER *p, *q;

	p = (HEADER *)blk - 1;
	for (q = allocp; !(p > q && p < q->s.ptr); q = q->s.ptr)
		if (q >= q ->s.ptr && (p > q || p < q->s.ptr)) break;

	if (p + p->s.size == q->s.ptr) {
		p->s.size += q->s.ptr->s.size;
		p->s.ptr = q->s.ptr->s.ptr;
		}
	else p->s.ptr = q->s.ptr;
	if (q + q->s.size == p) {
		q->s.size += p->s.size;
		q->s.ptr = p->s.ptr;
		}
	else q->s.ptr = p;
	allocp = q;
}

/*  The functions xsbrk(), xsettop(), and rsvstk() live in the module xsbrk.mac
	as they have to beat on machine things like the stack pointer.	*/


