/* * 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 , 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); }