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