/* roff.c, macro processing */

#include "nroff.h"
extern	char	extrabuf[];

/* define a macro */

setmdef(buf, cmd)
char	*buf;
{
	struct	source	*mp;
	char	name[2];
	char	*ttl;
	struct	cm	*getcmd();
	struct	cm	*cp;
	int	l;
	
	if(*buf == '\0')
		return;
	for(ttl = name ; *buf && *buf != ' ';buf++)
		if(ttl < name + 2)
			*ttl++ = *buf;
	if(ttl == name + 1)
		name[1] = '\0';
	
	for(mp = macros ; mp ; mp = mp->m_next)
		if(mp->m_name[0] == name[0] && mp->m_name[1] == name[1])
			break;
	if(mp == 0){		/* not found */
		mp = (struct source *)mymalloc(sizeof(struct source), TRUE);
		mp->m_name[0] = name[0];
		mp->m_name[1] = name[1];
		mp->m_next = macros;
		macros = mp;
	}
		
		/* redefining an old one (appending ) */
	if(cmd != AM){
		if(mp->m_val)
			myfree(mp->m_val);
		mp->m_val = 0;
	}
	if(mp->m_val == 0){
		mp->m_val = mymalloc(LINESIZE+1, FALSE);
		mp->m_eptr = mp->m_val + LINESIZE;
		mp->m_curp = mp->m_val;
	}
	else {
		l = strlen(mp->m_val);
		ttl = mymalloc(l + LINESIZE + 1, FALSE);
		strcpy(ttl, mp->m_val);
		myfree(mp->m_val);
		mp->m_val = ttl;
		mp->m_curp = mp->m_val + l;
		mp->m_eptr = mp->m_curp + LINESIZE;
	}
	mp->m_last = curdiv;
	curdiv = mp;
	while(ngets(extrabuf, TRUE)){
		if(CMD(extrabuf[0])){
			cp = getcmd(extrabuf);
			if(cp != 0)		/* unknown command */
				if(cp->sev == EN)  /* finish definition */
					break;
		}
		/* must add to macro definition */
		for(ttl = extrabuf ; *ttl ; ttl++)
			PUT(*ttl);
		PUTNL();
	}
	*mp->m_curp = '\0';
	curdiv = mp->m_last;
	mp->m_last = 0;
}

setmargs(mp, buf)
struct	source	*mp;
char	*buf;
{
	int	i;
	int	c;
	char	*ttl;

	/* first free all old arguments (if any) */
	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;	/* reset current args */

	for(;;mp->m_nargs++){ /* now collect arguments */
		while(*buf == ' ')
			buf++;
		if(*buf == '\0')
			break;
		if(*buf == '"')
			c = *buf++;
		else
			c = ' ';
		ttl = buf;
		while(*buf != '\0' && *buf != c)
			buf++;
		if(*buf == c)
			*buf++ = '\0';
		c = strlen(ttl);
		mp->m_args[mp->m_nargs] = mymalloc(c+1, FALSE);
		strcpy(mp->m_args[mp->m_nargs], ttl);
	}
}
		
setsource(buf)
char	*buf;
{
	FILE	*fp;
	struct	source	*mp;
	char	*ttl;
	int	c;

	if(*buf == '\0')
		return;
	if(*buf == '"')
		c = *buf++;
	else
		c = ' ';
	ttl = buf;
	while(*buf && *buf != c)
		buf++;
	*buf = '\0';
	/*
	 * now check current so level
	 */
	if(nsources++ >= MAXSOURCE){
		fprintf(stderr, "Out of .so stack space\n");
		exit(1);
	}
	if( (fp = fopen(ttl, "r")) == NULL){
		fprintf(stderr, "Cannot open .so '%s'\n", ttl);
		exit(2);
	}
	mp = (struct source *)mymalloc(sizeof(struct source), TRUE);
	mp->m_val = mymalloc(LINESIZE+1, TRUE);
	mp->m_curp = mp->m_val;
	mp->m_fp = fp;
	mp->m_last = curmacro;
	curmacro = mp;
}

/* call the end macro */

doemacro(name)
char	*name;
{
	struct	source	*mp;

	for(mp = macros ; mp ; mp = mp->m_next)
		if(mp->m_name[0] == name[0] && mp->m_name[1] == name[1])
			break;
	if(mp == 0)	/* not found */
		return;
	mp->m_last = curmacro;
	curmacro = mp;
	mp->m_curp = mp->m_val;
}
