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