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