#
# include	<stdio.h>

# include	"constants.h"
# include	"globals.h"

/*
**  RETRIEVE.C -- ret_list struct handlers
**
**	The Ret_list is a structure where references to C variables,
**	and their types, used in a target list of a "tupret" are kept
**	for outputting in the while loop generated.
**
**	Defines:
**		enter_ret()
**		add_ret()
**		w_ret()
**		free_ret()
**
**	Required By:
**		the semantic augments
**
**	Files:
**		globals.h
**		constants.h
**
**	History:
**		6/1/78 -- (marc) written
*/

/*
**  ENTER_RET -- enter a variable in a ret_list
**	Concatenatest the strings in disp the calls add_ret
**	to add the new string to Ret_list.
**
**	Parameters:
**		disp -- display containing the reference to the variable
**		type -- type of the variable
**
**	Called By:
**		tupret productions
**
**	History:
**		6/1/78 -- (marc) written
*/


enter_ret(disp, type)
struct display		*disp;
int			type;
{
	char			buf [MAXSTRING + 2]; /* &buf [1] is the start
						      * of the concatenated
						      * strings
						      */
	register char		*srce, *dest;
	struct disp_node	*d;
	register		i;

	i = 0;
	dest = buf;
	for (d = disp->disp_first; d; d = d->d_next)
	{
		for (srce = d->d_elm; *srce; )
		{
			if (i < MAXSTRING)
			{
				i += 1;
				*++dest = *srce++;
			}
			else
				break;
		}

		if (i >= MAXSTRING)
		{
			yysemerr("reference to a variable too long, ']' probably missing from array subscription",
			0);
			break;
		}
	}
	*++dest = '\0';
	add_ret(salloc(&buf [1]), type);
}

/*
**  ADD_RET -- add a string (reference to a variable) to the Ret_list
**
**	Parameters:
**		s -- string to add
**		type -- type of variable being added
**
**	Called By:
**		enter_ret()
**
**	History:
**		6/1/78 -- (marc) written
*/


add_ret(s, type)
char		*s;
int		type;
{
	register struct ret_list	*list;
	register struct ret_var		*node;
	extern char			*nalloc();

	if (!s)
	{
		s = "ERROR_TOKEN";
		yysemerr("alloc error", s);
	}
	list = &Ret_list;
	node = (struct ret_var *) nalloc(sizeof *node);
	if (!node)
	{
		yysemerr("alloc error", s);
		xfree(s);
		return;
	}
	node->r_elm = s;
	node->r_next = 0;
	node->r_type = type;
	if (list->ret_first == 0)
		list->ret_first = list->ret_last = node;
	else
	{
		list->ret_last->r_next = node;
		list->ret_last = node;
	}
}


/*
**  W_RET -- Generates the IIn_get() calls for the Ret_list
**
**	Any variable whose type is not string gets an '&'
**	(adress of) operand prepended.
**
**	Called By:
**		"gen_while" production
**
**	History:
**		6/1/78 -- (marc) written
*/


w_ret()
{
	register struct ret_var	*node;
	char			type [3];

	for (node = Ret_list.ret_first; node; node = node->r_next)
	{
		w_op("IIn_ret(");
		if (node->r_type != opSTRING)
			w_op("&");
		w_op(node->r_elm);
		w_op(",");
		itoa(node->r_type, type);
		w_op(type);
		w_op(");");
	}
}


/*
**  FRE_RET -- Free up the storage used by the Ret_list
**
**	History:
**		6/1/78 -- (marc) written
**
*/



free_ret()
{
	register struct ret_list	*list;
	register struct ret_var		*n, *f;

	list = &Ret_list;
	for (f = list->ret_first; f; f = n)
	{
		n = f->r_next;
		xfree(f->r_elm);
		xfree(f);
	}
	list->ret_first = list->ret_last = 0;
}
