eval.c revision 69246
1254885Sdumbbell/*
2254885Sdumbbell * Copyright (c) 1989, 1993
3254885Sdumbbell *	The Regents of the University of California.  All rights reserved.
4254885Sdumbbell *
5254885Sdumbbell * This code is derived from software contributed to Berkeley by
6254885Sdumbbell * Ozan Yigit at York University.
7254885Sdumbbell *
8254885Sdumbbell * Redistribution and use in source and binary forms, with or without
9254885Sdumbbell * modification, are permitted provided that the following conditions
10254885Sdumbbell * are met:
11254885Sdumbbell * 1. Redistributions of source code must retain the above copyright
12254885Sdumbbell *    notice, this list of conditions and the following disclaimer.
13254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright
14254885Sdumbbell *    notice, this list of conditions and the following disclaimer in the
15254885Sdumbbell *    documentation and/or other materials provided with the distribution.
16254885Sdumbbell * 3. All advertising materials mentioning features or use of this software
17254885Sdumbbell *    must display the following acknowledgement:
18254885Sdumbbell *	This product includes software developed by the University of
19254885Sdumbbell *	California, Berkeley and its contributors.
20254885Sdumbbell * 4. Neither the name of the University nor the names of its contributors
21254885Sdumbbell *    may be used to endorse or promote products derived from this software
22254885Sdumbbell *    without specific prior written permission.
23254885Sdumbbell *
24254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27254885Sdumbbell * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34254885Sdumbbell * SUCH DAMAGE.
35254885Sdumbbell */
36254885Sdumbbell
37254885Sdumbbell#ifndef lint
38254885Sdumbbell#if 0
39254885Sdumbbellstatic char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 6/6/93";
40254885Sdumbbell#endif
41254885Sdumbbellstatic const char rcsid[] =
42254885Sdumbbell  "$FreeBSD: head/usr.bin/m4/eval.c 69246 2000-11-27 04:26:39Z kris $";
43254885Sdumbbell#endif /* not lint */
44254885Sdumbbell
45254885Sdumbbell/*
46254885Sdumbbell * eval.c
47254885Sdumbbell * Facility: m4 macro processor
48254885Sdumbbell * by: oz
49254885Sdumbbell */
50254885Sdumbbell
51254885Sdumbbell#include <sys/types.h>
52254885Sdumbbell#include <err.h>
53254885Sdumbbell#include <stdio.h>
54254885Sdumbbell#include <stdlib.h>
55254885Sdumbbell#include <string.h>
56254885Sdumbbell#include <unistd.h>
57254885Sdumbbell#include "mdef.h"
58254885Sdumbbell#include "stdd.h"
59254885Sdumbbell#include "extern.h"
60254885Sdumbbell#include "pathnames.h"
61254885Sdumbbell
62254885Sdumbbell/*
63254885Sdumbbell * eval - evaluate built-in macros.
64254885Sdumbbell *	  argc - number of elements in argv.
65254885Sdumbbell *	  argv - element vector :
66254885Sdumbbell *			argv[0] = definition of a user
67254885Sdumbbell *				  macro or nil if built-in.
68254885Sdumbbell *			argv[1] = name of the macro or
69254885Sdumbbell *				  built-in.
70254885Sdumbbell *			argv[2] = parameters to user-defined
71254885Sdumbbell *			   .	  macro or built-in.
72254885Sdumbbell *			   .
73254885Sdumbbell *
74254885Sdumbbell * Note that the minimum value for argc is 3. A call in the form
75254885Sdumbbell * of macro-or-builtin() will result in:
76254885Sdumbbell *			argv[0] = nullstr
77254885Sdumbbell *			argv[1] = macro-or-builtin
78254885Sdumbbell *			argv[2] = nullstr
79254885Sdumbbell */
80254885Sdumbbell
81254885Sdumbbellvoid
82254885Sdumbbelleval(argv, argc, td)
83254885Sdumbbellregister char *argv[];
84254885Sdumbbellregister int argc;
85254885Sdumbbellregister int td;
86254885Sdumbbell{
87254885Sdumbbell	register int c, n;
88254885Sdumbbell	static int sysval = 0;
89254885Sdumbbell
90254885Sdumbbell#ifdef DEBUG
91254885Sdumbbell	printf("argc = %d\n", argc);
92254885Sdumbbell	for (n = 0; n < argc; n++)
93254885Sdumbbell		printf("argv[%d] = %s\n", n, argv[n]);
94254885Sdumbbell#endif
95254885Sdumbbell /*
96254885Sdumbbell  * if argc == 3 and argv[2] is null, then we
97254885Sdumbbell  * have macro-or-builtin() type call. We adjust
98254885Sdumbbell  * argc to avoid further checking..
99254885Sdumbbell  */
100254885Sdumbbell	if (argc == 3 && !*(argv[2]))
101254885Sdumbbell		argc--;
102254885Sdumbbell
103254885Sdumbbell	switch (td & ~STATIC) {
104254885Sdumbbell
105254885Sdumbbell	case DEFITYPE:
106254885Sdumbbell		if (argc > 2)
107254885Sdumbbell			dodefine(argv[2], (argc > 3) ? argv[3] : null);
108254885Sdumbbell		break;
109254885Sdumbbell
110254885Sdumbbell	case PUSDTYPE:
111254885Sdumbbell		if (argc > 2)
112254885Sdumbbell			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
113254885Sdumbbell		break;
114254885Sdumbbell
115254885Sdumbbell	case DUMPTYPE:
116254885Sdumbbell		dodump(argv, argc);
117254885Sdumbbell		break;
118254885Sdumbbell
119254885Sdumbbell	case EXPRTYPE:
120254885Sdumbbell	/*
121254885Sdumbbell	 * doexpr - evaluate arithmetic
122254885Sdumbbell	 * expression
123254885Sdumbbell	 */
124254885Sdumbbell		if (argc > 2)
125254885Sdumbbell			pbnum(expr(argv[2]));
126254885Sdumbbell		break;
127254885Sdumbbell
128254885Sdumbbell	case IFELTYPE:
129254885Sdumbbell		if (argc > 4)
130254885Sdumbbell			doifelse(argv, argc);
131254885Sdumbbell		break;
132254885Sdumbbell
133254885Sdumbbell	case IFDFTYPE:
134254885Sdumbbell	/*
135254885Sdumbbell	 * doifdef - select one of two
136254885Sdumbbell	 * alternatives based on the existence of
137254885Sdumbbell	 * another definition
138254885Sdumbbell	 */
139254885Sdumbbell		if (argc > 3) {
140254885Sdumbbell			if (lookup(argv[2]) != nil)
141254885Sdumbbell				pbstr(argv[3]);
142254885Sdumbbell			else if (argc > 4)
143254885Sdumbbell				pbstr(argv[4]);
144254885Sdumbbell		}
145254885Sdumbbell		break;
146254885Sdumbbell
147254885Sdumbbell	case LENGTYPE:
148254885Sdumbbell	/*
149254885Sdumbbell	 * dolen - find the length of the
150254885Sdumbbell	 * argument
151254885Sdumbbell	 */
152254885Sdumbbell		if (argc > 2)
153254885Sdumbbell			pbnum((argc > 2) ? strlen(argv[2]) : 0);
154254885Sdumbbell		break;
155254885Sdumbbell
156254885Sdumbbell	case INCRTYPE:
157254885Sdumbbell	/*
158254885Sdumbbell	 * doincr - increment the value of the
159254885Sdumbbell	 * argument
160254885Sdumbbell	 */
161254885Sdumbbell		if (argc > 2)
162254885Sdumbbell			pbnum(atoi(argv[2]) + 1);
163254885Sdumbbell		break;
164254885Sdumbbell
165254885Sdumbbell	case DECRTYPE:
166254885Sdumbbell	/*
167254885Sdumbbell	 * dodecr - decrement the value of the
168254885Sdumbbell	 * argument
169254885Sdumbbell	 */
170254885Sdumbbell		if (argc > 2)
171254885Sdumbbell			pbnum(atoi(argv[2]) - 1);
172254885Sdumbbell		break;
173254885Sdumbbell
174254885Sdumbbell	case SYSCTYPE:
175254885Sdumbbell	/*
176254885Sdumbbell	 * dosys - execute system command
177254885Sdumbbell	 */
178254885Sdumbbell		/* Make sure m4 output is NOT interrupted */
179254885Sdumbbell		fflush(stdout);
180254885Sdumbbell		fflush(stderr);
181254885Sdumbbell		if (argc > 2)
182254885Sdumbbell			sysval = system(argv[2]);
183254885Sdumbbell		break;
184254885Sdumbbell
185254885Sdumbbell	case SYSVTYPE:
186254885Sdumbbell	/*
187254885Sdumbbell	 * dosysval - return value of the last
188254885Sdumbbell	 * system call.
189254885Sdumbbell	 *
190254885Sdumbbell	 */
191254885Sdumbbell		pbnum(sysval);
192254885Sdumbbell		break;
193254885Sdumbbell
194254885Sdumbbell	case INCLTYPE:
195254885Sdumbbell		if (argc > 2)
196254885Sdumbbell			if (!doincl(argv[2]))
197254885Sdumbbell				err(1, "%s", argv[2]);
198254885Sdumbbell		break;
199254885Sdumbbell
200254885Sdumbbell	case SINCTYPE:
201254885Sdumbbell		if (argc > 2)
202254885Sdumbbell			(void) doincl(argv[2]);
203254885Sdumbbell		break;
204254885Sdumbbell#ifdef EXTENDED
205254885Sdumbbell	case PASTTYPE:
206254885Sdumbbell		if (argc > 2)
207254885Sdumbbell			if (!dopaste(argv[2]))
208254885Sdumbbell				err(1, "%s", argv[2]);
209254885Sdumbbell		break;
210254885Sdumbbell
211254885Sdumbbell	case SPASTYPE:
212254885Sdumbbell		if (argc > 2)
213254885Sdumbbell			(void) dopaste(argv[2]);
214254885Sdumbbell		break;
215254885Sdumbbell#endif
216254885Sdumbbell	case CHNQTYPE:
217254885Sdumbbell		dochq(argv, argc);
218254885Sdumbbell		break;
219254885Sdumbbell
220254885Sdumbbell	case CHNCTYPE:
221254885Sdumbbell		dochc(argv, argc);
222254885Sdumbbell		break;
223254885Sdumbbell
224254885Sdumbbell	case SUBSTYPE:
225254885Sdumbbell	/*
226254885Sdumbbell	 * dosub - select substring
227254885Sdumbbell	 *
228254885Sdumbbell	 */
229254885Sdumbbell		if (argc > 3)
230254885Sdumbbell			dosub(argv, argc);
231254885Sdumbbell		break;
232254885Sdumbbell
233254885Sdumbbell	case SHIFTYPE:
234254885Sdumbbell	/*
235254885Sdumbbell	 * doshift - push back all arguments
236254885Sdumbbell	 * except the first one (i.e. skip
237254885Sdumbbell	 * argv[2])
238254885Sdumbbell	 */
239254885Sdumbbell		if (argc > 3) {
240254885Sdumbbell			for (n = argc - 1; n > 3; n--) {
241254885Sdumbbell				putback(rquote);
242254885Sdumbbell				pbstr(argv[n]);
243254885Sdumbbell				putback(lquote);
244254885Sdumbbell				putback(',');
245254885Sdumbbell			}
246254885Sdumbbell			putback(rquote);
247254885Sdumbbell			pbstr(argv[3]);
248254885Sdumbbell			putback(lquote);
249254885Sdumbbell		}
250254885Sdumbbell		break;
251254885Sdumbbell
252254885Sdumbbell	case DIVRTYPE:
253254885Sdumbbell		if (argc > 2 && (n = atoi(argv[2])) != 0)
254254885Sdumbbell			dodiv(n);
255254885Sdumbbell		else {
256254885Sdumbbell			active = stdout;
257254885Sdumbbell			oindex = 0;
258254885Sdumbbell		}
259254885Sdumbbell		break;
260254885Sdumbbell
261254885Sdumbbell	case UNDVTYPE:
262254885Sdumbbell		doundiv(argv, argc);
263254885Sdumbbell		break;
264254885Sdumbbell
265254885Sdumbbell	case DIVNTYPE:
266254885Sdumbbell	/*
267254885Sdumbbell	 * dodivnum - return the number of
268254885Sdumbbell	 * current output diversion
269254885Sdumbbell	 */
270254885Sdumbbell		pbnum(oindex);
271254885Sdumbbell		break;
272254885Sdumbbell
273254885Sdumbbell	case UNDFTYPE:
274254885Sdumbbell	/*
275254885Sdumbbell	 * doundefine - undefine a previously
276254885Sdumbbell	 * defined macro(s) or m4 keyword(s).
277254885Sdumbbell	 */
278254885Sdumbbell		if (argc > 2)
279254885Sdumbbell			for (n = 2; n < argc; n++)
280254885Sdumbbell				remhash(argv[n], ALL);
281254885Sdumbbell		break;
282254885Sdumbbell
283254885Sdumbbell	case POPDTYPE:
284254885Sdumbbell	/*
285254885Sdumbbell	 * dopopdef - remove the topmost
286254885Sdumbbell	 * definitions of macro(s) or m4
287254885Sdumbbell	 * keyword(s).
288254885Sdumbbell	 */
289254885Sdumbbell		if (argc > 2)
290254885Sdumbbell			for (n = 2; n < argc; n++)
291254885Sdumbbell				remhash(argv[n], TOP);
292254885Sdumbbell		break;
293254885Sdumbbell
294254885Sdumbbell	case MKTMTYPE:
295254885Sdumbbell	/*
296254885Sdumbbell	 * dotemp - create a temporary file
297254885Sdumbbell	 */
298254885Sdumbbell		if (argc > 2)
299254885Sdumbbell			pbstr(mktemp(argv[2]));
300254885Sdumbbell		break;
301254885Sdumbbell
302254885Sdumbbell	case TRNLTYPE:
303254885Sdumbbell	/*
304254885Sdumbbell	 * dotranslit - replace all characters in
305254885Sdumbbell	 * the source string that appears in the
306254885Sdumbbell	 * "from" string with the corresponding
307254885Sdumbbell	 * characters in the "to" string.
308254885Sdumbbell	 */
309254885Sdumbbell		if (argc > 3) {
310254885Sdumbbell			char temp[STRSPMAX+1];
311254885Sdumbbell			if (argc > 4)
312254885Sdumbbell				map(temp, argv[2], argv[3], argv[4]);
313254885Sdumbbell			else
314254885Sdumbbell				map(temp, argv[2], argv[3], null);
315254885Sdumbbell			pbstr(temp);
316254885Sdumbbell		}
317254885Sdumbbell		else if (argc > 2)
318254885Sdumbbell			pbstr(argv[2]);
319254885Sdumbbell		break;
320254885Sdumbbell
321254885Sdumbbell	case INDXTYPE:
322254885Sdumbbell	/*
323254885Sdumbbell	 * doindex - find the index of the second
324254885Sdumbbell	 * argument string in the first argument
325254885Sdumbbell	 * string. -1 if not present.
326254885Sdumbbell	 */
327254885Sdumbbell		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
328254885Sdumbbell		break;
329254885Sdumbbell
330254885Sdumbbell	case ERRPTYPE:
331254885Sdumbbell	/*
332254885Sdumbbell	 * doerrp - print the arguments to stderr
333254885Sdumbbell	 * file
334254885Sdumbbell	 */
335254885Sdumbbell		if (argc > 2) {
336254885Sdumbbell			for (n = 2; n < argc; n++)
337254885Sdumbbell				fprintf(stderr, "%s ", argv[n]);
338254885Sdumbbell			fprintf(stderr, "\n");
339254885Sdumbbell		}
340254885Sdumbbell		break;
341254885Sdumbbell
342254885Sdumbbell	case DNLNTYPE:
343254885Sdumbbell	/*
344254885Sdumbbell	 * dodnl - eat-up-to and including
345254885Sdumbbell	 * newline
346254885Sdumbbell	 */
347254885Sdumbbell		while ((c = gpbc()) != '\n' && c != EOF)
348254885Sdumbbell			;
349254885Sdumbbell		break;
350254885Sdumbbell
351254885Sdumbbell	case M4WRTYPE:
352254885Sdumbbell	/*
353254885Sdumbbell	 * dom4wrap - set up for
354254885Sdumbbell	 * wrap-up/wind-down activity
355254885Sdumbbell	 */
356254885Sdumbbell		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
357254885Sdumbbell		break;
358254885Sdumbbell
359254885Sdumbbell	case EXITTYPE:
360254885Sdumbbell	/*
361254885Sdumbbell	 * doexit - immediate exit from m4.
362254885Sdumbbell	 */
363254885Sdumbbell		killdiv();
364254885Sdumbbell		exit((argc > 2) ? atoi(argv[2]) : 0);
365254885Sdumbbell		break;
366254885Sdumbbell
367254885Sdumbbell	case DEFNTYPE:
368254885Sdumbbell		if (argc > 2)
369254885Sdumbbell			for (n = 2; n < argc; n++)
370254885Sdumbbell				dodefn(argv[n]);
371254885Sdumbbell		break;
372254885Sdumbbell
373254885Sdumbbell	case MACRTYPE:
374254885Sdumbbell		pbstr("");
375254885Sdumbbell		break;
376254885Sdumbbell
377254885Sdumbbell	default:
378254885Sdumbbell		errx(1, "eval: major botch");
379254885Sdumbbell		break;
380254885Sdumbbell	}
381254885Sdumbbell}
382254885Sdumbbell
383254885Sdumbbellconst char dumpfmt[] = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
384254885Sdumbbell
385254885Sdumbbell/*
386254885Sdumbbell * expand - user-defined macro expansion
387254885Sdumbbell */
388254885Sdumbbellvoid
389254885Sdumbbellexpand(argv, argc)
390254885Sdumbbellregister char *argv[];
391254885Sdumbbellregister int argc;
392254885Sdumbbell{
393254885Sdumbbell	register unsigned char *t;
394254885Sdumbbell	register unsigned char *p;
395254885Sdumbbell	register int n;
396254885Sdumbbell	register int argno;
397254885Sdumbbell
398254885Sdumbbell	t = argv[0];		       /* defn string as a whole */
399254885Sdumbbell	p = t;
400254885Sdumbbell	while (*p)
401254885Sdumbbell		p++;
402254885Sdumbbell	p--;			       /* last character of defn */
403254885Sdumbbell	while (p > t) {
404254885Sdumbbell		if (*(p - 1) != ARGFLAG)
405254885Sdumbbell			putback(*p);
406254885Sdumbbell		else {
407254885Sdumbbell			switch (*p) {
408254885Sdumbbell
409254885Sdumbbell			case '#':
410254885Sdumbbell				pbnum(argc - 2);
411254885Sdumbbell				break;
412254885Sdumbbell			case '0':
413254885Sdumbbell			case '1':
414254885Sdumbbell			case '2':
415254885Sdumbbell			case '3':
416254885Sdumbbell			case '4':
417254885Sdumbbell			case '5':
418254885Sdumbbell			case '6':
419254885Sdumbbell			case '7':
420254885Sdumbbell			case '8':
421254885Sdumbbell			case '9':
422254885Sdumbbell				if ((argno = *p - '0') < argc - 1)
423254885Sdumbbell					pbstr(argv[argno + 1]);
424254885Sdumbbell				break;
425254885Sdumbbell			case '*':
426254885Sdumbbell				for (n = argc - 1; n > 2; n--) {
427254885Sdumbbell					pbstr(argv[n]);
428254885Sdumbbell					putback(',');
429254885Sdumbbell				}
430254885Sdumbbell				pbstr(argv[2]);
431254885Sdumbbell				break;
432254885Sdumbbell			case '@':
433254885Sdumbbell				for( n = argc - 1; n >= 2; n-- )
434254885Sdumbbell				{
435254885Sdumbbell					putback(rquote);
436254885Sdumbbell					pbstr(argv[n]);
437254885Sdumbbell					putback(lquote);
438254885Sdumbbell					if( n > 2 )
439254885Sdumbbell						putback(',');
440254885Sdumbbell				}
441254885Sdumbbell				break;
442254885Sdumbbell			default:
443254885Sdumbbell				putback(*p);
444254885Sdumbbell				putback('$');
445254885Sdumbbell				break;
446254885Sdumbbell			}
447254885Sdumbbell			p--;
448254885Sdumbbell		}
449254885Sdumbbell		p--;
450254885Sdumbbell	}
451254885Sdumbbell	if (p == t)		       /* do last character */
452254885Sdumbbell		putback(*p);
453254885Sdumbbell}
454254885Sdumbbell
455254885Sdumbbell/*
456254885Sdumbbell * dodefine - install definition in the table
457254885Sdumbbell */
458254885Sdumbbellvoid
459254885Sdumbbelldodefine(name, defn)
460254885Sdumbbellregister char *name;
461254885Sdumbbellregister char *defn;
462254885Sdumbbell{
463254885Sdumbbell	register ndptr p;
464254885Sdumbbell
465254885Sdumbbell	if (!*name)
466254885Sdumbbell		errx(1, "null definition");
467254885Sdumbbell	if (STREQ(name, defn))
468254885Sdumbbell		errx(1, "%s: recursive definition", name);
469254885Sdumbbell	if ((p = lookup(name)) == nil)
470254885Sdumbbell		p = addent(name);
471254885Sdumbbell	else if (p->defn != null)
472254885Sdumbbell		free((char *) p->defn);
473254885Sdumbbell	if (!*defn)
474254885Sdumbbell		p->defn = null;
475254885Sdumbbell	else
476254885Sdumbbell		p->defn = xstrdup(defn);
477254885Sdumbbell	p->type = MACRTYPE;
478254885Sdumbbell}
479254885Sdumbbell
480254885Sdumbbell/*
481254885Sdumbbell * dodefn - push back a quoted definition of
482254885Sdumbbell *      the given name.
483254885Sdumbbell */
484254885Sdumbbellvoid
485254885Sdumbbelldodefn(name)
486254885Sdumbbellchar *name;
487254885Sdumbbell{
488254885Sdumbbell	register ndptr p;
489254885Sdumbbell
490254885Sdumbbell	if ((p = lookup(name)) != nil && p->defn != null) {
491254885Sdumbbell		putback(rquote);
492254885Sdumbbell		pbstr(p->defn);
493254885Sdumbbell		putback(lquote);
494254885Sdumbbell	}
495254885Sdumbbell}
496254885Sdumbbell
497254885Sdumbbell/*
498254885Sdumbbell * dopushdef - install a definition in the hash table
499254885Sdumbbell *      without removing a previous definition. Since
500254885Sdumbbell *      each new entry is entered in *front* of the
501254885Sdumbbell *      hash bucket, it hides a previous definition from
502254885Sdumbbell *      lookup.
503254885Sdumbbell */
504254885Sdumbbellvoid
505254885Sdumbbelldopushdef(name, defn)
506254885Sdumbbellregister char *name;
507254885Sdumbbellregister char *defn;
508254885Sdumbbell{
509254885Sdumbbell	register ndptr p;
510254885Sdumbbell
511254885Sdumbbell	if (!*name)
512254885Sdumbbell		errx(1, "null definition");
513254885Sdumbbell	if (STREQ(name, defn))
514254885Sdumbbell		errx(1, "%s: recursive definition", name);
515254885Sdumbbell	p = addent(name);
516254885Sdumbbell	if (!*defn)
517254885Sdumbbell		p->defn = null;
518254885Sdumbbell	else
519254885Sdumbbell		p->defn = xstrdup(defn);
520254885Sdumbbell	p->type = MACRTYPE;
521254885Sdumbbell}
522254885Sdumbbell
523254885Sdumbbell/*
524254885Sdumbbell * dodumpdef - dump the specified definitions in the hash
525254885Sdumbbell *      table to stderr. If nothing is specified, the entire
526254885Sdumbbell *      hash table is dumped.
527254885Sdumbbell */
528254885Sdumbbellvoid
529254885Sdumbbelldodump(argv, argc)
530254885Sdumbbellregister char *argv[];
531254885Sdumbbellregister int argc;
532254885Sdumbbell{
533254885Sdumbbell	register int n;
534254885Sdumbbell	ndptr p;
535254885Sdumbbell
536254885Sdumbbell	if (argc > 2) {
537254885Sdumbbell		for (n = 2; n < argc; n++)
538254885Sdumbbell			if ((p = lookup(argv[n])) != nil)
539254885Sdumbbell				fprintf(stderr, dumpfmt, p->name,
540254885Sdumbbell					p->defn);
541254885Sdumbbell	}
542254885Sdumbbell	else {
543254885Sdumbbell		for (n = 0; n < HASHSIZE; n++)
544254885Sdumbbell			for (p = hashtab[n]; p != nil; p = p->nxtptr)
545254885Sdumbbell				fprintf(stderr, dumpfmt, p->name,
546254885Sdumbbell					p->defn);
547254885Sdumbbell	}
548254885Sdumbbell}
549254885Sdumbbell
550254885Sdumbbell/*
551254885Sdumbbell * doifelse - select one of two alternatives - loop.
552254885Sdumbbell */
553254885Sdumbbellvoid
554254885Sdumbbelldoifelse(argv, argc)
555254885Sdumbbellregister char *argv[];
556254885Sdumbbellregister int argc;
557254885Sdumbbell{
558254885Sdumbbell	cycle {
559254885Sdumbbell		if (STREQ(argv[2], argv[3]))
560254885Sdumbbell			pbstr(argv[4]);
561254885Sdumbbell		else if (argc == 6)
562254885Sdumbbell			pbstr(argv[5]);
563254885Sdumbbell		else if (argc > 6) {
564254885Sdumbbell			argv += 3;
565254885Sdumbbell			argc -= 3;
566254885Sdumbbell			continue;
567254885Sdumbbell		}
568254885Sdumbbell		break;
569254885Sdumbbell	}
570254885Sdumbbell}
571254885Sdumbbell
572254885Sdumbbell/*
573254885Sdumbbell * doinclude - include a given file.
574254885Sdumbbell */
575254885Sdumbbellint
576254885Sdumbbelldoincl(ifile)
577254885Sdumbbellchar *ifile;
578254885Sdumbbell{
579254885Sdumbbell	if (ilevel + 1 == MAXINP)
580254885Sdumbbell		errx(1, "too many include files");
581254885Sdumbbell	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
582254885Sdumbbell		ilevel++;
583254885Sdumbbell		bbase[ilevel] = bufbase = bp;
584254885Sdumbbell		return (1);
585254885Sdumbbell	}
586254885Sdumbbell	else
587254885Sdumbbell		return (0);
588254885Sdumbbell}
589254885Sdumbbell
590254885Sdumbbell#ifdef EXTENDED
591254885Sdumbbell/*
592254885Sdumbbell * dopaste - include a given file without any
593254885Sdumbbell *           macro processing.
594254885Sdumbbell */
595254885Sdumbbellint
596254885Sdumbbelldopaste(pfile)
597254885Sdumbbellchar *pfile;
598254885Sdumbbell{
599254885Sdumbbell	FILE *pf;
600254885Sdumbbell	register int c;
601254885Sdumbbell
602254885Sdumbbell	if ((pf = fopen(pfile, "r")) != NULL) {
603254885Sdumbbell		while ((c = getc(pf)) != EOF)
604254885Sdumbbell			putc(c, active);
605254885Sdumbbell		(void) fclose(pf);
606254885Sdumbbell		return (1);
607254885Sdumbbell	}
608254885Sdumbbell	else
609254885Sdumbbell		return (0);
610254885Sdumbbell}
611254885Sdumbbell#endif
612254885Sdumbbell
613254885Sdumbbell/*
614254885Sdumbbell * dochq - change quote characters
615254885Sdumbbell */
616254885Sdumbbellvoid
617254885Sdumbbelldochq(argv, argc)
618254885Sdumbbellregister char *argv[];
619254885Sdumbbellregister int argc;
620254885Sdumbbell{
621254885Sdumbbell	if (argc > 2) {
622254885Sdumbbell		if (*argv[2])
623254885Sdumbbell			lquote = *argv[2];
624254885Sdumbbell		else
625254885Sdumbbell			lquote = LQUOTE;
626254885Sdumbbell		if (argc > 3) {
627254885Sdumbbell			if (*argv[3])
628254885Sdumbbell				rquote = *argv[3];
629254885Sdumbbell			else
630254885Sdumbbell				rquote = RQUOTE;
631254885Sdumbbell		}
632254885Sdumbbell		else
633254885Sdumbbell			rquote = lquote;
634254885Sdumbbell	}
635254885Sdumbbell	else {
636254885Sdumbbell		lquote = LQUOTE;
637254885Sdumbbell		rquote = RQUOTE;
638254885Sdumbbell	}
639254885Sdumbbell}
640254885Sdumbbell
641254885Sdumbbell/*
642254885Sdumbbell * dochc - change comment characters
643254885Sdumbbell */
644254885Sdumbbellvoid
645254885Sdumbbelldochc(argv, argc)
646254885Sdumbbellregister char *argv[];
647254885Sdumbbellregister int argc;
648254885Sdumbbell{
649254885Sdumbbell	if (argc > 2) {
650254885Sdumbbell		if (*argv[2])
651254885Sdumbbell			scommt = *argv[2];
652254885Sdumbbell		if (argc > 3) {
653254885Sdumbbell			if (*argv[3])
654254885Sdumbbell				ecommt = *argv[3];
655254885Sdumbbell		}
656254885Sdumbbell		else
657254885Sdumbbell			ecommt = ECOMMT;
658254885Sdumbbell	}
659254885Sdumbbell	else {
660254885Sdumbbell		scommt = SCOMMT;
661254885Sdumbbell		ecommt = ECOMMT;
662254885Sdumbbell	}
663254885Sdumbbell}
664254885Sdumbbell
665254885Sdumbbell/*
666254885Sdumbbell * dodivert - divert the output to a temporary file
667254885Sdumbbell */
668254885Sdumbbellvoid
669254885Sdumbbelldodiv(n)
670254885Sdumbbellregister int n;
671254885Sdumbbell{
672254885Sdumbbell	oindex = n;
673254885Sdumbbell	if (n < 0 || n >= MAXOUT)
674254885Sdumbbell		n = 0;		       /* bitbucket */
675254885Sdumbbell	if (outfile[n] == NULL) {
676254885Sdumbbell		m4temp[UNIQUE] = n + '0';
677254885Sdumbbell		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
678254885Sdumbbell			errx(1, "%s: cannot divert", m4temp);
679254885Sdumbbell	}
680254885Sdumbbell	active = outfile[n];
681254885Sdumbbell}
682254885Sdumbbell
683254885Sdumbbell/*
684254885Sdumbbell * doundivert - undivert a specified output, or all
685254885Sdumbbell *              other outputs, in numerical order.
686254885Sdumbbell */
687254885Sdumbbellvoid
688254885Sdumbbelldoundiv(argv, argc)
689254885Sdumbbellregister char *argv[];
690254885Sdumbbellregister int argc;
691254885Sdumbbell{
692254885Sdumbbell	register int ind;
693254885Sdumbbell	register int n;
694254885Sdumbbell
695254885Sdumbbell	if (argc > 2) {
696254885Sdumbbell		for (ind = 2; ind < argc; ind++) {
697254885Sdumbbell			n = atoi(argv[ind]);
698254885Sdumbbell			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
699254885Sdumbbell				getdiv(n);
700254885Sdumbbell
701254885Sdumbbell		}
702254885Sdumbbell	}
703254885Sdumbbell	else
704254885Sdumbbell		for (n = 1; n < MAXOUT; n++)
705254885Sdumbbell			if (outfile[n] != NULL)
706254885Sdumbbell				getdiv(n);
707254885Sdumbbell}
708254885Sdumbbell
709254885Sdumbbell/*
710254885Sdumbbell * dosub - select substring
711254885Sdumbbell */
712254885Sdumbbellvoid
713254885Sdumbbelldosub(argv, argc)
714254885Sdumbbellregister char *argv[];
715254885Sdumbbellregister int argc;
716254885Sdumbbell{
717254885Sdumbbell	register unsigned char *ap, *fc, *k;
718254885Sdumbbell	register int nc;
719254885Sdumbbell
720254885Sdumbbell	if (argc < 5)
721254885Sdumbbell		nc = MAXTOK;
722254885Sdumbbell	else
723254885Sdumbbell#ifdef EXPR
724254885Sdumbbell		nc = expr(argv[4]);
725254885Sdumbbell#else
726254885Sdumbbell		nc = atoi(argv[4]);
727254885Sdumbbell#endif
728254885Sdumbbell	ap = argv[2];		       /* target string */
729254885Sdumbbell#ifdef EXPR
730254885Sdumbbell	fc = ap + expr(argv[3]);       /* first char */
731254885Sdumbbell#else
732254885Sdumbbell	fc = ap + atoi(argv[3]);       /* first char */
733254885Sdumbbell#endif
734254885Sdumbbell	if (fc >= ap && fc < ap + strlen(ap))
735254885Sdumbbell		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
736254885Sdumbbell			putback(*k);
737254885Sdumbbell}
738254885Sdumbbell
739254885Sdumbbell/*
740254885Sdumbbell * map:
741254885Sdumbbell * map every character of s1 that is specified in from
742254885Sdumbbell * into s3 and replace in s. (source s1 remains untouched)
743254885Sdumbbell *
744254885Sdumbbell * This is a standard implementation of map(s,from,to) function of ICON
745254885Sdumbbell * language. Within mapvec, we replace every character of "from" with
746254885Sdumbbell * the corresponding character in "to". If "to" is shorter than "from",
747254885Sdumbbell * than the corresponding entries are null, which means that those
748254885Sdumbbell * characters dissapear altogether. Furthermore, imagine
749254885Sdumbbell * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
750254885Sdumbbell * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
751254885Sdumbbell * ultimately maps to `*'. In order to achieve this effect in an efficient
752254885Sdumbbell * manner (i.e. without multiple passes over the destination string), we
753254885Sdumbbell * loop over mapvec, starting with the initial source character. if the
754254885Sdumbbell * character value (dch) in this location is different than the source
755254885Sdumbbell * character (sch), sch becomes dch, once again to index into mapvec, until
756254885Sdumbbell * the character value stabilizes (i.e. sch = dch, in other words
757254885Sdumbbell * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
758254885Sdumbbell * character, it will stabilize, since mapvec[0] == 0 at all times. At the
759254885Sdumbbell * end, we restore mapvec* back to normal where mapvec[n] == n for
760254885Sdumbbell * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
761254885Sdumbbell * about 5 times faster than any algorithm that makes multiple passes over
762254885Sdumbbell * destination string.
763254885Sdumbbell */
764254885Sdumbbellvoid
765254885Sdumbbellmap(dest, src, from, to)
766254885Sdumbbellregister char *dest;
767254885Sdumbbellregister char *src;
768254885Sdumbbellregister char *from;
769254885Sdumbbellregister char *to;
770254885Sdumbbell{
771254885Sdumbbell	register char *tmp;
772254885Sdumbbell	register char sch, dch;
773254885Sdumbbell	static char mapvec[128] = {
774254885Sdumbbell		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
775254885Sdumbbell		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
776254885Sdumbbell		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
777254885Sdumbbell		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
778254885Sdumbbell		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
779254885Sdumbbell		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
780254885Sdumbbell		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
781254885Sdumbbell		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
782254885Sdumbbell		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
783254885Sdumbbell		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
784254885Sdumbbell		120, 121, 122, 123, 124, 125, 126, 127
785254885Sdumbbell	};
786254885Sdumbbell
787254885Sdumbbell	if (*src) {
788254885Sdumbbell		tmp = from;
789254885Sdumbbell	/*
790254885Sdumbbell	 * create a mapping between "from" and
791254885Sdumbbell	 * "to"
792254885Sdumbbell	 */
793254885Sdumbbell		while (*from)
794254885Sdumbbell			mapvec[*from++] = (*to) ? *to++ : (char) 0;
795254885Sdumbbell
796254885Sdumbbell		while (*src) {
797254885Sdumbbell			sch = *src++;
798254885Sdumbbell			dch = mapvec[sch];
799254885Sdumbbell			while (dch != sch) {
800254885Sdumbbell				sch = dch;
801254885Sdumbbell				dch = mapvec[sch];
802254885Sdumbbell			}
803254885Sdumbbell			if (*dest = dch)
804254885Sdumbbell				dest++;
805254885Sdumbbell		}
806254885Sdumbbell	/*
807254885Sdumbbell	 * restore all the changed characters
808254885Sdumbbell	 */
809254885Sdumbbell		while (*tmp) {
810254885Sdumbbell			mapvec[*tmp] = *tmp;
811254885Sdumbbell			tmp++;
812254885Sdumbbell		}
813254885Sdumbbell	}
814254885Sdumbbell	*dest = (char) 0;
815254885Sdumbbell}
816254885Sdumbbell