xref: /minix3/minix/commands/cawf/expand.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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