/* roff.c, when processing */
#include "nroff.h"

setwhen(buf)
char	*buf;
{
	char	name[2];
	char	*ttl;
	int	pos;
	struct	when	*wp;
	int	fbot;
	struct	when	*xwp;

	pos = eval(&buf);
	while(*buf == ' ')
		buf++;
	if(*buf == '\0'){	/* delete when on this line */
		if(pos < 0)	/* pos is relative to bottom */
			pos = pos - bottom;
		for(wp = whens ; wp ; wp = wp->w_next)
			if(wp->w_lno == pos)
				break;
		if(wp == 0)	/* no when on this line */
			return;
		if(wp == whens)
			whens = wp->w_next;
		else {
			xwp = whens;
			for(; xwp->w_next != wp ; xwp = xwp->w_next);
			xwp->w_next = wp->w_next;
		}
		myfree( (char *)wp);
		return;
	}
	ttl = name;
	for(;*buf && *buf != ' '; buf++)
		if(ttl < name + 2)
			*ttl++ = *buf;
	if(ttl == name + 1)
		*ttl = '\0';
	wp = (struct when *)mymalloc(sizeof(struct when), TRUE);
	wp->w_next = whens;
	whens = wp;
	wp->w_name[0] = name[0];
	wp->w_name[1] = name[1];
	wp->w_lno = pos;
}

/* change the position of the when signal */

chwhen(buf)
char	*buf;
{
	char	name[2];
	char	*ttl;
	struct	when	*wp;
	struct	when	*xwp;

	if(*buf == '\0')	/* no name !! */
		return;
	ttl = name;
	for(;*buf && *buf != ' '; buf++)
		if(ttl < name + 2)
			*ttl++ = *buf;
	if(ttl == name + 1)
		*ttl = '\0';
	for(wp = whens ; wp ; wp = wp->w_next)
		if(wp->w_name[0] == name[0] && wp->w_name[1] == name[1])
			break;
	if(wp == 0)		/* not found */
		return;
	while(*buf == ' ')
		buf++;
	/*
	 * first zap old when value
	 */
	if(wp == whens)
		whens = wp->w_next;
	else {
		for(xwp = whens ; xwp->w_next != wp ; xwp = xwp->w_next);
		xwp->w_next = wp->w_next;
	}
	if(*buf == '\0'){	/* no value delete */
		myfree((char *)wp);
		return;
	}
	wp->w_lno = eval(&buf);
	wp->w_next = whens;
	whens = wp;
}

spring(lno)
{
	char	name[2];
	struct	source	*mp;
	int	i;
	int	cmd;
	struct	when	*wp;
	int	fbot = lno - bottom; /* negative value to the bottom */

	for(wp = whens ; wp ; wp = wp->w_next)
		if(wp->w_lno == lno || (wp->w_lno < 0 && wp->w_lno == fbot))
			break;
	if(wp == 0)	/* no when on this line */
		return(0);
	for(mp = macros ; mp ; mp = mp->m_next)
		if(wp->w_name[0] == mp->m_name[0] &&
				wp->w_name[1] == mp->m_name[1])
			break;
	if(mp == 0)		/* macro not found */
		return(sprcmd(wp->w_name));
	if(mp->m_last != 0)	/* got a macro which has sprung already */
		return(0);
	mp->m_last = curmacro;	/* invoke the macro */
	curmacro = mp;
	curmacro->m_curp = mp->m_val;
	for(i = 0 ; i < mp->m_nargs ; i++)
		if(mp->m_args[i] != 0){
			myfree(mp->m_args[i]);
			mp->m_args[i] = 0;
		}
	mp->m_nargs = 0;
	return(1);
}

/*
 * is this a command that has to be sprung ??
 */

sprcmd(name)
char	*name;
{
	struct	cm	*cp;
	struct	source	*mp;
	char	*p;

	for(cp = cmd ; cp->se ; cp++)
		if(cp->se[0] == *name && cp->se[1] == name[1])
			break;
	if(cp->se == 0)		/* not a command */
		return(0);

	/* hand craft !! */
	mp = (struct source *)mymalloc(sizeof(struct source), TRUE);
	mp->m_val = mymalloc(1+2+1+1, FALSE);	/* .bp\n\0 */
	mp->m_curp = mp->m_val;
	p = mp->m_val;
	*p++ = cmdchar1;	/* horrible !! */
	*p++ = cp->se[0];
	if(*p = cp->se[1])
		p++;
	*p++ = '\n';
	*p = 0;
	mp->m_last = curmacro;
	curmacro = mp;
	return(1);
}

/*
 * little function to find out where the next trap is after
 * a lineno, if no when is found then value is to end of page
 * in a diversion, value is huge
 */
towhen(lno)
{
	struct	when	*wp;
	int	lowbound;
	int	val;
	int	fbot;

	lowbound = bottom;	/* also works for diversions */
	fbot = lno - bottom;	/* negative to the bottom */
	
	for(wp = whens ; wp ; wp = wp->w_next){
		if(wp->w_lno >= 0){
			if(lno <= wp->w_lno){
				if(wp->w_lno < lowbound)
					lowbound = wp->w_lno;
			}
		} else if(fbot <= wp->w_lno){
			if(bottom + wp->w_lno < lowbound)
				lowbound = bottom + wp->w_lno;
		}
	}
	return(lowbound - lno);
}
