1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc * expand.c - macro expansion functions for cawf(1)
3433d6423SLionel Sambuc */
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc /*
6433d6423SLionel Sambuc * Copyright (c) 1991 Purdue University Research Foundation,
7433d6423SLionel Sambuc * West Lafayette, Indiana 47907. All rights reserved.
8433d6423SLionel Sambuc *
9433d6423SLionel Sambuc * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
10433d6423SLionel Sambuc * University Computing Center. Not derived from licensed software;
11433d6423SLionel Sambuc * derived from awf(1) by Henry Spencer of the University of Toronto.
12433d6423SLionel Sambuc *
13433d6423SLionel Sambuc * Permission is granted to anyone to use this software for any
14433d6423SLionel Sambuc * purpose on any computer system, and to alter it and redistribute
15433d6423SLionel Sambuc * it freely, subject to the following restrictions:
16433d6423SLionel Sambuc *
17433d6423SLionel Sambuc * 1. The author is not responsible for any consequences of use of
18433d6423SLionel Sambuc * this software, even if they arise from flaws in it.
19433d6423SLionel Sambuc *
20433d6423SLionel Sambuc * 2. The origin of this software must not be misrepresented, either
21433d6423SLionel Sambuc * by explicit claim or by omission. Credits must appear in the
22433d6423SLionel Sambuc * documentation.
23433d6423SLionel Sambuc *
24433d6423SLionel Sambuc * 3. Altered versions must be plainly marked as such, and must not
25433d6423SLionel Sambuc * be misrepresented as being the original software. Credits must
26433d6423SLionel Sambuc * appear in the documentation.
27433d6423SLionel Sambuc *
28433d6423SLionel Sambuc * 4. This notice may not be removed or altered.
29433d6423SLionel Sambuc */
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc #include "cawf.h"
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc /*
34433d6423SLionel Sambuc * Expand(line) - expand macro or if/ie/el line
35433d6423SLionel Sambuc */
36433d6423SLionel Sambuc
Expand(unsigned char * line)37*d9494baaSJacob Adams void Expand(unsigned char *line) {
38*d9494baaSJacob Adams
39433d6423SLionel Sambuc unsigned char buf[2*MAXLINE]; /* line buffer */
40433d6423SLionel Sambuc unsigned char cmd[4]; /* nroff command */
41433d6423SLionel Sambuc int cmdl; /* command length */
42433d6423SLionel Sambuc int cmdx; /* cmd index in Macrotab[] */
43433d6423SLionel Sambuc int cond = 0; /* conditional statuses */
44433d6423SLionel Sambuc int i, j; /* temporary indexes */
45433d6423SLionel Sambuc int iflen; /* if statement length */
46433d6423SLionel Sambuc int invert; /* inversion status */
47433d6423SLionel Sambuc unsigned char *lp; /* line pointer */
48433d6423SLionel Sambuc int mx = -1; /* Macrotab[] index */
49433d6423SLionel Sambuc int n1, n2; /* temporary numbers */
50433d6423SLionel Sambuc int nargs = 0; /* number of arguments */
51433d6423SLionel Sambuc int nleft = 0; /* number of macro lines left */
52433d6423SLionel Sambuc char op; /* comparison operator */
53433d6423SLionel Sambuc int prevcond; /* previous condition (for else's) */
54433d6423SLionel Sambuc int ptr = -1; /* Macrotxt[] index */
55433d6423SLionel Sambuc int quote; /* quoted string status */
56433d6423SLionel Sambuc unsigned char *s1, *s2; /* temporary string pointers */
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc (void) sprintf((char *)buf, ".^= %d %s", NR, (char *)Inname);
60433d6423SLionel Sambuc Pass2(buf);
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc for (lp = line; *lp; ) {
63433d6423SLionel Sambuc invert = regexec(Pat[1].pat, lp);
64433d6423SLionel Sambuc prevcond = cond;
65433d6423SLionel Sambuc cond = 0;
66433d6423SLionel Sambuc if (regexec(Pat[0].pat, lp) == 0) {
67433d6423SLionel Sambuc /*
68433d6423SLionel Sambuc * Not conditional: - ! "^[.'](i[ef]|el)"
69433d6423SLionel Sambuc */
70433d6423SLionel Sambuc cond = 1;
71433d6423SLionel Sambuc iflen = 0;
72433d6423SLionel Sambuc }
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc else if (regexec(Pat[2].pat, lp)) {
75433d6423SLionel Sambuc /*
76433d6423SLionel Sambuc * Argument count comparison: -
77433d6423SLionel Sambuc * "^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] "
78433d6423SLionel Sambuc */
79433d6423SLionel Sambuc iflen = strlen(".if \\n(.$=n ") + invert;
80433d6423SLionel Sambuc s1 = lp + iflen - 3;
81433d6423SLionel Sambuc op = *s1++;
82433d6423SLionel Sambuc if (*s1 == '=' && (op == '>' || op == '<')) {
83433d6423SLionel Sambuc s1++;
84433d6423SLionel Sambuc op = (op == '>') ? 'G' : 'L';
85433d6423SLionel Sambuc }
86433d6423SLionel Sambuc n1 = (int)(*s1 - '0');
87433d6423SLionel Sambuc switch (op) {
88433d6423SLionel Sambuc case '=':
89433d6423SLionel Sambuc if ((nargs - 1) == n1)
90433d6423SLionel Sambuc cond = 1;
91433d6423SLionel Sambuc break;
92433d6423SLionel Sambuc case '<':
93433d6423SLionel Sambuc if ((nargs - 1) < n1)
94433d6423SLionel Sambuc cond = 1;
95433d6423SLionel Sambuc break;
96433d6423SLionel Sambuc case '>':
97433d6423SLionel Sambuc if ((nargs - 1) > n1)
98433d6423SLionel Sambuc cond = 1;
99433d6423SLionel Sambuc break;
100433d6423SLionel Sambuc case 'G': /* >= */
101433d6423SLionel Sambuc if ((nargs - 1) >= n1)
102433d6423SLionel Sambuc cond = 1;
103433d6423SLionel Sambuc break;
104433d6423SLionel Sambuc case 'L': /* <= */
105433d6423SLionel Sambuc if ((nargs - 1) <= n1)
106433d6423SLionel Sambuc cond = 1;
107433d6423SLionel Sambuc }
108433d6423SLionel Sambuc }
109433d6423SLionel Sambuc
110433d6423SLionel Sambuc else if (regexec(Pat[3].pat, lp)) {
111433d6423SLionel Sambuc /*
112433d6423SLionel Sambuc * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' "
113433d6423SLionel Sambuc */
114433d6423SLionel Sambuc iflen = strlen(".if '\\$n'") + invert;
115433d6423SLionel Sambuc n1 = (int)(*(lp + iflen - 2) - '0');
116433d6423SLionel Sambuc if (n1 >= 0 && n1 < nargs)
117433d6423SLionel Sambuc s1 = Args[n1];
118433d6423SLionel Sambuc else
119433d6423SLionel Sambuc s1 = (unsigned char *)"";
120433d6423SLionel Sambuc if ((s2 = (unsigned char *)strchr((char *)lp
121433d6423SLionel Sambuc + iflen, '\''))
122433d6423SLionel Sambuc != NULL) {
123433d6423SLionel Sambuc n2 = s2 - lp - iflen;
124433d6423SLionel Sambuc if (strncmp((char *)s1, (char *)lp + iflen, n2)
125433d6423SLionel Sambuc == 0)
126433d6423SLionel Sambuc cond = 1;
127433d6423SLionel Sambuc iflen += n2 + 2;
128433d6423SLionel Sambuc }
129433d6423SLionel Sambuc }
130433d6423SLionel Sambuc
131433d6423SLionel Sambuc else if (regexec(Pat[4].pat, lp)) {
132433d6423SLionel Sambuc /*
133433d6423SLionel Sambuc * Nroff or troff: - "^[.']i[ef] !?[nt] "
134433d6423SLionel Sambuc */
135433d6423SLionel Sambuc iflen = strlen(".if n ") + invert;
136433d6423SLionel Sambuc if (*(lp + iflen - 2) == 'n')
137433d6423SLionel Sambuc cond = 1;
138433d6423SLionel Sambuc }
139433d6423SLionel Sambuc
140433d6423SLionel Sambuc else if ((*lp == '.' || *lp == '\'')
141433d6423SLionel Sambuc && strncmp((char *)lp+1, "el ", 3) == 0) {
142433d6423SLionel Sambuc /*
143433d6423SLionel Sambuc * Else clause: - "^[.']el "
144433d6423SLionel Sambuc */
145433d6423SLionel Sambuc cond = 1 - prevcond;
146433d6423SLionel Sambuc iflen = 4;
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc else {
150433d6423SLionel Sambuc /*
151433d6423SLionel Sambuc * Unknown conditional:
152433d6423SLionel Sambuc */
153433d6423SLionel Sambuc cond = 1;
154433d6423SLionel Sambuc iflen = 0;
155433d6423SLionel Sambuc (void) sprintf((char *)buf,
156433d6423SLionel Sambuc ".tm unknown .if/.ie form: %s", (char *)lp);
157433d6423SLionel Sambuc lp = buf;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc /*
160433d6423SLionel Sambuc * Handle conditional. If case is true, locate predicate.
161433d6423SLionel Sambuc * If predicate is an .i[ef], process it.
162433d6423SLionel Sambuc */
163433d6423SLionel Sambuc if (invert)
164433d6423SLionel Sambuc cond = 1 - cond;
165433d6423SLionel Sambuc if (cond && iflen > 0) {
166433d6423SLionel Sambuc lp += iflen;
167433d6423SLionel Sambuc if (regexec(Pat[15].pat, lp))
168433d6423SLionel Sambuc continue;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc /*
171433d6423SLionel Sambuc * Do argument substitution, as necessary.
172433d6423SLionel Sambuc */
173433d6423SLionel Sambuc if (cond && regexec(Pat[5].pat, lp)) { /* "\$[0-9]" ??? */
174433d6423SLionel Sambuc for (s1 = buf;;) {
175433d6423SLionel Sambuc if ((n1 = Pat[5].pat->startp[0] - lp) > 0) {
176433d6423SLionel Sambuc (void) strncpy((char *)s1, (char *)lp,
177433d6423SLionel Sambuc n1);
178433d6423SLionel Sambuc s1 += n1;
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc *s1 = '\0';
181433d6423SLionel Sambuc lp = Pat[5].pat->endp[0];
182433d6423SLionel Sambuc n1 = (int)(*(lp-1) - '0');
183433d6423SLionel Sambuc if (n1 >= 0 && n1 < nargs) {
184433d6423SLionel Sambuc (void) strcpy((char *)s1,
185433d6423SLionel Sambuc (char *)Args[n1]);
186433d6423SLionel Sambuc s1 += strlen((char *)Args[n1]);
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc if (*lp == '\0')
189433d6423SLionel Sambuc break;
190433d6423SLionel Sambuc if (regexec(Pat[5].pat, lp) == 0) {
191433d6423SLionel Sambuc (void) strcpy((char *)s1, (char *)lp);
192433d6423SLionel Sambuc break;
193433d6423SLionel Sambuc }
194433d6423SLionel Sambuc }
195433d6423SLionel Sambuc lp = buf;
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc /*
198433d6423SLionel Sambuc * Check for nroff command.
199433d6423SLionel Sambuc */
200433d6423SLionel Sambuc if (cond) {
201433d6423SLionel Sambuc cmdl = 0;
202433d6423SLionel Sambuc if (cond && (*lp == '.' || *lp == '\'')) {
203433d6423SLionel Sambuc if ((*cmd = *(lp+1)) != '\0') {
204433d6423SLionel Sambuc cmdl++;
205433d6423SLionel Sambuc if ((*(cmd+1) = *(lp+2)) == ' ')
206433d6423SLionel Sambuc *(cmd+1) = '\0';
207433d6423SLionel Sambuc else
208433d6423SLionel Sambuc cmdl++;
209433d6423SLionel Sambuc }
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc cmd[cmdl] = '\0';
212433d6423SLionel Sambuc }
213433d6423SLionel Sambuc if (cond == 0)
214433d6423SLionel Sambuc i = i; /* do nothing if condition is false */
215433d6423SLionel Sambuc else if (cmdl == 0 || ((cmdx = Findmacro(cmd, 0)) < 0))
216433d6423SLionel Sambuc Pass2(lp);
217433d6423SLionel Sambuc else if (Sp >= MAXSP) {
218433d6423SLionel Sambuc (void) sprintf((char *)buf, " macro nesting > %d",
219433d6423SLionel Sambuc MAXSP);
220433d6423SLionel Sambuc Error(WARN, LINE, (char *)buf, NULL);
221433d6423SLionel Sambuc } else {
222433d6423SLionel Sambuc /*
223433d6423SLionel Sambuc * Stack macros.
224433d6423SLionel Sambuc */
225433d6423SLionel Sambuc /*
226433d6423SLionel Sambuc * Push stack.
227433d6423SLionel Sambuc */
228433d6423SLionel Sambuc Sp++;
229433d6423SLionel Sambuc Nleftstack[Sp] = nleft;
230433d6423SLionel Sambuc Ptrstack[Sp] = ptr;
231433d6423SLionel Sambuc Mxstack[Sp] = mx;
232433d6423SLionel Sambuc Condstack[Sp] = cond;
233433d6423SLionel Sambuc for (i = 10*Sp, j = 0; j < 10; i++, j++) {
234433d6423SLionel Sambuc Argstack[i] = Args[j];
235433d6423SLionel Sambuc Args[j] = NULL;
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc /*
238433d6423SLionel Sambuc * Start new stack entry.
239433d6423SLionel Sambuc */
240433d6423SLionel Sambuc mx = cmdx;
241433d6423SLionel Sambuc ptr = Macrotab[mx].bx;
242433d6423SLionel Sambuc cond = 0;
243433d6423SLionel Sambuc nleft = Macrotab[mx].ct;
244433d6423SLionel Sambuc Args[0] = Newstr(cmd);
245433d6423SLionel Sambuc /*
246433d6423SLionel Sambuc * Parse arguments.
247433d6423SLionel Sambuc */
248433d6423SLionel Sambuc for (s1 = lp + cmdl + 1, nargs = 1; nargs < 10;) {
249433d6423SLionel Sambuc while (*s1 && (*s1 == ' ' || *s1 == '\t'))
250433d6423SLionel Sambuc s1++;
251433d6423SLionel Sambuc if (*s1 == '\0')
252433d6423SLionel Sambuc break;
253433d6423SLionel Sambuc if (*s1 == '"') {
254433d6423SLionel Sambuc s1++;
255433d6423SLionel Sambuc quote = 1;
256433d6423SLionel Sambuc } else
257433d6423SLionel Sambuc quote = 0;
258433d6423SLionel Sambuc for (s2 = buf;;) {
259433d6423SLionel Sambuc if (!quote && (*s1 == ' ' || *s1 == '\t')) {
260433d6423SLionel Sambuc *s2 = '\0';
261433d6423SLionel Sambuc break;
262433d6423SLionel Sambuc }
263433d6423SLionel Sambuc if ((*s2 = *s1) == '\0')
264433d6423SLionel Sambuc break;
265433d6423SLionel Sambuc s1++;
266433d6423SLionel Sambuc if (quote && *s2 == '"') {
267433d6423SLionel Sambuc *s2 = '\0';
268433d6423SLionel Sambuc break;
269433d6423SLionel Sambuc }
270433d6423SLionel Sambuc s2++;
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc if (buf[0])
273433d6423SLionel Sambuc Args[nargs++] = Newstr(buf);
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc for (i = nargs; i < 10; i++) {
276433d6423SLionel Sambuc Args[i] = NULL;
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc }
279433d6423SLionel Sambuc /*
280433d6423SLionel Sambuc * Unstack completed macros.
281433d6423SLionel Sambuc */
282433d6423SLionel Sambuc while (nleft <= 0 && Sp >= 0) {
283433d6423SLionel Sambuc nleft = Nleftstack[Sp];
284433d6423SLionel Sambuc mx = Mxstack[Sp];
285433d6423SLionel Sambuc ptr = Ptrstack[Sp];
286433d6423SLionel Sambuc cond = Condstack[Sp];
287433d6423SLionel Sambuc for (i = 10*Sp, j = 0, nargs = -1; j < 10; i++, j++) {
288433d6423SLionel Sambuc Free(&Args[j]);
289433d6423SLionel Sambuc if ((Args[j] = Argstack[i]) != NULL)
290433d6423SLionel Sambuc nargs = j;
291433d6423SLionel Sambuc }
292433d6423SLionel Sambuc Sp--;
293433d6423SLionel Sambuc nargs++;
294433d6423SLionel Sambuc }
295433d6423SLionel Sambuc /*
296433d6423SLionel Sambuc * Get next line.
297433d6423SLionel Sambuc */
298433d6423SLionel Sambuc if (nleft > 0) {
299433d6423SLionel Sambuc lp = Macrotxt[ptr++];
300433d6423SLionel Sambuc nleft--;
301433d6423SLionel Sambuc } else
302433d6423SLionel Sambuc lp = (unsigned char *)"";
303433d6423SLionel Sambuc }
304433d6423SLionel Sambuc (void) sprintf((char *)buf, ".^# %d %s", NR, (char *)Inname);
305433d6423SLionel Sambuc Pass2(buf);
306433d6423SLionel Sambuc }
307