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 Expand(unsigned char *line) { 38 39 unsigned char buf[2*MAXLINE]; /* line buffer */ 40 unsigned char cmd[4]; /* nroff command */ 41 int cmdl; /* command length */ 42 int cmdx; /* cmd index in Macrotab[] */ 43 int cond = 0; /* conditional statuses */ 44 int i, j; /* temporary indexes */ 45 int iflen; /* if statement length */ 46 int invert; /* inversion status */ 47 unsigned char *lp; /* line pointer */ 48 int mx = -1; /* Macrotab[] index */ 49 int n1, n2; /* temporary numbers */ 50 int nargs = 0; /* number of arguments */ 51 int nleft = 0; /* number of macro lines left */ 52 char op; /* comparison operator */ 53 int prevcond; /* previous condition (for else's) */ 54 int ptr = -1; /* Macrotxt[] index */ 55 int quote; /* quoted string status */ 56 unsigned char *s1, *s2; /* temporary string pointers */ 57 58 59 (void) sprintf((char *)buf, ".^= %d %s", NR, (char *)Inname); 60 Pass2(buf); 61 62 for (lp = line; *lp; ) { 63 invert = regexec(Pat[1].pat, lp); 64 prevcond = cond; 65 cond = 0; 66 if (regexec(Pat[0].pat, lp) == 0) { 67 /* 68 * Not conditional: - ! "^[.'](i[ef]|el)" 69 */ 70 cond = 1; 71 iflen = 0; 72 } 73 74 else if (regexec(Pat[2].pat, lp)) { 75 /* 76 * Argument count comparison: - 77 * "^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] " 78 */ 79 iflen = strlen(".if \\n(.$=n ") + invert; 80 s1 = lp + iflen - 3; 81 op = *s1++; 82 if (*s1 == '=' && (op == '>' || op == '<')) { 83 s1++; 84 op = (op == '>') ? 'G' : 'L'; 85 } 86 n1 = (int)(*s1 - '0'); 87 switch (op) { 88 case '=': 89 if ((nargs - 1) == n1) 90 cond = 1; 91 break; 92 case '<': 93 if ((nargs - 1) < n1) 94 cond = 1; 95 break; 96 case '>': 97 if ((nargs - 1) > n1) 98 cond = 1; 99 break; 100 case 'G': /* >= */ 101 if ((nargs - 1) >= n1) 102 cond = 1; 103 break; 104 case 'L': /* <= */ 105 if ((nargs - 1) <= n1) 106 cond = 1; 107 } 108 } 109 110 else if (regexec(Pat[3].pat, lp)) { 111 /* 112 * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' " 113 */ 114 iflen = strlen(".if '\\$n'") + invert; 115 n1 = (int)(*(lp + iflen - 2) - '0'); 116 if (n1 >= 0 && n1 < nargs) 117 s1 = Args[n1]; 118 else 119 s1 = (unsigned char *)""; 120 if ((s2 = (unsigned char *)strchr((char *)lp 121 + iflen, '\'')) 122 != NULL) { 123 n2 = s2 - lp - iflen; 124 if (strncmp((char *)s1, (char *)lp + iflen, n2) 125 == 0) 126 cond = 1; 127 iflen += n2 + 2; 128 } 129 } 130 131 else if (regexec(Pat[4].pat, lp)) { 132 /* 133 * Nroff or troff: - "^[.']i[ef] !?[nt] " 134 */ 135 iflen = strlen(".if n ") + invert; 136 if (*(lp + iflen - 2) == 'n') 137 cond = 1; 138 } 139 140 else if ((*lp == '.' || *lp == '\'') 141 && strncmp((char *)lp+1, "el ", 3) == 0) { 142 /* 143 * Else clause: - "^[.']el " 144 */ 145 cond = 1 - prevcond; 146 iflen = 4; 147 } 148 149 else { 150 /* 151 * Unknown conditional: 152 */ 153 cond = 1; 154 iflen = 0; 155 (void) sprintf((char *)buf, 156 ".tm unknown .if/.ie form: %s", (char *)lp); 157 lp = buf; 158 } 159 /* 160 * Handle conditional. If case is true, locate predicate. 161 * If predicate is an .i[ef], process it. 162 */ 163 if (invert) 164 cond = 1 - cond; 165 if (cond && iflen > 0) { 166 lp += iflen; 167 if (regexec(Pat[15].pat, lp)) 168 continue; 169 } 170 /* 171 * Do argument substitution, as necessary. 172 */ 173 if (cond && regexec(Pat[5].pat, lp)) { /* "\$[0-9]" ??? */ 174 for (s1 = buf;;) { 175 if ((n1 = Pat[5].pat->startp[0] - lp) > 0) { 176 (void) strncpy((char *)s1, (char *)lp, 177 n1); 178 s1 += n1; 179 } 180 *s1 = '\0'; 181 lp = Pat[5].pat->endp[0]; 182 n1 = (int)(*(lp-1) - '0'); 183 if (n1 >= 0 && n1 < nargs) { 184 (void) strcpy((char *)s1, 185 (char *)Args[n1]); 186 s1 += strlen((char *)Args[n1]); 187 } 188 if (*lp == '\0') 189 break; 190 if (regexec(Pat[5].pat, lp) == 0) { 191 (void) strcpy((char *)s1, (char *)lp); 192 break; 193 } 194 } 195 lp = buf; 196 } 197 /* 198 * Check for nroff command. 199 */ 200 if (cond) { 201 cmdl = 0; 202 if (cond && (*lp == '.' || *lp == '\'')) { 203 if ((*cmd = *(lp+1)) != '\0') { 204 cmdl++; 205 if ((*(cmd+1) = *(lp+2)) == ' ') 206 *(cmd+1) = '\0'; 207 else 208 cmdl++; 209 } 210 } 211 cmd[cmdl] = '\0'; 212 } 213 if (cond == 0) 214 i = i; /* do nothing if condition is false */ 215 else if (cmdl == 0 || ((cmdx = Findmacro(cmd, 0)) < 0)) 216 Pass2(lp); 217 else if (Sp >= MAXSP) { 218 (void) sprintf((char *)buf, " macro nesting > %d", 219 MAXSP); 220 Error(WARN, LINE, (char *)buf, NULL); 221 } else { 222 /* 223 * Stack macros. 224 */ 225 /* 226 * Push stack. 227 */ 228 Sp++; 229 Nleftstack[Sp] = nleft; 230 Ptrstack[Sp] = ptr; 231 Mxstack[Sp] = mx; 232 Condstack[Sp] = cond; 233 for (i = 10*Sp, j = 0; j < 10; i++, j++) { 234 Argstack[i] = Args[j]; 235 Args[j] = NULL; 236 } 237 /* 238 * Start new stack entry. 239 */ 240 mx = cmdx; 241 ptr = Macrotab[mx].bx; 242 cond = 0; 243 nleft = Macrotab[mx].ct; 244 Args[0] = Newstr(cmd); 245 /* 246 * Parse arguments. 247 */ 248 for (s1 = lp + cmdl + 1, nargs = 1; nargs < 10;) { 249 while (*s1 && (*s1 == ' ' || *s1 == '\t')) 250 s1++; 251 if (*s1 == '\0') 252 break; 253 if (*s1 == '"') { 254 s1++; 255 quote = 1; 256 } else 257 quote = 0; 258 for (s2 = buf;;) { 259 if (!quote && (*s1 == ' ' || *s1 == '\t')) { 260 *s2 = '\0'; 261 break; 262 } 263 if ((*s2 = *s1) == '\0') 264 break; 265 s1++; 266 if (quote && *s2 == '"') { 267 *s2 = '\0'; 268 break; 269 } 270 s2++; 271 } 272 if (buf[0]) 273 Args[nargs++] = Newstr(buf); 274 } 275 for (i = nargs; i < 10; i++) { 276 Args[i] = NULL; 277 } 278 } 279 /* 280 * Unstack completed macros. 281 */ 282 while (nleft <= 0 && Sp >= 0) { 283 nleft = Nleftstack[Sp]; 284 mx = Mxstack[Sp]; 285 ptr = Ptrstack[Sp]; 286 cond = Condstack[Sp]; 287 for (i = 10*Sp, j = 0, nargs = -1; j < 10; i++, j++) { 288 Free(&Args[j]); 289 if ((Args[j] = Argstack[i]) != NULL) 290 nargs = j; 291 } 292 Sp--; 293 nargs++; 294 } 295 /* 296 * Get next line. 297 */ 298 if (nleft > 0) { 299 lp = Macrotxt[ptr++]; 300 nleft--; 301 } else 302 lp = (unsigned char *)""; 303 } 304 (void) sprintf((char *)buf, ".^# %d %s", NR, (char *)Inname); 305 Pass2(buf); 306 } 307