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