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