/*******************************************************************
*                                                                  *
*             This software is part of the ast package             *
*                Copyright (c) 1985-2004 AT&T Corp.                *
*        and it may only be used by you under license from         *
*                       AT&T Corp. ("AT&T")                        *
*         A copy of the Source Code Agreement is available         *
*                at the AT&T Internet web site URL                 *
*                                                                  *
*       http://www.research.att.com/sw/license/ast-open.html       *
*                                                                  *
*    If you have copied or used this software without agreeing     *
*        to the terms of the license you are infringing on         *
*           the license and copyright and are violating            *
*               AT&T's intellectual property rights.               *
*                                                                  *
*            Information and Software Systems Research             *
*                        AT&T Labs Research                        *
*                         Florham Park NJ                          *
*                                                                  *
*               Glenn Fowler <gsf@research.att.com>                *
*                David Korn <dgk@research.att.com>                 *
*                 Phong Vo <kpv@research.att.com>                  *
*                                                                  *
*******************************************************************/
#pragma prototyped
/*
 * pointer stack routines
 */

static const char id_stack[] = "\n@(#)$Id: stack (AT&T Bell Laboratories) 1984-05-01 $\0\n";

#include <ast.h>
#include <stack.h>

/*
 * create a new stack
 */

STACK
stackalloc(register int size, void* error)
{
	register STACK			stack;
	register struct stackblock	*b;

	if (size <= 0) size = 100;
	if (!(stack = newof(0, struct stacktable, 1, 0))) return(0);
	if (!(b = newof(0, struct stackblock, 1, 0)))
	{
		free(stack);
		return(0);
	}
	if (!(b->stack = newof(0, void*, size, 0)))
	{
		free(b);
		free(stack);
		return(0);
	}
	stack->blocks = b;
	stack->size = size;
	stack->error = error;
	stack->position.block = b;
	stack->position.index = -1;
	b->next = 0;
	b->prev = 0;
	return(stack);
}

/*
 * remove a stack
 */

void
stackfree(register STACK stack)
{
	register struct stackblock*	b;
	register struct stackblock*	p;

	b = stack->blocks;
	while (p = b)
	{
		b = p->next;
		free(p->stack);
		free(p);
	}
	free(stack);
}

/*
 * clear stack
 */

void
stackclear(register STACK stack)
{
	stack->position.block = stack->blocks;
	stack->position.index = -1;
}

/*
 * get value on top of stack
 */

void*
stackget(register STACK stack)
{
	if (stack->position.index < 0) return(stack->error);
	else return(stack->position.block->stack[stack->position.index]);
}

/*
 * push value on to stack
 */

int
stackpush(register STACK stack, void* value)
{
	register struct stackblock	*b;

	if (++stack->position.index >= stack->size)
	{
		b = stack->position.block;
		if (b->next) b = b->next;
		else
		{
			if (!(b->next = newof(0, struct stackblock, 1, 0)))
				return(-1);
			b = b->next;
			if (!(b->stack = newof(0, void*, stack->size, 0)))
				return(-1);
			b->prev = stack->position.block;
			b->next = 0;
		}
		stack->position.block = b;
		stack->position.index = 0;
	}
	stack->position.block->stack[stack->position.index] = value;
	return(0);
}

/*
 * pop value off stack
 */

int
stackpop(register STACK stack)
{
	/*
	 * return:
	 *
	 *	-1	if stack empty before pop
	 *	 0	if stack empty after pop
	 *	 1	if stack not empty before & after pop
	 */

	if (stack->position.index < 0) return(-1);
	else if (--stack->position.index < 0)
	{
		if (!stack->position.block->prev) return(0);
		stack->position.block = stack->position.block->prev;
		stack->position.index = stack->size - 1;
		return(1);
	}
	else return(1);
}

/*
 * set|get stack position
 */

void
stacktell(register STACK stack, int set, STACKPOS* position)
{
	if (set) stack->position = *position;
	else *position = stack->position;
}
