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