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