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