Deleted Added
sdiff udiff text old ( 228697 ) new ( 228701 )
full compact
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}