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