309 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *	expand.c - macro expansion functions for cawf(1)
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 *	Copyright (c) 1991 Purdue University Research Foundation,
 | 
						|
 *	West Lafayette, Indiana 47907.  All rights reserved.
 | 
						|
 *
 | 
						|
 *	Written by Victor A. Abell <abe@mace.cc.purdue.edu>,  Purdue
 | 
						|
 *	University Computing Center.  Not derived from licensed software;
 | 
						|
 *	derived from awf(1) by Henry Spencer of the University of Toronto.
 | 
						|
 *
 | 
						|
 *	Permission is granted to anyone to use this software for any
 | 
						|
 *	purpose on any computer system, and to alter it and redistribute
 | 
						|
 *	it freely, subject to the following restrictions:
 | 
						|
 *
 | 
						|
 *	1. The author is not responsible for any consequences of use of
 | 
						|
 *	   this software, even if they arise from flaws in it.
 | 
						|
 *
 | 
						|
 *	2. The origin of this software must not be misrepresented, either
 | 
						|
 *	   by explicit claim or by omission.  Credits must appear in the
 | 
						|
 *	   documentation.
 | 
						|
 *
 | 
						|
 *	3. Altered versions must be plainly marked as such, and must not
 | 
						|
 *	   be misrepresented as being the original software.  Credits must
 | 
						|
 *	   appear in the documentation.
 | 
						|
 *
 | 
						|
 *	4. This notice may not be removed or altered.
 | 
						|
 */
 | 
						|
 | 
						|
