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);
 | |
| }
 | 
