eval.c revision 114368
1/*	$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $	*/
2/*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3
4/*
5 * Copyright (c) 1989, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
43#else
44#if 0
45static char rcsid[] = "$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $";
46#endif
47#endif
48#endif /* not lint */
49
50#include <sys/cdefs.h>
51__FBSDID("$FreeBSD: head/usr.bin/m4/eval.c 114368 2003-05-01 02:36:27Z tjr $");
52
53/*
54 * eval.c
55 * Facility: m4 macro processor
56 * by: oz
57 */
58
59#include <sys/types.h>
60#include <errno.h>
61#include <unistd.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <stddef.h>
65#include <string.h>
66#include <fcntl.h>
67#include <err.h>
68#include "mdef.h"
69#include "stdd.h"
70#include "extern.h"
71#include "pathnames.h"
72
73#define BUILTIN_MARKER	"__builtin_"
74
75static void	dodefn(const char *);
76static void	dopushdef(const char *, const char *);
77static void	dodump(const char *[], int);
78static void	dotrace(const char *[], int, int);
79static void	doifelse(const char *[], int);
80static int	doincl(const char *);
81static int	dopaste(const char *);
82static void	gnu_dochq(const char *[], int);
83static void	dochq(const char *[], int);
84static void	gnu_dochc(const char *[], int);
85static void	dochc(const char *[], int);
86static void	dodiv(int);
87static void	doundiv(const char *[], int);
88static void	dosub(const char *[], int);
89static void	map(char *, const char *, const char *, const char *);
90static const char *handledash(char *, char *, const char *);
91static void	expand_builtin(const char *[], int, int);
92static void	expand_macro(const char *[], int);
93static void	dump_one_def(ndptr);
94
95unsigned long	expansion_id;
96
97/*
98 * eval - eval all macros and builtins calls
99 *	  argc - number of elements in argv.
100 *	  argv - element vector :
101 *			argv[0] = definition of a user
102 *				  macro or nil if built-in.
103 *			argv[1] = name of the macro or
104 *				  built-in.
105 *			argv[2] = parameters to user-defined
106 *			   .	  macro or built-in.
107 *			   .
108 *
109 * A call in the form of macro-or-builtin() will result in:
110 *			argv[0] = nullstr
111 *			argv[1] = macro-or-builtin
112 *			argv[2] = nullstr
113 *
114 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
115 */
116void
117eval(const char *argv[], int argc, int td)
118{
119	ssize_t mark = -1;
120
121	expansion_id++;
122	if (td & RECDEF)
123		errx(1, "%s at line %lu: expanding recursive definition for %s",
124			CURRENT_NAME, CURRENT_LINE, argv[1]);
125	if (traced_macros && is_traced(argv[1]))
126		mark = trace(argv, argc, infile+ilevel);
127	if (td == MACRTYPE)
128		expand_macro(argv, argc);
129	else
130		expand_builtin(argv, argc, td);
131    	if (mark != -1)
132		finish_trace(mark);
133}
134
135/*
136 * expand_builtin - evaluate built-in macros.
137 */
138void
139expand_builtin(const char *argv[], int argc, int td)
140{
141	int c, n;
142	int ac;
143	static int sysval = 0;
144
145#ifdef DEBUG
146	printf("argc = %d\n", argc);
147	for (n = 0; n < argc; n++)
148		printf("argv[%d] = %s\n", n, argv[n]);
149	fflush(stdout);
150#endif
151
152 /*
153  * if argc == 3 and argv[2] is null, then we
154  * have macro-or-builtin() type call. We adjust
155  * argc to avoid further checking..
156  */
157  	ac = argc;
158
159	if (argc == 3 && !*(argv[2]))
160		argc--;
161
162	switch (td & TYPEMASK) {
163
164	case DEFITYPE:
165		if (argc > 2)
166			dodefine(argv[2], (argc > 3) ? argv[3] : null);
167		break;
168
169	case PUSDTYPE:
170		if (argc > 2)
171			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
172		break;
173
174	case DUMPTYPE:
175		dodump(argv, argc);
176		break;
177
178	case TRACEONTYPE:
179		dotrace(argv, argc, 1);
180		break;
181
182	case TRACEOFFTYPE:
183		dotrace(argv, argc, 0);
184		break;
185
186	case EXPRTYPE:
187	/*
188	 * doexpr - evaluate arithmetic
189	 * expression
190	 */
191		if (argc > 2)
192			pbnum(expr(argv[2]));
193		break;
194
195	case IFELTYPE:
196		if (argc > 4)
197			doifelse(argv, argc);
198		break;
199
200	case IFDFTYPE:
201	/*
202	 * doifdef - select one of two
203	 * alternatives based on the existence of
204	 * another definition
205	 */
206		if (argc > 3) {
207			if (lookup(argv[2]) != nil)
208				pbstr(argv[3]);
209			else if (argc > 4)
210				pbstr(argv[4]);
211		}
212		break;
213
214	case LENGTYPE:
215	/*
216	 * dolen - find the length of the
217	 * argument
218	 */
219		pbnum((argc > 2) ? strlen(argv[2]) : 0);
220		break;
221
222	case INCRTYPE:
223	/*
224	 * doincr - increment the value of the
225	 * argument
226	 */
227		if (argc > 2)
228			pbnum(atoi(argv[2]) + 1);
229		break;
230
231	case DECRTYPE:
232	/*
233	 * dodecr - decrement the value of the
234	 * argument
235	 */
236		if (argc > 2)
237			pbnum(atoi(argv[2]) - 1);
238		break;
239
240	case SYSCTYPE:
241	/*
242	 * dosys - execute system command
243	 */
244		if (argc > 2) {
245			fflush(NULL);
246			sysval = system(argv[2]);
247		}
248		break;
249
250	case SYSVTYPE:
251	/*
252	 * dosysval - return value of the last
253	 * system call.
254	 *
255	 */
256		pbnum(sysval);
257		break;
258
259	case ESYSCMDTYPE:
260		if (argc > 2)
261			doesyscmd(argv[2]);
262	    	break;
263	case INCLTYPE:
264		if (argc > 2)
265			if (!doincl(argv[2]))
266				err(1, "%s at line %lu: include(%s)",
267				    CURRENT_NAME, CURRENT_LINE, argv[2]);
268		break;
269
270	case SINCTYPE:
271		if (argc > 2)
272			(void) doincl(argv[2]);
273		break;
274#ifdef EXTENDED
275	case PASTTYPE:
276		if (argc > 2)
277			if (!dopaste(argv[2]))
278				err(1, "%s at line %lu: paste(%s)",
279				    CURRENT_NAME, CURRENT_LINE, argv[2]);
280		break;
281
282	case SPASTYPE:
283		if (argc > 2)
284			(void) dopaste(argv[2]);
285		break;
286#endif
287	case CHNQTYPE:
288		if (mimic_gnu)
289			gnu_dochq(argv, ac);
290		else
291			dochq(argv, argc);
292		break;
293
294	case CHNCTYPE:
295		if (mimic_gnu)
296			gnu_dochc(argv, ac);
297		else
298			dochc(argv, argc);
299		break;
300
301	case SUBSTYPE:
302	/*
303	 * dosub - select substring
304	 *
305	 */
306		if (argc > 3)
307			dosub(argv, argc);
308		break;
309
310	case SHIFTYPE:
311	/*
312	 * doshift - push back all arguments
313	 * except the first one (i.e. skip
314	 * argv[2])
315	 */
316		if (argc > 3) {
317			for (n = argc - 1; n > 3; n--) {
318				pbstr(rquote);
319				pbstr(argv[n]);
320				pbstr(lquote);
321				putback(COMMA);
322			}
323			pbstr(rquote);
324			pbstr(argv[3]);
325			pbstr(lquote);
326		}
327		break;
328
329	case DIVRTYPE:
330		if (argc > 2 && (n = atoi(argv[2])) != 0)
331			dodiv(n);
332		else {
333			active = stdout;
334			oindex = 0;
335		}
336		break;
337
338	case UNDVTYPE:
339		doundiv(argv, argc);
340		break;
341
342	case DIVNTYPE:
343	/*
344	 * dodivnum - return the number of
345	 * current output diversion
346	 */
347		pbnum(oindex);
348		break;
349
350	case UNDFTYPE:
351	/*
352	 * doundefine - undefine a previously
353	 * defined macro(s) or m4 keyword(s).
354	 */
355		if (argc > 2)
356			for (n = 2; n < argc; n++)
357				remhash(argv[n], ALL);
358		break;
359
360	case POPDTYPE:
361	/*
362	 * dopopdef - remove the topmost
363	 * definitions of macro(s) or m4
364	 * keyword(s).
365	 */
366		if (argc > 2)
367			for (n = 2; n < argc; n++)
368				remhash(argv[n], TOP);
369		break;
370
371	case MKTMTYPE:
372	/*
373	 * dotemp - create a temporary file
374	 */
375		if (argc > 2) {
376			int fd;
377			char *temp;
378
379			temp = xstrdup(argv[2]);
380
381			fd = mkstemp(temp);
382			if (fd == -1)
383				err(1,
384	    "%s at line %lu: couldn't make temp file %s",
385	    CURRENT_NAME, CURRENT_LINE, argv[2]);
386			close(fd);
387			pbstr(temp);
388			free(temp);
389		}
390		break;
391
392	case TRNLTYPE:
393	/*
394	 * dotranslit - replace all characters in
395	 * the source string that appears in the
396	 * "from" string with the corresponding
397	 * characters in the "to" string.
398	 */
399		if (argc > 3) {
400			char *temp;
401
402			temp = xalloc(strlen(argv[2])+1);
403			if (argc > 4)
404				map(temp, argv[2], argv[3], argv[4]);
405			else
406				map(temp, argv[2], argv[3], null);
407			pbstr(temp);
408			free(temp);
409		} else if (argc > 2)
410			pbstr(argv[2]);
411		break;
412
413	case INDXTYPE:
414	/*
415	 * doindex - find the index of the second
416	 * argument string in the first argument
417	 * string. -1 if not present.
418	 */
419		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
420		break;
421
422	case ERRPTYPE:
423	/*
424	 * doerrp - print the arguments to stderr
425	 * file
426	 */
427		if (argc > 2) {
428			for (n = 2; n < argc; n++)
429				fprintf(stderr, "%s ", argv[n]);
430			fprintf(stderr, "\n");
431		}
432		break;
433
434	case DNLNTYPE:
435	/*
436	 * dodnl - eat-up-to and including
437	 * newline
438	 */
439		while ((c = gpbc()) != '\n' && c != EOF)
440			;
441		break;
442
443	case M4WRTYPE:
444	/*
445	 * dom4wrap - set up for
446	 * wrap-up/wind-down activity
447	 */
448		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
449		break;
450
451	case EXITTYPE:
452	/*
453	 * doexit - immediate exit from m4.
454	 */
455		killdiv();
456		exit((argc > 2) ? atoi(argv[2]) : 0);
457		break;
458
459	case DEFNTYPE:
460		if (argc > 2)
461			for (n = 2; n < argc; n++)
462				dodefn(argv[n]);
463		break;
464
465	case INDIRTYPE:	/* Indirect call */
466		if (argc > 2)
467			doindir(argv, argc);
468		break;
469
470	case BUILTINTYPE: /* Builtins only */
471		if (argc > 2)
472			dobuiltin(argv, argc);
473		break;
474
475	case PATSTYPE:
476		if (argc > 2)
477			dopatsubst(argv, argc);
478		break;
479	case REGEXPTYPE:
480		if (argc > 2)
481			doregexp(argv, argc);
482		break;
483	case LINETYPE:
484		doprintlineno(infile+ilevel);
485		break;
486	case FILENAMETYPE:
487		doprintfilename(infile+ilevel);
488		break;
489	case SELFTYPE:
490		pbstr(rquote);
491		pbstr(argv[1]);
492		pbstr(lquote);
493		break;
494	default:
495		errx(1, "%s at line %lu: eval: major botch.",
496			CURRENT_NAME, CURRENT_LINE);
497		break;
498	}
499}
500
501/*
502 * expand_macro - user-defined macro expansion
503 */
504void
505expand_macro(const char *argv[], int argc)
506{
507	const char *t;
508	const char *p;
509	int n;
510	int argno;
511
512	t = argv[0];		       /* defn string as a whole */
513	p = t;
514	while (*p)
515		p++;
516	p--;			       /* last character of defn */
517	while (p > t) {
518		if (*(p - 1) != ARGFLAG)
519			PUTBACK(*p);
520		else {
521			switch (*p) {
522
523			case '#':
524				pbnum(argc - 2);
525				break;
526			case '0':
527			case '1':
528			case '2':
529			case '3':
530			case '4':
531			case '5':
532			case '6':
533			case '7':
534			case '8':
535			case '9':
536				if ((argno = *p - '0') < argc - 1)
537					pbstr(argv[argno + 1]);
538				break;
539			case '*':
540				if (argc > 2) {
541					for (n = argc - 1; n > 2; n--) {
542						pbstr(argv[n]);
543						putback(COMMA);
544					}
545					pbstr(argv[2]);
546			    	}
547				break;
548                        case '@':
549				if (argc > 2) {
550					for (n = argc - 1; n > 2; n--) {
551						pbstr(rquote);
552						pbstr(argv[n]);
553						pbstr(lquote);
554						putback(COMMA);
555					}
556					pbstr(rquote);
557					pbstr(argv[2]);
558					pbstr(lquote);
559				}
560                                break;
561			default:
562				PUTBACK(*p);
563				PUTBACK('$');
564				break;
565			}
566			p--;
567		}
568		p--;
569	}
570	if (p == t)		       /* do last character */
571		PUTBACK(*p);
572}
573
574/*
575 * dodefine - install definition in the table
576 */
577void
578dodefine(const char *name, const char *defn)
579{
580	ndptr p;
581	int n;
582
583	if (!*name)
584		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
585		    CURRENT_LINE);
586	if ((p = lookup(name)) == nil)
587		p = addent(name);
588	else if (p->defn != null)
589		free((char *) p->defn);
590	if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
591		n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
592		if (n != -1) {
593			p->type = n & TYPEMASK;
594			if ((n & NOARGS) == 0)
595				p->type |= NEEDARGS;
596			p->defn = xstrdup(null);
597			return;
598		}
599	}
600	if (!*defn)
601		p->defn = xstrdup(null);
602	else
603		p->defn = xstrdup(defn);
604	p->type = MACRTYPE;
605	if (STREQ(name, defn))
606		p->type |= RECDEF;
607}
608
609/*
610 * dodefn - push back a quoted definition of
611 *      the given name.
612 */
613static void
614dodefn(const char *name)
615{
616	ndptr p;
617	const char *real;
618
619	if ((p = lookup(name)) != nil) {
620		if (p->defn != null) {
621			pbstr(rquote);
622			pbstr(p->defn);
623			pbstr(lquote);
624		} else if ((real = builtin_realname(p->type)) != NULL) {
625			pbstr(real);
626			pbstr(BUILTIN_MARKER);
627		}
628	}
629}
630
631/*
632 * dopushdef - install a definition in the hash table
633 *      without removing a previous definition. Since
634 *      each new entry is entered in *front* of the
635 *      hash bucket, it hides a previous definition from
636 *      lookup.
637 */
638static void
639dopushdef(const char *name, const char *defn)
640{
641	ndptr p;
642
643	if (!*name)
644		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
645		    CURRENT_LINE);
646	p = addent(name);
647	if (!*defn)
648		p->defn = xstrdup(null);
649	else
650		p->defn = xstrdup(defn);
651	p->type = MACRTYPE;
652	if (STREQ(name, defn))
653		p->type |= RECDEF;
654}
655
656/*
657 * dump_one_def - dump the specified definition.
658 */
659static void
660dump_one_def(ndptr p)
661{
662	const char *real;
663
664	if (mimic_gnu) {
665		if ((p->type & TYPEMASK) == MACRTYPE)
666			fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
667		else {
668			real = builtin_realname(p->type);
669			if (real == NULL)
670				real = null;
671			fprintf(traceout, "%s:\t<%s>\n", p->name, real);
672	    	}
673	} else
674		fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
675}
676
677/*
678 * dodumpdef - dump the specified definitions in the hash
679 *      table to stderr. If nothing is specified, the entire
680 *      hash table is dumped.
681 */
682static void
683dodump(const char *argv[], int argc)
684{
685	int n;
686	ndptr p;
687
688	if (argc > 2) {
689		for (n = 2; n < argc; n++)
690			if ((p = lookup(argv[n])) != nil)
691				dump_one_def(p);
692	} else {
693		for (n = 0; n < HASHSIZE; n++)
694			for (p = hashtab[n]; p != nil; p = p->nxtptr)
695				dump_one_def(p);
696	}
697}
698
699/*
700 * dotrace - mark some macros as traced/untraced depending upon on.
701 */
702static void
703dotrace(const char *argv[], int argc, int on)
704{
705	int n;
706
707	if (argc > 2) {
708		for (n = 2; n < argc; n++)
709			mark_traced(argv[n], on);
710	} else
711		mark_traced(NULL, on);
712}
713
714/*
715 * doifelse - select one of two alternatives - loop.
716 */
717static void
718doifelse(const char *argv[], int argc)
719{
720	cycle {
721		if (STREQ(argv[2], argv[3]))
722			pbstr(argv[4]);
723		else if (argc == 6)
724			pbstr(argv[5]);
725		else if (argc > 6) {
726			argv += 3;
727			argc -= 3;
728			continue;
729		}
730		break;
731	}
732}
733
734/*
735 * doinclude - include a given file.
736 */
737static int
738doincl(const char *ifile)
739{
740	if (ilevel + 1 == MAXINP)
741		errx(1, "%s at line %lu: too many include files.",
742		    CURRENT_NAME, CURRENT_LINE);
743	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
744		ilevel++;
745		if ((inname[ilevel] = strdup(ifile)) == NULL)
746			err(1, NULL);
747		inlineno[ilevel] = 1;
748		bbase[ilevel] = bufbase = bp;
749		emitline();
750		return (1);
751	} else
752		return (0);
753}
754
755#ifdef EXTENDED
756/*
757 * dopaste - include a given file without any
758 *           macro processing.
759 */
760static int
761dopaste(const char *pfile)
762{
763	FILE *pf;
764	int c;
765
766	if ((pf = fopen(pfile, "r")) != NULL) {
767		fprintf(active, "#line 1 \"%s\"\n", pfile);
768		while ((c = getc(pf)) != EOF)
769			putc(c, active);
770		(void) fclose(pf);
771		emitline();
772		return (1);
773	} else
774		return (0);
775}
776#endif
777
778static void
779gnu_dochq(const char *argv[], int ac)
780{
781	/* In gnu-m4 mode, the only way to restore quotes is to have no
782	 * arguments at all. */
783	if (ac == 2) {
784		lquote[0] = LQUOTE, lquote[1] = EOS;
785		rquote[0] = RQUOTE, rquote[1] = EOS;
786	} else {
787		strlcpy(lquote, argv[2], sizeof(lquote));
788		if(ac > 3)
789			strlcpy(rquote, argv[3], sizeof(rquote));
790		else
791			rquote[0] = EOS;
792	}
793}
794
795/*
796 * dochq - change quote characters
797 */
798static void
799dochq(const char *argv[], int argc)
800{
801	if (argc > 2) {
802		if (*argv[2])
803			strlcpy(lquote, argv[2], sizeof(lquote));
804		else {
805			lquote[0] = LQUOTE;
806			lquote[1] = EOS;
807		}
808		if (argc > 3) {
809			if (*argv[3])
810				strlcpy(rquote, argv[3], sizeof(rquote));
811		} else
812			strcpy(rquote, lquote);
813	} else {
814		lquote[0] = LQUOTE, lquote[1] = EOS;
815		rquote[0] = RQUOTE, rquote[1] = EOS;
816	}
817}
818
819static void
820gnu_dochc(const char *argv[], int ac)
821{
822	/* In gnu-m4 mode, no arguments mean no comment
823	 * arguments at all. */
824	if (ac == 2) {
825		scommt[0] = EOS;
826		ecommt[0] = EOS;
827	} else {
828		if (*argv[2])
829			strlcpy(scommt, argv[2], sizeof(scommt));
830		else
831			scommt[0] = SCOMMT, scommt[1] = EOS;
832		if(ac > 3 && *argv[3])
833			strlcpy(ecommt, argv[3], sizeof(ecommt));
834		else
835			ecommt[0] = ECOMMT, ecommt[1] = EOS;
836	}
837}
838/*
839 * dochc - change comment characters
840 */
841static void
842dochc(const char *argv[], int argc)
843{
844	if (argc > 2) {
845		if (*argv[2])
846			strlcpy(scommt, argv[2], sizeof(scommt));
847		if (argc > 3) {
848			if (*argv[3])
849				strlcpy(ecommt, argv[3], sizeof(ecommt));
850		}
851		else
852			ecommt[0] = ECOMMT, ecommt[1] = EOS;
853	}
854	else {
855		scommt[0] = SCOMMT, scommt[1] = EOS;
856		ecommt[0] = ECOMMT, ecommt[1] = EOS;
857	}
858}
859
860/*
861 * dodivert - divert the output to a temporary file
862 */
863static void
864dodiv(int n)
865{
866	int fd;
867
868	oindex = n;
869	if (n >= maxout) {
870		if (mimic_gnu)
871			resizedivs(n + 10);
872		else
873			n = 0;		/* bitbucket */
874    	}
875
876	if (n < 0)
877		n = 0;		       /* bitbucket */
878	if (outfile[n] == NULL) {
879		char fname[] = _PATH_DIVNAME;
880
881		if ((fd = mkstemp(fname)) < 0 ||
882			(outfile[n] = fdopen(fd, "w+")) == NULL)
883				err(1, "%s: cannot divert", fname);
884		if (unlink(fname) == -1)
885			err(1, "%s: cannot unlink", fname);
886	}
887	active = outfile[n];
888}
889
890/*
891 * doundivert - undivert a specified output, or all
892 *              other outputs, in numerical order.
893 */
894static void
895doundiv(const char *argv[], int argc)
896{
897	int ind;
898	int n;
899
900	if (argc > 2) {
901		for (ind = 2; ind < argc; ind++) {
902			n = atoi(argv[ind]);
903			if (n > 0 && n < maxout && outfile[n] != NULL)
904				getdiv(n);
905
906		}
907	}
908	else
909		for (n = 1; n < maxout; n++)
910			if (outfile[n] != NULL)
911				getdiv(n);
912}
913
914/*
915 * dosub - select substring
916 */
917static void
918dosub(const char *argv[], int argc)
919{
920	const char *ap, *fc, *k;
921	int nc;
922
923	ap = argv[2];		       /* target string */
924#ifdef EXPR
925	fc = ap + expr(argv[3]);       /* first char */
926#else
927	fc = ap + atoi(argv[3]);       /* first char */
928#endif
929	nc = strlen(fc);
930	if (argc >= 5)
931#ifdef EXPR
932		nc = min(nc, expr(argv[4]));
933#else
934		nc = min(nc, atoi(argv[4]));
935#endif
936	if (fc >= ap && fc < ap + strlen(ap))
937		for (k = fc + nc - 1; k >= fc; k--)
938			putback(*k);
939}
940
941/*
942 * map:
943 * map every character of s1 that is specified in from
944 * into s3 and replace in s. (source s1 remains untouched)
945 *
946 * This is a standard implementation of map(s,from,to) function of ICON
947 * language. Within mapvec, we replace every character of "from" with
948 * the corresponding character in "to". If "to" is shorter than "from",
949 * than the corresponding entries are null, which means that those
950 * characters dissapear altogether. Furthermore, imagine
951 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
952 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
953 * ultimately maps to `*'. In order to achieve this effect in an efficient
954 * manner (i.e. without multiple passes over the destination string), we
955 * loop over mapvec, starting with the initial source character. if the
956 * character value (dch) in this location is different than the source
957 * character (sch), sch becomes dch, once again to index into mapvec, until
958 * the character value stabilizes (i.e. sch = dch, in other words
959 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
960 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
961 * end, we restore mapvec* back to normal where mapvec[n] == n for
962 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
963 * about 5 times faster than any algorithm that makes multiple passes over
964 * destination string.
965 */
966static void
967map(char *dest, const char *src, const char *from, const char *to)
968{
969	const char *tmp;
970	unsigned char sch, dch;
971	static char frombis[257];
972	static char tobis[257];
973	static unsigned char mapvec[256] = {
974	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
975	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
976	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
977	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
978	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
979	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
980	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
981	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
982	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
983	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
984	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
985	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
986	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
987	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
988	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
989	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
990	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
991	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
992	};
993
994	if (*src) {
995		if (mimic_gnu) {
996			/*
997			 * expand character ranges on the fly
998			 */
999			from = handledash(frombis, frombis + 256, from);
1000			to = handledash(tobis, tobis + 256, to);
1001		}
1002		tmp = from;
1003	/*
1004	 * create a mapping between "from" and
1005	 * "to"
1006	 */
1007		while (*from)
1008			mapvec[(unsigned char)(*from++)] = (*to) ?
1009				(unsigned char)(*to++) : 0;
1010
1011		while (*src) {
1012			sch = (unsigned char)(*src++);
1013			dch = mapvec[sch];
1014			while (dch != sch) {
1015				sch = dch;
1016				dch = mapvec[sch];
1017			}
1018			if ((*dest = (char)dch))
1019				dest++;
1020		}
1021	/*
1022	 * restore all the changed characters
1023	 */
1024		while (*tmp) {
1025			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1026			tmp++;
1027		}
1028	}
1029	*dest = '\0';
1030}
1031
1032
1033/*
1034 * handledash:
1035 *  use buffer to copy the src string, expanding character ranges
1036 * on the way.
1037 */
1038static const char *
1039handledash(char *buffer, char *end, const char *src)
1040{
1041	char *p;
1042
1043	p = buffer;
1044	while(*src) {
1045		if (src[1] == '-' && src[2]) {
1046			unsigned char i;
1047			for (i = (unsigned char)src[0];
1048			    i <= (unsigned char)src[2]; i++) {
1049				*p++ = i;
1050				if (p == end) {
1051					*p = '\0';
1052					return buffer;
1053				}
1054			}
1055			src += 3;
1056		} else
1057			*p++ = *src++;
1058		if (p == end)
1059			break;
1060	}
1061	*p = '\0';
1062	return buffer;
1063}
1064