xref: /netbsd-src/usr.bin/m4/eval.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ozan Yigit.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char sccsid[] = "@(#)eval.c	5.4 (Berkeley) 2/26/91";
39 #endif /* not lint */
40 
41 /*
42  * eval.c
43  * Facility: m4 macro processor
44  * by: oz
45  */
46 
47 #include <unistd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include "mdef.h"
52 #include "extr.h"
53 
54 extern ndptr lookup();
55 
56 /*
57  * eval - evaluate built-in macros.
58  *	  argc - number of elements in argv.
59  *	  argv - element vector :
60  *			argv[0] = definition of a user
61  *				  macro or nil if built-in.
62  *			argv[1] = name of the macro or
63  *				  built-in.
64  *			argv[2] = parameters to user-defined
65  *			   .	  macro or built-in.
66  *			   .
67  *
68  * Note that the minimum value for argc is 3. A call in the form
69  * of macro-or-builtin() will result in:
70  *			argv[0] = nullstr
71  *			argv[1] = macro-or-builtin
72  *			argv[2] = nullstr
73  *
74  */
75 
76 eval (argv, argc, td)
77 register char *argv[];
78 register int argc;
79 register int  td;
80 {
81 	register int c, n;
82 	static int sysval;
83 
84 #ifdef DEBUG
85 	printf("argc = %d\n", argc);
86 	for (n = 0; n < argc; n++)
87 		printf("argv[%d] = %s\n", n, argv[n]);
88 #endif
89 	/*
90 	 * if argc == 3 and argv[2] is null,
91 	 * then we have macro-or-builtin() type call.
92 	 * We adjust argc to avoid further checking..
93 	 *
94 	 */
95 	if (argc == 3 && !*(argv[2]))
96 		argc--;
97 
98 	switch (td & ~STATIC) {
99 
100 	case DEFITYPE:
101 		if (argc > 2)
102 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
103 		break;
104 
105 	case PUSDTYPE:
106 		if (argc > 2)
107 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
108 		break;
109 
110 	case DUMPTYPE:
111 		dodump(argv, argc);
112 		break;
113 
114 	case EXPRTYPE:
115 		/*
116 		 * doexpr - evaluate arithmetic expression
117 		 *
118 		 */
119 		if (argc > 2)
120 			pbnum(expr(argv[2]));
121 		break;
122 
123 	case IFELTYPE:
124 		if (argc > 4)
125 			doifelse(argv, argc);
126 		break;
127 
128 	case IFDFTYPE:
129 		/*
130 		 * doifdef - select one of two alternatives based
131 		 *	     on the existence of another definition
132 		 */
133 		if (argc > 3) {
134 			if (lookup(argv[2]) != nil)
135 				pbstr(argv[3]);
136 			else if (argc > 4)
137 				pbstr(argv[4]);
138 		}
139 		break;
140 
141 	case LENGTYPE:
142 		/*
143 		 * dolen - find the length of the argument
144 		 *
145 		 */
146 		if (argc > 2)
147 			pbnum((argc > 2) ? strlen(argv[2]) : 0);
148 		break;
149 
150 	case INCRTYPE:
151 		/*
152 		 * doincr - increment the value of the argument
153 		 *
154 		 */
155 		if (argc > 2)
156 			pbnum(atoi(argv[2]) + 1);
157 		break;
158 
159 	case DECRTYPE:
160 		/*
161 		 * dodecr - decrement the value of the argument
162 		 *
163 		 */
164 		if (argc > 2)
165 			pbnum(atoi(argv[2]) - 1);
166 		break;
167 
168 	case SYSCTYPE:
169 		/*
170 		 * dosys - execute system command
171 		 *
172 		 */
173 		if (argc > 2)
174 			sysval = system(argv[2]);
175 		break;
176 
177 	case SYSVTYPE:
178 		/*
179 		 * dosysval - return value of the last system call.
180 		 *
181 		 */
182 		pbnum(sysval);
183 		break;
184 
185 	case INCLTYPE:
186 		if (argc > 2)
187 			if (!doincl(argv[2])) {
188 				fprintf(stderr,"m4: %s: ",argv[2]);
189 				error("cannot open for read.");
190 			}
191 		break;
192 
193 	case SINCTYPE:
194 		if (argc > 2)
195 			(void) doincl(argv[2]);
196 		break;
197 #ifdef EXTENDED
198 	case PASTTYPE:
199 		if (argc > 2)
200 			if (!dopaste(argv[2])) {
201 				fprintf(stderr,"m4: %s: ",argv[2]);
202 				error("cannot open for read.");
203 			}
204 		break;
205 
206 	case SPASTYPE:
207 		if (argc > 2)
208 			(void) dopaste(argv[2]);
209 		break;
210 #endif
211 	case CHNQTYPE:
212 		dochq(argv, argc);
213 		break;
214 
215 	case CHNCTYPE:
216 		dochc(argv, argc);
217 		break;
218 
219 	case SUBSTYPE:
220 		/*
221 		 * dosub - select substring
222 		 *
223 		 */
224 		if (argc > 3)
225 			dosub(argv,argc);
226 		break;
227 
228 	case SHIFTYPE:
229 		/*
230 		 * doshift - push back all arguments except the
231 		 *	     first one (i.e. skip argv[2])
232 		 */
233 		if (argc > 3) {
234 			for (n = argc-1; n > 3; n--) {
235 				putback(rquote);
236 				pbstr(argv[n]);
237 				putback(lquote);
238 				putback(',');
239 			}
240 			putback(rquote);
241 			pbstr(argv[3]);
242 			putback(lquote);
243 		}
244 		break;
245 
246 	case DIVRTYPE:
247 		if (argc > 2 && (n = atoi(argv[2])) != 0)
248 			dodiv(n);
249 		else {
250 			active = stdout;
251 			oindex = 0;
252 		}
253 		break;
254 
255 	case UNDVTYPE:
256 		doundiv(argv, argc);
257 		break;
258 
259 	case DIVNTYPE:
260 		/*
261 		 * dodivnum - return the number of current
262 		 * output diversion
263 		 *
264 		 */
265 		pbnum(oindex);
266 		break;
267 
268 	case UNDFTYPE:
269 		/*
270 		 * doundefine - undefine a previously defined
271 		 *		macro(s) or m4 keyword(s).
272 		 */
273 		if (argc > 2)
274 			for (n = 2; n < argc; n++)
275 				remhash(argv[n], ALL);
276 		break;
277 
278 	case POPDTYPE:
279 		/*
280 		 * dopopdef - remove the topmost definitions of
281 		 *	      macro(s) or m4 keyword(s).
282 		 */
283 		if (argc > 2)
284 			for (n = 2; n < argc; n++)
285 				remhash(argv[n], TOP);
286 		break;
287 
288 	case MKTMTYPE:
289 		/*
290 		 * dotemp - create a temporary file
291 		 *
292 		 */
293 		if (argc > 2)
294 			pbstr(mktemp(argv[2]));
295 		break;
296 
297 	case TRNLTYPE:
298 		/*
299 		 * dotranslit - replace all characters in the
300 		 *		source string that appears in
301 		 *		the "from" string with the corresponding
302 		 *		characters in the "to" string.
303 		 *
304 		 */
305 		if (argc > 3) {
306 			char temp[MAXTOK];
307 			if (argc > 4)
308 				map(temp, argv[2], argv[3], argv[4]);
309 			else
310 				map(temp, argv[2], argv[3], null);
311 			pbstr(temp);
312 		}
313 		else
314 		    if (argc > 2)
315 			pbstr(argv[2]);
316 		break;
317 
318 	case INDXTYPE:
319 		/*
320 		 * doindex - find the index of the second argument
321 		 *	     string in the first argument string.
322 		 *	     -1 if not present.
323 		 */
324 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
325 		break;
326 
327 	case ERRPTYPE:
328 		/*
329 		 * doerrp - print the arguments to stderr file
330 		 *
331 		 */
332 		if (argc > 2) {
333 			for (n = 2; n < argc; n++)
334 				fprintf(stderr,"%s ", argv[n]);
335 			fprintf(stderr, "\n");
336 		}
337 		break;
338 
339 	case DNLNTYPE:
340 		/*
341 		 * dodnl - eat-up-to and including newline
342 		 *
343 		 */
344 		while ((c = gpbc()) != '\n' && c != EOF)
345 			;
346 		break;
347 
348 	case M4WRTYPE:
349 		/*
350 		 * dom4wrap - set up for wrap-up/wind-down activity
351 		 *
352 		 */
353 		m4wraps = (argc > 2) ? strdup(argv[2]) : null;
354 		break;
355 
356 	case EXITTYPE:
357 		/*
358 		 * doexit - immediate exit from m4.
359 		 *
360 		 */
361 		exit((argc > 2) ? atoi(argv[2]) : 0);
362 		break;
363 
364 	case DEFNTYPE:
365 		if (argc > 2)
366 			for (n = 2; n < argc; n++)
367 				dodefn(argv[n]);
368 		break;
369 
370 	default:
371 		error("m4: major botch in eval.");
372 		break;
373 	}
374 }
375