xref: /openbsd/usr.bin/m4/eval.c (revision ee3599c7)
1*ee3599c7Sespie /*	$OpenBSD: eval.c,v 1.19 1999/11/17 14:57:21 espie Exp $	*/
2aa676ce1Smillert /*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1989, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Ozan Yigit at York University.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
19df930be7Sderaadt  * 3. All advertising materials mentioning features or use of this software
20df930be7Sderaadt  *    must display the following acknowledgement:
21df930be7Sderaadt  *	This product includes software developed by the University of
22df930be7Sderaadt  *	California, Berkeley and its contributors.
23df930be7Sderaadt  * 4. Neither the name of the University nor the names of its contributors
24df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
25df930be7Sderaadt  *    without specific prior written permission.
26df930be7Sderaadt  *
27df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df930be7Sderaadt  * SUCH DAMAGE.
38df930be7Sderaadt  */
39df930be7Sderaadt 
40df930be7Sderaadt #ifndef lint
41df930be7Sderaadt #if 0
42df930be7Sderaadt static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
43df930be7Sderaadt #else
44*ee3599c7Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.19 1999/11/17 14:57:21 espie Exp $";
45df930be7Sderaadt #endif
46df930be7Sderaadt #endif /* not lint */
47df930be7Sderaadt 
48df930be7Sderaadt /*
49df930be7Sderaadt  * eval.c
50df930be7Sderaadt  * Facility: m4 macro processor
51df930be7Sderaadt  * by: oz
52df930be7Sderaadt  */
53df930be7Sderaadt 
54df930be7Sderaadt #include <sys/types.h>
55df930be7Sderaadt #include <errno.h>
56df930be7Sderaadt #include <unistd.h>
57df930be7Sderaadt #include <stdio.h>
58df930be7Sderaadt #include <stdlib.h>
593f42598dSespie #include <stddef.h>
60df930be7Sderaadt #include <string.h>
61445b77f7Smillert #include <fcntl.h>
6281c2181eSespie #include <err.h>
63df930be7Sderaadt #include "mdef.h"
64df930be7Sderaadt #include "stdd.h"
65df930be7Sderaadt #include "extern.h"
66df930be7Sderaadt #include "pathnames.h"
67df930be7Sderaadt 
68df930be7Sderaadt /*
69df930be7Sderaadt  * eval - evaluate built-in macros.
70df930be7Sderaadt  *	  argc - number of elements in argv.
71df930be7Sderaadt  *	  argv - element vector :
72df930be7Sderaadt  *			argv[0] = definition of a user
73df930be7Sderaadt  *				  macro or nil if built-in.
74df930be7Sderaadt  *			argv[1] = name of the macro or
75df930be7Sderaadt  *				  built-in.
76df930be7Sderaadt  *			argv[2] = parameters to user-defined
77df930be7Sderaadt  *			   .	  macro or built-in.
78df930be7Sderaadt  *			   .
79df930be7Sderaadt  *
80df930be7Sderaadt  * Note that the minimum value for argc is 3. A call in the form
81df930be7Sderaadt  * of macro-or-builtin() will result in:
82df930be7Sderaadt  *			argv[0] = nullstr
83df930be7Sderaadt  *			argv[1] = macro-or-builtin
84df930be7Sderaadt  *			argv[2] = nullstr
85df930be7Sderaadt  */
86df930be7Sderaadt 
87df930be7Sderaadt void
88df930be7Sderaadt eval(argv, argc, td)
8953f6f6bfSespie 	char *argv[];
9053f6f6bfSespie 	int argc;
9153f6f6bfSespie 	int td;
92df930be7Sderaadt {
9353f6f6bfSespie 	int c, n;
94df930be7Sderaadt 	static int sysval = 0;
95df930be7Sderaadt 
96df930be7Sderaadt #ifdef DEBUG
97df930be7Sderaadt 	printf("argc = %d\n", argc);
98df930be7Sderaadt 	for (n = 0; n < argc; n++)
99df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
100df930be7Sderaadt #endif
101df930be7Sderaadt  /*
102df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
103df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
104df930be7Sderaadt   * argc to avoid further checking..
105df930be7Sderaadt   */
106df930be7Sderaadt 	if (argc == 3 && !*(argv[2]))
107df930be7Sderaadt 		argc--;
108df930be7Sderaadt 
109df930be7Sderaadt 	switch (td & ~STATIC) {
110df930be7Sderaadt 
111df930be7Sderaadt 	case DEFITYPE:
112df930be7Sderaadt 		if (argc > 2)
113df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
114df930be7Sderaadt 		break;
115df930be7Sderaadt 
116df930be7Sderaadt 	case PUSDTYPE:
117df930be7Sderaadt 		if (argc > 2)
118df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
119df930be7Sderaadt 		break;
120df930be7Sderaadt 
121df930be7Sderaadt 	case DUMPTYPE:
122df930be7Sderaadt 		dodump(argv, argc);
123df930be7Sderaadt 		break;
124df930be7Sderaadt 
125df930be7Sderaadt 	case EXPRTYPE:
126df930be7Sderaadt 	/*
127df930be7Sderaadt 	 * doexpr - evaluate arithmetic
128df930be7Sderaadt 	 * expression
129df930be7Sderaadt 	 */
130df930be7Sderaadt 		if (argc > 2)
131df930be7Sderaadt 			pbnum(expr(argv[2]));
132df930be7Sderaadt 		break;
133df930be7Sderaadt 
134df930be7Sderaadt 	case IFELTYPE:
135df930be7Sderaadt 		if (argc > 4)
136df930be7Sderaadt 			doifelse(argv, argc);
137df930be7Sderaadt 		break;
138df930be7Sderaadt 
139df930be7Sderaadt 	case IFDFTYPE:
140df930be7Sderaadt 	/*
141df930be7Sderaadt 	 * doifdef - select one of two
142df930be7Sderaadt 	 * alternatives based on the existence of
143df930be7Sderaadt 	 * another definition
144df930be7Sderaadt 	 */
145df930be7Sderaadt 		if (argc > 3) {
146df930be7Sderaadt 			if (lookup(argv[2]) != nil)
147df930be7Sderaadt 				pbstr(argv[3]);
148df930be7Sderaadt 			else if (argc > 4)
149df930be7Sderaadt 				pbstr(argv[4]);
150df930be7Sderaadt 		}
151df930be7Sderaadt 		break;
152df930be7Sderaadt 
153df930be7Sderaadt 	case LENGTYPE:
154df930be7Sderaadt 	/*
155df930be7Sderaadt 	 * dolen - find the length of the
156df930be7Sderaadt 	 * argument
157df930be7Sderaadt 	 */
158df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
159df930be7Sderaadt 		break;
160df930be7Sderaadt 
161df930be7Sderaadt 	case INCRTYPE:
162df930be7Sderaadt 	/*
163df930be7Sderaadt 	 * doincr - increment the value of the
164df930be7Sderaadt 	 * argument
165df930be7Sderaadt 	 */
166df930be7Sderaadt 		if (argc > 2)
167df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
168df930be7Sderaadt 		break;
169df930be7Sderaadt 
170df930be7Sderaadt 	case DECRTYPE:
171df930be7Sderaadt 	/*
172df930be7Sderaadt 	 * dodecr - decrement the value of the
173df930be7Sderaadt 	 * argument
174df930be7Sderaadt 	 */
175df930be7Sderaadt 		if (argc > 2)
176df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
177df930be7Sderaadt 		break;
178df930be7Sderaadt 
179df930be7Sderaadt 	case SYSCTYPE:
180df930be7Sderaadt 	/*
181df930be7Sderaadt 	 * dosys - execute system command
182df930be7Sderaadt 	 */
183df930be7Sderaadt 		if (argc > 2)
184df930be7Sderaadt 			sysval = system(argv[2]);
185df930be7Sderaadt 		break;
186df930be7Sderaadt 
187df930be7Sderaadt 	case SYSVTYPE:
188df930be7Sderaadt 	/*
189df930be7Sderaadt 	 * dosysval - return value of the last
190df930be7Sderaadt 	 * system call.
191df930be7Sderaadt 	 *
192df930be7Sderaadt 	 */
193df930be7Sderaadt 		pbnum(sysval);
194df930be7Sderaadt 		break;
195df930be7Sderaadt 
196df930be7Sderaadt 	case INCLTYPE:
197df930be7Sderaadt 		if (argc > 2)
198df930be7Sderaadt 			if (!doincl(argv[2]))
19981c2181eSespie 				err(1, "%s", argv[2]);
200df930be7Sderaadt 		break;
201df930be7Sderaadt 
202df930be7Sderaadt 	case SINCTYPE:
203df930be7Sderaadt 		if (argc > 2)
204df930be7Sderaadt 			(void) doincl(argv[2]);
205df930be7Sderaadt 		break;
206df930be7Sderaadt #ifdef EXTENDED
207df930be7Sderaadt 	case PASTTYPE:
208df930be7Sderaadt 		if (argc > 2)
209df930be7Sderaadt 			if (!dopaste(argv[2]))
21081c2181eSespie 				err(1, "%s", argv[2]);
211df930be7Sderaadt 		break;
212df930be7Sderaadt 
213df930be7Sderaadt 	case SPASTYPE:
214df930be7Sderaadt 		if (argc > 2)
215df930be7Sderaadt 			(void) dopaste(argv[2]);
216df930be7Sderaadt 		break;
217df930be7Sderaadt #endif
218df930be7Sderaadt 	case CHNQTYPE:
219df930be7Sderaadt 		dochq(argv, argc);
220df930be7Sderaadt 		break;
221df930be7Sderaadt 
222df930be7Sderaadt 	case CHNCTYPE:
223df930be7Sderaadt 		dochc(argv, argc);
224df930be7Sderaadt 		break;
225df930be7Sderaadt 
226df930be7Sderaadt 	case SUBSTYPE:
227df930be7Sderaadt 	/*
228df930be7Sderaadt 	 * dosub - select substring
229df930be7Sderaadt 	 *
230df930be7Sderaadt 	 */
231df930be7Sderaadt 		if (argc > 3)
232df930be7Sderaadt 			dosub(argv, argc);
233df930be7Sderaadt 		break;
234df930be7Sderaadt 
235df930be7Sderaadt 	case SHIFTYPE:
236df930be7Sderaadt 	/*
237df930be7Sderaadt 	 * doshift - push back all arguments
238df930be7Sderaadt 	 * except the first one (i.e. skip
239df930be7Sderaadt 	 * argv[2])
240df930be7Sderaadt 	 */
241df930be7Sderaadt 		if (argc > 3) {
242df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
2433a73db8cSderaadt 				pbstr(rquote);
244df930be7Sderaadt 				pbstr(argv[n]);
2453a73db8cSderaadt 				pbstr(lquote);
246aa676ce1Smillert 				putback(COMMA);
247df930be7Sderaadt 			}
2483a73db8cSderaadt 			pbstr(rquote);
249df930be7Sderaadt 			pbstr(argv[3]);
2503a73db8cSderaadt 			pbstr(lquote);
251df930be7Sderaadt 		}
252df930be7Sderaadt 		break;
253df930be7Sderaadt 
254df930be7Sderaadt 	case DIVRTYPE:
255df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
256df930be7Sderaadt 			dodiv(n);
257df930be7Sderaadt 		else {
258df930be7Sderaadt 			active = stdout;
259df930be7Sderaadt 			oindex = 0;
260df930be7Sderaadt 		}
261df930be7Sderaadt 		break;
262df930be7Sderaadt 
263df930be7Sderaadt 	case UNDVTYPE:
264df930be7Sderaadt 		doundiv(argv, argc);
265df930be7Sderaadt 		break;
266df930be7Sderaadt 
267df930be7Sderaadt 	case DIVNTYPE:
268df930be7Sderaadt 	/*
269df930be7Sderaadt 	 * dodivnum - return the number of
270df930be7Sderaadt 	 * current output diversion
271df930be7Sderaadt 	 */
272df930be7Sderaadt 		pbnum(oindex);
273df930be7Sderaadt 		break;
274df930be7Sderaadt 
275df930be7Sderaadt 	case UNDFTYPE:
276df930be7Sderaadt 	/*
277df930be7Sderaadt 	 * doundefine - undefine a previously
278df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
279df930be7Sderaadt 	 */
280df930be7Sderaadt 		if (argc > 2)
281df930be7Sderaadt 			for (n = 2; n < argc; n++)
282df930be7Sderaadt 				remhash(argv[n], ALL);
283df930be7Sderaadt 		break;
284df930be7Sderaadt 
285df930be7Sderaadt 	case POPDTYPE:
286df930be7Sderaadt 	/*
287df930be7Sderaadt 	 * dopopdef - remove the topmost
288df930be7Sderaadt 	 * definitions of macro(s) or m4
289df930be7Sderaadt 	 * keyword(s).
290df930be7Sderaadt 	 */
291df930be7Sderaadt 		if (argc > 2)
292df930be7Sderaadt 			for (n = 2; n < argc; n++)
293df930be7Sderaadt 				remhash(argv[n], TOP);
294df930be7Sderaadt 		break;
295df930be7Sderaadt 
296df930be7Sderaadt 	case MKTMTYPE:
297df930be7Sderaadt 	/*
298df930be7Sderaadt 	 * dotemp - create a temporary file
299df930be7Sderaadt 	 */
30001e71e69Sespie 		if (argc > 2) {
30101e71e69Sespie 			int fd;
30201e71e69Sespie 
30301e71e69Sespie 			fd = mkstemp(argv[2]);
30401e71e69Sespie 			if (fd == -1)
30501e71e69Sespie 				err(1, "couldn't make temp file %s", argv[2]);
30601e71e69Sespie 			close(fd);
30701e71e69Sespie 			pbstr(argv[2]);
30801e71e69Sespie 		}
309df930be7Sderaadt 		break;
310df930be7Sderaadt 
311df930be7Sderaadt 	case TRNLTYPE:
312df930be7Sderaadt 	/*
313df930be7Sderaadt 	 * dotranslit - replace all characters in
314df930be7Sderaadt 	 * the source string that appears in the
315df930be7Sderaadt 	 * "from" string with the corresponding
316df930be7Sderaadt 	 * characters in the "to" string.
317df930be7Sderaadt 	 */
318df930be7Sderaadt 		if (argc > 3) {
3197d3e0b6bSderaadt 			char temp[STRSPMAX+1];
320df930be7Sderaadt 			if (argc > 4)
321df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
322df930be7Sderaadt 			else
323df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
324df930be7Sderaadt 			pbstr(temp);
3257d3e0b6bSderaadt 		} else if (argc > 2)
326df930be7Sderaadt 			pbstr(argv[2]);
327df930be7Sderaadt 		break;
328df930be7Sderaadt 
329df930be7Sderaadt 	case INDXTYPE:
330df930be7Sderaadt 	/*
331df930be7Sderaadt 	 * doindex - find the index of the second
332df930be7Sderaadt 	 * argument string in the first argument
333df930be7Sderaadt 	 * string. -1 if not present.
334df930be7Sderaadt 	 */
335df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
336df930be7Sderaadt 		break;
337df930be7Sderaadt 
338df930be7Sderaadt 	case ERRPTYPE:
339df930be7Sderaadt 	/*
340df930be7Sderaadt 	 * doerrp - print the arguments to stderr
341df930be7Sderaadt 	 * file
342df930be7Sderaadt 	 */
343df930be7Sderaadt 		if (argc > 2) {
344df930be7Sderaadt 			for (n = 2; n < argc; n++)
345df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
346df930be7Sderaadt 			fprintf(stderr, "\n");
347df930be7Sderaadt 		}
348df930be7Sderaadt 		break;
349df930be7Sderaadt 
350df930be7Sderaadt 	case DNLNTYPE:
351df930be7Sderaadt 	/*
352df930be7Sderaadt 	 * dodnl - eat-up-to and including
353df930be7Sderaadt 	 * newline
354df930be7Sderaadt 	 */
355df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
356df930be7Sderaadt 			;
357df930be7Sderaadt 		break;
358df930be7Sderaadt 
359df930be7Sderaadt 	case M4WRTYPE:
360df930be7Sderaadt 	/*
361df930be7Sderaadt 	 * dom4wrap - set up for
362df930be7Sderaadt 	 * wrap-up/wind-down activity
363df930be7Sderaadt 	 */
364df930be7Sderaadt 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
365df930be7Sderaadt 		break;
366df930be7Sderaadt 
367df930be7Sderaadt 	case EXITTYPE:
368df930be7Sderaadt 	/*
369df930be7Sderaadt 	 * doexit - immediate exit from m4.
370df930be7Sderaadt 	 */
371df930be7Sderaadt 		killdiv();
372df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
373df930be7Sderaadt 		break;
374df930be7Sderaadt 
375df930be7Sderaadt 	case DEFNTYPE:
376df930be7Sderaadt 		if (argc > 2)
377df930be7Sderaadt 			for (n = 2; n < argc; n++)
378df930be7Sderaadt 				dodefn(argv[n]);
379df930be7Sderaadt 		break;
380df930be7Sderaadt 
381df930be7Sderaadt 	default:
38281c2181eSespie 		errx(1, "eval: major botch.");
383df930be7Sderaadt 		break;
384df930be7Sderaadt 	}
385df930be7Sderaadt }
386df930be7Sderaadt 
387df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
388df930be7Sderaadt 
389df930be7Sderaadt /*
390df930be7Sderaadt  * expand - user-defined macro expansion
391df930be7Sderaadt  */
392df930be7Sderaadt void
393df930be7Sderaadt expand(argv, argc)
39453f6f6bfSespie 	char *argv[];
39553f6f6bfSespie 	int argc;
396df930be7Sderaadt {
39753f6f6bfSespie 	char *t;
39853f6f6bfSespie 	char *p;
39953f6f6bfSespie 	int n;
40053f6f6bfSespie 	int argno;
401df930be7Sderaadt 
402df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
403df930be7Sderaadt 	p = t;
404df930be7Sderaadt 	while (*p)
405df930be7Sderaadt 		p++;
406df930be7Sderaadt 	p--;			       /* last character of defn */
407df930be7Sderaadt 	while (p > t) {
408df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
409df930be7Sderaadt 			putback(*p);
410df930be7Sderaadt 		else {
411df930be7Sderaadt 			switch (*p) {
412df930be7Sderaadt 
413df930be7Sderaadt 			case '#':
414df930be7Sderaadt 				pbnum(argc - 2);
415df930be7Sderaadt 				break;
416df930be7Sderaadt 			case '0':
417df930be7Sderaadt 			case '1':
418df930be7Sderaadt 			case '2':
419df930be7Sderaadt 			case '3':
420df930be7Sderaadt 			case '4':
421df930be7Sderaadt 			case '5':
422df930be7Sderaadt 			case '6':
423df930be7Sderaadt 			case '7':
424df930be7Sderaadt 			case '8':
425df930be7Sderaadt 			case '9':
426df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
427df930be7Sderaadt 					pbstr(argv[argno + 1]);
428df930be7Sderaadt 				break;
429df930be7Sderaadt 			case '*':
430df930be7Sderaadt 				for (n = argc - 1; n > 2; n--) {
431df930be7Sderaadt 					pbstr(argv[n]);
432aa676ce1Smillert 					putback(COMMA);
433df930be7Sderaadt 				}
434df930be7Sderaadt 				pbstr(argv[2]);
435df930be7Sderaadt 				break;
436aa676ce1Smillert                         case '@':
437aa676ce1Smillert                                 for (n = argc - 1; n > 2; n--) {
438aa676ce1Smillert                                         pbstr(rquote);
439aa676ce1Smillert                                         pbstr(argv[n]);
440aa676ce1Smillert                                         pbstr(lquote);
441aa676ce1Smillert 					putback(COMMA);
442aa676ce1Smillert                                 }
443aa676ce1Smillert 				pbstr(rquote);
444aa676ce1Smillert                                 pbstr(argv[2]);
445aa676ce1Smillert 				pbstr(lquote);
446aa676ce1Smillert                                 break;
447df930be7Sderaadt 			default:
448df930be7Sderaadt 				putback(*p);
449df930be7Sderaadt 				putback('$');
450df930be7Sderaadt 				break;
451df930be7Sderaadt 			}
452df930be7Sderaadt 			p--;
453df930be7Sderaadt 		}
454df930be7Sderaadt 		p--;
455df930be7Sderaadt 	}
456df930be7Sderaadt 	if (p == t)		       /* do last character */
457df930be7Sderaadt 		putback(*p);
458df930be7Sderaadt }
459df930be7Sderaadt 
460df930be7Sderaadt /*
461df930be7Sderaadt  * dodefine - install definition in the table
462df930be7Sderaadt  */
463df930be7Sderaadt void
464df930be7Sderaadt dodefine(name, defn)
46553f6f6bfSespie 	char *name;
46653f6f6bfSespie 	char *defn;
467df930be7Sderaadt {
46853f6f6bfSespie 	ndptr p;
469df930be7Sderaadt 
470df930be7Sderaadt 	if (!*name)
47181c2181eSespie 		errx(1, "null definition.");
472df930be7Sderaadt 	if (STREQ(name, defn))
47381c2181eSespie 		errx(1, "%s: recursive definition.", name);
474df930be7Sderaadt 	if ((p = lookup(name)) == nil)
475df930be7Sderaadt 		p = addent(name);
476df930be7Sderaadt 	else if (p->defn != null)
477df930be7Sderaadt 		free((char *) p->defn);
478df930be7Sderaadt 	if (!*defn)
479df930be7Sderaadt 		p->defn = null;
480df930be7Sderaadt 	else
481df930be7Sderaadt 		p->defn = xstrdup(defn);
482df930be7Sderaadt 	p->type = MACRTYPE;
483df930be7Sderaadt }
484df930be7Sderaadt 
485df930be7Sderaadt /*
486df930be7Sderaadt  * dodefn - push back a quoted definition of
487df930be7Sderaadt  *      the given name.
488df930be7Sderaadt  */
489df930be7Sderaadt void
490df930be7Sderaadt dodefn(name)
491df930be7Sderaadt 	char *name;
492df930be7Sderaadt {
49353f6f6bfSespie 	ndptr p;
494df930be7Sderaadt 
495df930be7Sderaadt 	if ((p = lookup(name)) != nil && p->defn != null) {
4963a73db8cSderaadt 		pbstr(rquote);
497df930be7Sderaadt 		pbstr(p->defn);
4983a73db8cSderaadt 		pbstr(lquote);
499df930be7Sderaadt 	}
500df930be7Sderaadt }
501df930be7Sderaadt 
502df930be7Sderaadt /*
503df930be7Sderaadt  * dopushdef - install a definition in the hash table
504df930be7Sderaadt  *      without removing a previous definition. Since
505df930be7Sderaadt  *      each new entry is entered in *front* of the
506df930be7Sderaadt  *      hash bucket, it hides a previous definition from
507df930be7Sderaadt  *      lookup.
508df930be7Sderaadt  */
509df930be7Sderaadt void
510df930be7Sderaadt dopushdef(name, defn)
51153f6f6bfSespie 	char *name;
51253f6f6bfSespie 	char *defn;
513df930be7Sderaadt {
51453f6f6bfSespie 	ndptr p;
515df930be7Sderaadt 
516df930be7Sderaadt 	if (!*name)
51781c2181eSespie 		errx(1, "null definition");
518df930be7Sderaadt 	if (STREQ(name, defn))
51981c2181eSespie 		errx(1, "%s: recursive definition.", name);
520df930be7Sderaadt 	p = addent(name);
521df930be7Sderaadt 	if (!*defn)
522df930be7Sderaadt 		p->defn = null;
523df930be7Sderaadt 	else
524df930be7Sderaadt 		p->defn = xstrdup(defn);
525df930be7Sderaadt 	p->type = MACRTYPE;
526df930be7Sderaadt }
527df930be7Sderaadt 
528df930be7Sderaadt /*
529df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
530df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
531df930be7Sderaadt  *      hash table is dumped.
532df930be7Sderaadt  */
533df930be7Sderaadt void
534df930be7Sderaadt dodump(argv, argc)
53553f6f6bfSespie 	char *argv[];
53653f6f6bfSespie 	int argc;
537df930be7Sderaadt {
53853f6f6bfSespie 	int n;
539df930be7Sderaadt 	ndptr p;
540df930be7Sderaadt 
541df930be7Sderaadt 	if (argc > 2) {
542df930be7Sderaadt 		for (n = 2; n < argc; n++)
543df930be7Sderaadt 			if ((p = lookup(argv[n])) != nil)
544df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
545df930be7Sderaadt 					p->defn);
5467d3e0b6bSderaadt 	} else {
547df930be7Sderaadt 		for (n = 0; n < HASHSIZE; n++)
548df930be7Sderaadt 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
549df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
550df930be7Sderaadt 					p->defn);
551df930be7Sderaadt 	}
552df930be7Sderaadt }
553df930be7Sderaadt 
554df930be7Sderaadt /*
555df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
556df930be7Sderaadt  */
557df930be7Sderaadt void
558df930be7Sderaadt doifelse(argv, argc)
55953f6f6bfSespie 	char *argv[];
56053f6f6bfSespie 	int argc;
561df930be7Sderaadt {
562df930be7Sderaadt 	cycle {
563df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
564df930be7Sderaadt 			pbstr(argv[4]);
565df930be7Sderaadt 		else if (argc == 6)
566df930be7Sderaadt 			pbstr(argv[5]);
567df930be7Sderaadt 		else if (argc > 6) {
568df930be7Sderaadt 			argv += 3;
569df930be7Sderaadt 			argc -= 3;
570df930be7Sderaadt 			continue;
571df930be7Sderaadt 		}
572df930be7Sderaadt 		break;
573df930be7Sderaadt 	}
574df930be7Sderaadt }
575df930be7Sderaadt 
576df930be7Sderaadt /*
577df930be7Sderaadt  * doinclude - include a given file.
578df930be7Sderaadt  */
579df930be7Sderaadt int
580df930be7Sderaadt doincl(ifile)
581df930be7Sderaadt 	char *ifile;
582df930be7Sderaadt {
583df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
58481c2181eSespie 		errx(1, "too many include files.");
5854a769388Sespie 	if ((infile[ilevel + 1] = fopen_trypath(ifile)) != NULL) {
586df930be7Sderaadt 		ilevel++;
587df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
588df930be7Sderaadt 		return (1);
5897d3e0b6bSderaadt 	} else
590df930be7Sderaadt 		return (0);
591df930be7Sderaadt }
592df930be7Sderaadt 
593df930be7Sderaadt #ifdef EXTENDED
594df930be7Sderaadt /*
595df930be7Sderaadt  * dopaste - include a given file without any
596df930be7Sderaadt  *           macro processing.
597df930be7Sderaadt  */
598df930be7Sderaadt int
599df930be7Sderaadt dopaste(pfile)
600df930be7Sderaadt 	char *pfile;
601df930be7Sderaadt {
602df930be7Sderaadt 	FILE *pf;
60353f6f6bfSespie 	int c;
604df930be7Sderaadt 
605df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
606df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
607df930be7Sderaadt 			putc(c, active);
608df930be7Sderaadt 		(void) fclose(pf);
609df930be7Sderaadt 		return (1);
6107d3e0b6bSderaadt 	} else
611df930be7Sderaadt 		return (0);
612df930be7Sderaadt }
613df930be7Sderaadt #endif
614df930be7Sderaadt 
615df930be7Sderaadt /*
616df930be7Sderaadt  * dochq - change quote characters
617df930be7Sderaadt  */
618df930be7Sderaadt void
619df930be7Sderaadt dochq(argv, argc)
62053f6f6bfSespie 	char *argv[];
62153f6f6bfSespie 	int argc;
622df930be7Sderaadt {
623df930be7Sderaadt 	if (argc > 2) {
62418a1973bSderaadt 		if (*argv[2])
62529a0bfdcSderaadt 			strncpy(lquote, argv[2], MAXCCHARS);
62618a1973bSderaadt 		else {
62718a1973bSderaadt 			lquote[0] = LQUOTE;
628f0484631Sespie 			lquote[1] = EOS;
62918a1973bSderaadt 		}
630df930be7Sderaadt 		if (argc > 3) {
631df930be7Sderaadt 			if (*argv[3])
63229a0bfdcSderaadt 				strncpy(rquote, argv[3], MAXCCHARS);
6337d3e0b6bSderaadt 		} else
63429a0bfdcSderaadt 			strcpy(rquote, lquote);
6357d3e0b6bSderaadt 	} else {
636f0484631Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
637f0484631Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
638df930be7Sderaadt 	}
639df930be7Sderaadt }
640df930be7Sderaadt 
641df930be7Sderaadt /*
642df930be7Sderaadt  * dochc - change comment characters
643df930be7Sderaadt  */
644df930be7Sderaadt void
645df930be7Sderaadt dochc(argv, argc)
64653f6f6bfSespie 	char *argv[];
64753f6f6bfSespie 	int argc;
648df930be7Sderaadt {
649df930be7Sderaadt 	if (argc > 2) {
650df930be7Sderaadt 		if (*argv[2])
65129a0bfdcSderaadt 			strncpy(scommt, argv[2], MAXCCHARS);
652df930be7Sderaadt 		if (argc > 3) {
653df930be7Sderaadt 			if (*argv[3])
65429a0bfdcSderaadt 				strncpy(ecommt, argv[3], MAXCCHARS);
655df930be7Sderaadt 		}
656df930be7Sderaadt 		else
657f0484631Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
658df930be7Sderaadt 	}
659df930be7Sderaadt 	else {
660f0484631Sespie 		scommt[0] = SCOMMT, scommt[1] = EOS;
661f0484631Sespie 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
662df930be7Sderaadt 	}
663df930be7Sderaadt }
664df930be7Sderaadt 
665df930be7Sderaadt /*
666df930be7Sderaadt  * dodivert - divert the output to a temporary file
667df930be7Sderaadt  */
668df930be7Sderaadt void
669df930be7Sderaadt dodiv(n)
67053f6f6bfSespie 	int n;
671df930be7Sderaadt {
672445b77f7Smillert 	int fd;
673445b77f7Smillert 
6747d3e0b6bSderaadt 	oindex = n;
675df930be7Sderaadt 	if (n < 0 || n >= MAXOUT)
676df930be7Sderaadt 		n = 0;		       /* bitbucket */
677df930be7Sderaadt 	if (outfile[n] == NULL) {
6783f42598dSespie 		char fname[] = _PATH_DIVNAME;
6793f42598dSespie 
6803f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
6813f42598dSespie 			(outfile[n] = fdopen(fd, "w+")) == NULL)
6823f42598dSespie 				err(1, "%s: cannot divert", fname);
6833f42598dSespie 		if (unlink(fname) == -1)
6843f42598dSespie 			err(1, "%s: cannot unlink", fname);
685df930be7Sderaadt 	}
686df930be7Sderaadt 	active = outfile[n];
687df930be7Sderaadt }
688df930be7Sderaadt 
689df930be7Sderaadt /*
690df930be7Sderaadt  * doundivert - undivert a specified output, or all
691df930be7Sderaadt  *              other outputs, in numerical order.
692df930be7Sderaadt  */
693df930be7Sderaadt void
694df930be7Sderaadt doundiv(argv, argc)
69553f6f6bfSespie 	char *argv[];
69653f6f6bfSespie 	int argc;
697df930be7Sderaadt {
69853f6f6bfSespie 	int ind;
69953f6f6bfSespie 	int n;
700df930be7Sderaadt 
701df930be7Sderaadt 	if (argc > 2) {
702df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
703df930be7Sderaadt 			n = atoi(argv[ind]);
704df930be7Sderaadt 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
705df930be7Sderaadt 				getdiv(n);
706df930be7Sderaadt 
707df930be7Sderaadt 		}
708df930be7Sderaadt 	}
709df930be7Sderaadt 	else
710df930be7Sderaadt 		for (n = 1; n < MAXOUT; n++)
711df930be7Sderaadt 			if (outfile[n] != NULL)
712df930be7Sderaadt 				getdiv(n);
713df930be7Sderaadt }
714df930be7Sderaadt 
715df930be7Sderaadt /*
716df930be7Sderaadt  * dosub - select substring
717df930be7Sderaadt  */
718df930be7Sderaadt void
719df930be7Sderaadt dosub(argv, argc)
72053f6f6bfSespie 	char *argv[];
72153f6f6bfSespie 	int argc;
722df930be7Sderaadt {
72353f6f6bfSespie 	char *ap, *fc, *k;
72453f6f6bfSespie 	int nc;
725df930be7Sderaadt 
726df930be7Sderaadt 	if (argc < 5)
727df930be7Sderaadt 		nc = MAXTOK;
728df930be7Sderaadt 	else
729df930be7Sderaadt #ifdef EXPR
730df930be7Sderaadt 		nc = expr(argv[4]);
731df930be7Sderaadt #else
732df930be7Sderaadt 		nc = atoi(argv[4]);
733df930be7Sderaadt #endif
734df930be7Sderaadt 	ap = argv[2];		       /* target string */
735df930be7Sderaadt #ifdef EXPR
736df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
737df930be7Sderaadt #else
738df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
739df930be7Sderaadt #endif
740df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
741df930be7Sderaadt 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
742df930be7Sderaadt 			putback(*k);
743df930be7Sderaadt }
744df930be7Sderaadt 
745df930be7Sderaadt /*
746df930be7Sderaadt  * map:
747df930be7Sderaadt  * map every character of s1 that is specified in from
748df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
749df930be7Sderaadt  *
750df930be7Sderaadt  * This is a standard implementation of map(s,from,to) function of ICON
751df930be7Sderaadt  * language. Within mapvec, we replace every character of "from" with
752df930be7Sderaadt  * the corresponding character in "to". If "to" is shorter than "from",
753df930be7Sderaadt  * than the corresponding entries are null, which means that those
754df930be7Sderaadt  * characters dissapear altogether. Furthermore, imagine
755df930be7Sderaadt  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
756df930be7Sderaadt  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
757df930be7Sderaadt  * ultimately maps to `*'. In order to achieve this effect in an efficient
758df930be7Sderaadt  * manner (i.e. without multiple passes over the destination string), we
759df930be7Sderaadt  * loop over mapvec, starting with the initial source character. if the
760df930be7Sderaadt  * character value (dch) in this location is different than the source
761df930be7Sderaadt  * character (sch), sch becomes dch, once again to index into mapvec, until
762df930be7Sderaadt  * the character value stabilizes (i.e. sch = dch, in other words
763df930be7Sderaadt  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
764df930be7Sderaadt  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
765df930be7Sderaadt  * end, we restore mapvec* back to normal where mapvec[n] == n for
766df930be7Sderaadt  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
767df930be7Sderaadt  * about 5 times faster than any algorithm that makes multiple passes over
768df930be7Sderaadt  * destination string.
769df930be7Sderaadt  */
770df930be7Sderaadt void
771df930be7Sderaadt map(dest, src, from, to)
77253f6f6bfSespie 	char *dest;
77353f6f6bfSespie 	char *src;
77453f6f6bfSespie 	char *from;
77553f6f6bfSespie 	char *to;
776df930be7Sderaadt {
77753f6f6bfSespie 	char *tmp;
778*ee3599c7Sespie 	unsigned char sch, dch;
779*ee3599c7Sespie 	static unsigned char mapvec[256] = {
780*ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
781*ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
782*ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
783*ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
784*ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
785*ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
786*ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
787*ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
788*ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
789*ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
790*ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
791*ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
792*ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
793*ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
794*ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
795*ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
796*ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
797*ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
798df930be7Sderaadt 	};
799df930be7Sderaadt 
800df930be7Sderaadt 	if (*src) {
801df930be7Sderaadt 		tmp = from;
802df930be7Sderaadt 	/*
803df930be7Sderaadt 	 * create a mapping between "from" and
804df930be7Sderaadt 	 * "to"
805df930be7Sderaadt 	 */
806df930be7Sderaadt 		while (*from)
807*ee3599c7Sespie 			mapvec[(unsigned char)(*from++)] = (*to) ?
808*ee3599c7Sespie 				(unsigned char)(*to++) : 0;
809df930be7Sderaadt 
810df930be7Sderaadt 		while (*src) {
811*ee3599c7Sespie 			sch = (unsigned char)(*src++);
812df930be7Sderaadt 			dch = mapvec[sch];
813df930be7Sderaadt 			while (dch != sch) {
814df930be7Sderaadt 				sch = dch;
815df930be7Sderaadt 				dch = mapvec[sch];
816df930be7Sderaadt 			}
817*ee3599c7Sespie 			if ((*dest = (char)dch))
818df930be7Sderaadt 				dest++;
819df930be7Sderaadt 		}
820df930be7Sderaadt 	/*
821df930be7Sderaadt 	 * restore all the changed characters
822df930be7Sderaadt 	 */
823df930be7Sderaadt 		while (*tmp) {
824*ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
825df930be7Sderaadt 			tmp++;
826df930be7Sderaadt 		}
827df930be7Sderaadt 	}
828*ee3599c7Sespie 	*dest = '\0';
829df930be7Sderaadt }
830