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