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