1 /* 2 * expand.c - macro expansion functions for cawf(1) 3 */ 4 5 /* 6 * Copyright (c) 1991 Purdue University Research Foundation, 7 * West Lafayette, Indiana 47907. All rights reserved. 8 * 9 * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue 10 * University Computing Center. Not derived from licensed software; 11 * derived from awf(1) by Henry Spencer of the University of Toronto. 12 * 13 * Permission is granted to anyone to use this software for any 14 * purpose on any computer system, and to alter it and redistribute 15 * it freely, subject to the following restrictions: 16 * 17 * 1. The author is not responsible for any consequences of use of 18 * this software, even if they arise from flaws in it. 19 * 20 * 2. The origin of this software must not be misrepresented, either 21 * by explicit claim or by omission. Credits must appear in the 22 * documentation. 23 * 24 * 3. Altered versions must be plainly marked as such, and must not 25 * be misrepresented as being the original software. Credits must 26 * appear in the documentation. 27 * 28 * 4. This notice may not be removed or altered. 29 */ 30 31 #include "cawf.h" 32 33 /* 34 * Expand(line) - expand macro or if/ie/el line 35 */ 36 37 void 38 Expand(line) 39 unsigned char *line; 40 { 41 unsigned char buf[2*MAXLINE]; /* line buffer */ 42 unsigned char cmd[4]; /* nroff command */ 43 int cmdl; /* command length */ 44 int cmdx; /* cmd index in Macrotab[] */ 45 int cond = 0; /* conditional statuses */ 46 int i, j; /* temporary indexes */ 47 int iflen; /* if statement length */ 48 int invert; /* inversion status */ 49 unsigned char *lp; /* line pointer */ 50 int mx = -1; /* Macrotab[] index */ 51 int n1, n2; /* temporary numbers */ 52 int nargs = 0; /* number of arguments */ 53 int nleft = 0; /* number of macro lines left */ 54 char op; /* comparison operator */ 55 int prevcond; /* previous condition (for else's) */ 56 int ptr = -1; /* Macrotxt[] index */ 57 int quote; /* quoted string status */ 58 unsigned char *s1, *s2; /* temporary string pointers */ 59 60 61 (void) sprintf((char *)buf, ".^= %d %s", NR, (char *)Inname); 62 Pass2(buf); 63 64 for (lp = line; *lp; ) { 65 invert = regexec(Pat[1].pat, lp); 66 prevcond = cond; 67 cond = 0; 68 if (regexec(Pat[0].pat, lp) == 0) { 69 /* 70 * Not conditional: - ! "^[.'](i[ef]|el)" 71 */ 72 cond = 1; 73 iflen = 0; 74 } 75 76 else if (regexec(Pat[2].pat, lp)) { 77 /* 78 * Argument count comparison: - 79 * "^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] " 80 */ 81 iflen = strlen(".if \\n(.$=n ") + invert; 82 s1 = lp + iflen - 3; 83 op = *s1++; 84 if (*s1 == '=' && (op == '>' || op == '<')) { 85 s1++; 86 op = (op == '>') ? 'G' : 'L'; 87 } 88 n1 = (int)(*s1 - '0'); 89 switch (op) { 90 case '=': 91 if ((nargs - 1) == n1) 92 cond = 1; 93 break; 94 case '<': 95 if ((nargs - 1) < n1) 96 cond = 1; 97 break; 98 case '>': 99 if ((nargs - 1) > n1) 100 cond = 1; 101 break; 102 case 'G': /* >= */ 103 if ((nargs - 1) >= n1) 104 cond = 1; 105 break; 106 case 'L': /* <= */ 107 if ((nargs - 1) <= n1) 108 cond = 1; 109 } 110 } 111 112 else if (regexec(Pat[3].pat, lp)) { 113 /* 114 * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' " 115 */ 116 iflen = strlen(".if '\\$n'") + invert; 117 n1 = (int)(*(lp + iflen - 2) - '0'); 118 if (n1 >= 0 && n1 < nargs) 119 s1 = Args[n1]; 120 else 121 s1 = (unsigned char *)""; 122 if ((s2 = (unsigned char *)strchr((char *)lp 123 + iflen, '\'')) 124 != NULL) { 125 n2 = s2 - lp - iflen; 126 if (strncmp((char *)s1, (char *)lp + iflen, n2) 127 == 0) 128 cond = 1; 129 iflen += n2 + 2; 130 } 131 } 132 133 else if (regexec(Pat[4].pat, lp)) { 134 /* 135 * Nroff or troff: - "^[.']i[ef] !?[nt] " 136 */ 137 iflen = strlen(".if n ") + invert; 138 if (*(lp + iflen - 2) == 'n') 139 cond = 1; 140 } 141 142 else if ((*lp == '.' || *lp == '\'') 143 && strncmp((char *)lp+1, "el ", 3) == 0) { 144 /* 145 * Else clause: - "^[.']el " 146 */ 147 cond = 1 - prevcond; 148 iflen = 4; 149 } 150 151 else { 152 /* 153 * Unknown conditional: 154 */ 155 cond = 1; 156 iflen = 0; 157 (void) sprintf((char *)buf, 158 ".tm unknown .if/.ie form: %s", (char *)lp); 159 lp = buf; 160 } 161 /* 162 * Handle conditional. If case is true, locate predicate. 163 * If predicate is an .i[ef], process it. 164 */ 165 if (invert) 166 cond = 1 - cond; 167 if (cond && iflen > 0) { 168 lp += iflen; 169 if (regexec(Pat[15].pat, lp)) 170 continue; 171 } 172 /* 173 * Do argument substitution, as necessary. 174 */ 175 if (cond && regexec(Pat[5].pat, lp)) { /* "\$[0-9]" ??? */ 176 for (s1 = buf;;) { 177 if ((n1 = Pat[5].pat->startp[0] - lp) > 0) { 178 (void) strncpy((char *)s1, (char *)lp, 179 n1); 180 s1 += n1; 181 } 182 *s1 = '\0'; 183 lp = Pat[5].pat->endp[0]; 184 n1 = (int)(*(lp-1) - '0'); 185 if (n1 >= 0 && n1 < nargs) { 186 (void) strcpy((char *)s1, 187 (char *)Args[n1]); 188 s1 += strlen((char *)Args[n1]); 189 } 190 if (*lp == '\0') 191 break; 192 if (regexec(Pat[5].pat, lp) == 0) { 193 (void) strcpy((char *)s1, (char *)lp); 194 break; 195 } 196 } 197 lp = buf; 198 } 199 /* 200 * Check for nroff command. 201 */ 202 if (cond) { 203 cmdl = 0; 204 if (cond && (*lp == '.' || *lp == '\'')) { 205 if ((*cmd = *(lp+1)) != '\0') { 206 cmdl++; 207 if ((*(cmd+1) = *(lp+2)) == ' ') 208 *(cmd+1) = '\0'; 209 else 210 cmdl++; 211 } 212 } 213 cmd[cmdl] = '\0'; 214 } 215 if (cond == 0) 216 i = i; /* do nothing if condition is false */ 217 else if (cmdl == 0 || ((cmdx = Findmacro(cmd, 0)) < 0)) 218 Pass2(lp); 219 else if (Sp >= MAXSP) { 220 (void) sprintf((char *)buf, " macro nesting > %d", 221 MAXSP); 222 Error(WARN, LINE, (char *)buf, NULL); 223 } else { 224 /* 225 * Stack macros. 226 */ 227 /* 228 * Push stack. 229 */ 230 Sp++; 231 Nleftstack[Sp] = nleft; 232 Ptrstack[Sp] = ptr; 233 Mxstack[Sp] = mx; 234 Condstack[Sp] = cond; 235 for (i = 10*Sp, j = 0; j < 10; i++, j++) { 236 Argstack[i] = Args[j]; 237 Args[j] = NULL; 238 } 239 /* 240 * Start new stack entry. 241 */ 242 mx = cmdx; 243 ptr = Macrotab[mx].bx; 244 cond = 0; 245 nleft = Macrotab[mx].ct; 246 Args[0] = Newstr(cmd); 247 /* 248 * Parse arguments. 249 */ 250 for (s1 = lp + cmdl + 1, nargs = 1; nargs < 10;) { 251 while (*s1 && (*s1 == ' ' || *s1 == '\t')) 252 s1++; 253 if (*s1 == '\0') 254 break; 255 if (*s1 == '"') { 256 s1++; 257 quote = 1; 258 } else 259 quote = 0; 260 for (s2 = buf;;) { 261 if (!quote && (*s1 == ' ' || *s1 == '\t')) { 262 *s2 = '\0'; 263 break; 264 } 265 if ((*s2 = *s1) == '\0') 266 break; 267 s1++; 268 if (quote && *s2 == '"') { 269 *s2 = '\0'; 270 break; 271 } 272 s2++; 273 } 274 if (buf[0]) 275 Args[nargs++] = Newstr(buf); 276 } 277 for (i = nargs; i < 10; i++) { 278 Args[i] = NULL; 279 } 280 } 281 /* 282 * Unstack completed macros. 283 */ 284 while (nleft <= 0 && Sp >= 0) { 285 nleft = Nleftstack[Sp]; 286 mx = Mxstack[Sp]; 287 ptr = Ptrstack[Sp]; 288 cond = Condstack[Sp]; 289 for (i = 10*Sp, j = 0, nargs = -1; j < 10; i++, j++) { 290 Free(&Args[j]); 291 if ((Args[j] = Argstack[i]) != NULL) 292 nargs = j; 293 } 294 Sp--; 295 nargs++; 296 } 297 /* 298 * Get next line. 299 */ 300 if (nleft > 0) { 301 lp = Macrotxt[ptr++]; 302 nleft--; 303 } else 304 lp = (unsigned char *)""; 305 } 306 (void) sprintf((char *)buf, ".^# %d %s", NR, (char *)Inname); 307 Pass2(buf); 308 } 309