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