#include "cawf.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Expand(line) - expand macro or if/ie/el line
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
Expand(line)
 | 
						|
	unsigned char *line;
 | 
						|
{
 | 
						|
	unsigned char buf[2*MAXLINE];	/* line buffer */
 | 
						|
	unsigned char cmd[4];		/* nroff command */
 | 
						|
	int cmdl;			/* command length */
 | 
						|
	int cmdx;			/* cmd index in Macrotab[] */
 | 
						|
	int cond = 0;			/* conditional statuses */
 | 
						|
	int i, j;			/* temporary indexes */
 | 
						|
	int iflen;			/* if statement length */
 | 
						|
	int invert;			/* inversion status */
 | 
						|
	unsigned char *lp;		/* line pointer */
 | 
						|
	int mx = -1;			/* Macrotab[] index */
 | 
						|
	int n1, n2;			/* temporary numbers */
 | 
						|
	int nargs = 0;			/* number of arguments */
 | 
						|
	int nleft = 0;			/* number of macro lines left */
 | 
						|
	char op;			/* comparison operator */
 | 
						|
	int prevcond;			/* previous condition (for else's) */
 | 
						|
	int ptr = -1;			/* Macrotxt[] index */
 | 
						|
	int quote;			/* quoted string status */
 | 
						|
	unsigned char *s1, *s2;		/* temporary string pointers */
 | 
						|
 | 
						|
 | 
						|
	(void) sprintf((char *)buf, ".^= %d %s", NR, (char *)Inname);
 | 
						|
	Pass2(buf);
 | 
						|
 | 
						|
	for (lp = line; *lp; ) {
 | 
						|
		invert = regexec(Pat[1].pat, lp);
 | 
						|
		prevcond = cond;
 | 
						|
		cond = 0;
 | 
						|
		if (regexec(Pat[0].pat, lp) == 0) {
 | 
						|
	    /*
 | 
						|
	     * Not conditional: - ! "^[.'](i[ef]|el)"
 | 
						|
	     */
 | 
						|
			cond = 1;
 | 
						|
			iflen = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		else if (regexec(Pat[2].pat, lp)) {
 | 
						|
	    /*
 | 
						|
	     * Argument count comparison: -
 | 
						|
	     *		"^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] "
 | 
						|
	     */
 | 
						|
			iflen = strlen(".if \\n(.$=n ") + invert;
 | 
						|
			s1 = lp + iflen - 3;
 | 
						|
			op = *s1++;
 | 
						|
			if (*s1 == '=' && (op == '>' || op == '<')) {
 | 
						|
				s1++;
 | 
						|
				op = (op == '>') ? 'G' : 'L';
 | 
						|
			}
 | 
						|
			n1 = (int)(*s1 - '0');
 | 
						|
			switch (op) {
 | 
						|
				case '=':
 | 
						|
					if ((nargs - 1) == n1)
 | 
						|
						cond = 1;
 | 
						|
					break;
 | 
						|
				case '<':
 | 
						|
					if ((nargs - 1) < n1)
 | 
						|
						cond = 1;
 | 
						|
					break;
 | 
						|
				case '>':
 | 
						|
					if ((nargs - 1) > n1)
 | 
						|
						cond = 1;
 | 
						|
					break;
 | 
						|
				case 'G':	/* >= */
 | 
						|
					if ((nargs - 1) >= n1)
 | 
						|
						cond = 1;
 | 
						|
					break;
 | 
						|
				case 'L':	/* <= */
 | 
						|
					if ((nargs - 1) <= n1)
 | 
						|
						cond = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		else if (regexec(Pat[3].pat, lp)) {
 | 
						|
	    /*
 | 
						|
	     * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' "
 | 
						|
	     */
 | 
						|
			iflen = strlen(".if '\\$n'") + invert;
 | 
						|
			n1 = (int)(*(lp + iflen - 2) - '0');
 | 
						|
			if (n1 >= 0 && n1 < nargs)
 | 
						|
				s1 = Args[n1];
 | 
						|
			else
 | 
						|
				s1 = (unsigned char *)"";
 | 
						|
			if ((s2 = (unsigned char *)strchr((char *)lp
 | 
						|
				  + iflen, '\''))
 | 
						|
			!= NULL) {
 | 
						|
				n2 = s2 - lp - iflen;
 | 
						|
				if (strncmp((char *)s1, (char *)lp + iflen, n2)
 | 
						|
				== 0)
 | 
						|
					cond = 1;
 | 
						|
				iflen += n2 + 2;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		else if (regexec(Pat[4].pat, lp)) {
 | 
						|
	    /*
 | 
						|
	     * Nroff or troff: - "^[.']i[ef] !?[nt] "
 | 
						|
	     */
 | 
						|
			iflen = strlen(".if n ") + invert;
 | 
						|
			if (*(lp + iflen - 2) == 'n')
 | 
						|
				cond = 1;
 | 
						|
		}
 | 
						|
		
 | 
						|
		else if ((*lp == '.' || *lp == '\'')
 | 
						|
		     &&  strncmp((char *)lp+1, "el ", 3) == 0) {
 | 
						|
	    /*
 | 
						|
	     * Else clause: - "^[.']el "
 | 
						|
	     */
 | 
						|
			cond = 1 - prevcond;
 | 
						|
			iflen = 4;
 | 
						|
		}
 | 
						|
		
 | 
						|
		else {
 | 
						|
	    /*
 | 
						|
	     * Unknown conditional:
 | 
						|
	     */
 | 
						|
			cond = 1;
 | 
						|
			iflen = 0;
 | 
						|
			(void) sprintf((char *)buf,
 | 
						|
				".tm unknown .if/.ie form: %s", (char *)lp);
 | 
						|
			lp = buf;
 | 
						|
		}
 | 
						|
	   /*
 | 
						|
	    * Handle conditional.  If case is true, locate predicate.
 | 
						|
	    * If predicate is an .i[ef], process it.
 | 
						|
	    */
 | 
						|
		if (invert)
 | 
						|
			cond = 1 - cond;
 | 
						|
		if (cond && iflen > 0) {
 | 
						|
			lp += iflen;
 | 
						|
			if (regexec(Pat[15].pat, lp))
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
	    /*
 | 
						|
	     * Do argument substitution, as necessary.
 | 
						|
	     */
 | 
						|
		if (cond && regexec(Pat[5].pat, lp)) {      /* "\$[0-9]" ??? */
 | 
						|
			for (s1 = buf;;) {
 | 
						|
				if ((n1 = Pat[5].pat->startp[0] - lp) > 0) {
 | 
						|
					(void) strncpy((char *)s1, (char *)lp,
 | 
						|
						n1);
 | 
						|
					s1 += n1;
 | 
						|
				}
 | 
						|
				*s1 = '\0';
 | 
						|
				lp = Pat[5].pat->endp[0];
 | 
						|
				n1 = (int)(*(lp-1) - '0');
 | 
						|
				if (n1 >= 0 && n1 < nargs) {
 | 
						|
					(void) strcpy((char *)s1,
 | 
						|
						(char *)Args[n1]);
 | 
						|
					s1 += strlen((char *)Args[n1]);
 | 
						|
				}
 | 
						|
				if (*lp == '\0')
 | 
						|
					break;
 | 
						|
				if (regexec(Pat[5].pat, lp) == 0) {
 | 
						|
					(void) strcpy((char *)s1, (char *)lp);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			lp = buf;
 | 
						|
		}
 | 
						|
	    /*
 | 
						|
	     * Check for nroff command.
 | 
						|
	     */
 | 
						|
		if (cond) {
 | 
						|
			cmdl = 0;
 | 
						|
			if (cond && (*lp == '.' || *lp == '\'')) {
 | 
						|
				if ((*cmd = *(lp+1)) != '\0') {
 | 
						|
					cmdl++;
 | 
						|
					if ((*(cmd+1) = *(lp+2)) == ' ')
 | 
						|
						*(cmd+1) = '\0';
 | 
						|
					else
 | 
						|
						cmdl++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			cmd[cmdl] = '\0';
 | 
						|
		}
 | 
						|
		if (cond == 0)
 | 
						|
			i = i;		/* do nothing if condition is false */
 | 
						|
		else if (cmdl == 0 || ((cmdx = Findmacro(cmd, 0)) < 0))
 | 
						|
			Pass2(lp);
 | 
						|
		else if (Sp >= MAXSP) {
 | 
						|
			(void) sprintf((char *)buf, " macro nesting > %d",
 | 
						|
				MAXSP);
 | 
						|
			Error(WARN, LINE, (char *)buf, NULL);
 | 
						|
		} else {
 | 
						|
	    /*
 | 
						|
	     * Stack macros.
 | 
						|
	     */
 | 
						|
		  /*
 | 
						|
		   * Push stack.
 | 
						|
		   */
 | 
						|
			Sp++;
 | 
						|
			Nleftstack[Sp] = nleft;
 | 
						|
			Ptrstack[Sp] = ptr;
 | 
						|
			Mxstack[Sp] = mx;
 | 
						|
			Condstack[Sp] = cond;
 | 
						|
			for (i = 10*Sp, j = 0; j < 10; i++, j++) {
 | 
						|
				Argstack[i] = Args[j];
 | 
						|
				Args[j] = NULL;
 | 
						|
			}
 | 
						|
		   /*
 | 
						|
		    * Start new stack entry.
 | 
						|
		    */
 | 
						|
			mx = cmdx;
 | 
						|
			ptr = Macrotab[mx].bx;
 | 
						|
			cond = 0;
 | 
						|
			nleft = Macrotab[mx].ct;
 | 
						|
			Args[0] = Newstr(cmd);
 | 
						|
		   /*
 | 
						|
		    * Parse arguments.
 | 
						|
		    */
 | 
						|
			for (s1 = lp + cmdl + 1, nargs = 1; nargs < 10;) {
 | 
						|
				while (*s1 && (*s1 == ' ' || *s1 == '\t'))
 | 
						|
					s1++;
 | 
						|
				if (*s1 == '\0')
 | 
						|
					break;
 | 
						|
				if (*s1 == '"') {
 | 
						|
					s1++;
 | 
						|
					quote = 1;
 | 
						|
				} else
 | 
						|
					quote = 0;
 | 
						|
				for (s2 = buf;;) {
 | 
						|
				    if (!quote && (*s1 == ' ' || *s1 == '\t')) {
 | 
						|
					*s2 = '\0';
 | 
						|
					break;
 | 
						|
				    }
 | 
						|
				    if ((*s2 = *s1) == '\0')
 | 
						|
					break;
 | 
						|
				    s1++;
 | 
						|
				    if (quote && *s2 == '"') {
 | 
						|
					*s2 = '\0';
 | 
						|
					break;
 | 
						|
				    }
 | 
						|
				    s2++;
 | 
						|
			    	}
 | 
						|
				if (buf[0])
 | 
						|
					Args[nargs++] = Newstr(buf);
 | 
						|
			}
 | 
						|
			for (i = nargs; i < 10; i++) {
 | 
						|
				Args[i] = NULL;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	    /*
 | 
						|
	     * Unstack completed macros.
 | 
						|
	     */
 | 
						|
		while (nleft <= 0 && Sp >= 0) {
 | 
						|
			nleft = Nleftstack[Sp];
 | 
						|
			mx = Mxstack[Sp];
 | 
						|
			ptr = Ptrstack[Sp];
 | 
						|
			cond = Condstack[Sp];
 | 
						|
			for (i = 10*Sp, j = 0, nargs = -1; j < 10; i++, j++) {
 | 
						|
				Free(&Args[j]);
 | 
						|
				if ((Args[j] = Argstack[i]) != NULL)
 | 
						|
					nargs = j;
 | 
						|
			}
 | 
						|
			Sp--;
 | 
						|
			nargs++;
 | 
						|
		}
 | 
						|
	    /*
 | 
						|
	     * Get next line.
 | 
						|
	     */
 | 
						|
		if (nleft > 0) {
 | 
						|
			lp = Macrotxt[ptr++];
 | 
						|
			nleft--;
 | 
						|
		} else
 | 
						|
			lp = (unsigned char *)"";
 | 
						|
	}
 | 
						|
	(void) sprintf((char *)buf, ".^# %d %s", NR, (char *)Inname);
 | 
						|
	Pass2(buf);
 | 
						|
}
 |