Sync with manuals from netbsd-8 branch.
[minix3.git] / usr.bin / m4 / eval.c
blob8b36406461e271c4c7d603f25efef0cd04125661
1 /* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */
2 /* $NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $ */
4 /*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
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.
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.
37 * eval.c
38 * Facility: m4 macro processor
39 * by: oz
41 #if HAVE_NBTOOL_CONFIG_H
42 #include "nbtool_config.h"
43 #endif
44 #include <sys/cdefs.h>
45 __RCSID("$NetBSD: eval.c,v 1.23 2015/01/29 19:26:20 christos Exp $");
47 #include <sys/types.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <stddef.h>
55 #include <stdint.h>
56 #include <string.h>
57 #include <inttypes.h>
58 #include <fcntl.h>
59 #include "mdef.h"
60 #include "stdd.h"
61 #include "extern.h"
62 #include "pathnames.h"
64 static void dodefn(const char *);
65 static void dopushdef(const char *, const char *);
66 static void dodump(const char *[], int);
67 static void dotrace(const char *[], int, int);
68 static void doifelse(const char *[], int);
69 static int doincl(const char *);
70 static int dopaste(const char *);
71 static void dochq(const char *[], int);
72 static void dochc(const char *[], int);
73 static void dom4wrap(const char *);
74 static void dodiv(int);
75 static void doundiv(const char *[], int);
76 static void dosub(const char *[], int);
77 static void map(char *, const char *, const char *, const char *);
78 static const char *handledash(char *, char *, const char *);
79 static void expand_builtin(const char *[], int, int);
80 static void expand_macro(const char *[], int);
81 static void dump_one_def(const char *, struct macro_definition *);
83 unsigned long expansion_id;
86 * eval - eval all macros and builtins calls
87 * argc - number of elements in argv.
88 * argv - element vector :
89 * argv[0] = definition of a user
90 * macro or NULL if built-in.
91 * argv[1] = name of the macro or
92 * built-in.
93 * argv[2] = parameters to user-defined
94 * . macro or built-in.
95 * .
97 * A call in the form of macro-or-builtin() will result in:
98 * argv[0] = nullstr
99 * argv[1] = macro-or-builtin
100 * argv[2] = nullstr
102 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
104 void
105 eval(const char *argv[], int argc, int td, int is_traced)
107 size_t mark = SIZE_MAX;
109 expansion_id++;
110 if (td & RECDEF)
111 m4errx(1, "expanding recursive definition for %s.", argv[1]);
112 if (is_traced)
113 mark = trace(argv, argc, infile+ilevel);
114 if (td == MACRTYPE)
115 expand_macro(argv, argc);
116 else
117 expand_builtin(argv, argc, td);
118 if (mark != SIZE_MAX)
119 finish_trace(mark);
123 * expand_builtin - evaluate built-in macros.
125 void
126 expand_builtin(const char *argv[], int argc, int td)
128 int c, n;
129 int ac;
130 static int sysval = 0;
132 #ifdef DEBUG
133 printf("argc = %d\n", argc);
134 for (n = 0; n < argc; n++)
135 printf("argv[%d] = %s\n", n, argv[n]);
136 fflush(stdout);
137 #endif
140 * if argc == 3 and argv[2] is null, then we
141 * have macro-or-builtin() type call. We adjust
142 * argc to avoid further checking..
144 /* we keep the initial value for those built-ins that differentiate
145 * between builtin() and builtin.
147 ac = argc;
149 if (argc == 3 && !*(argv[2]) && !mimic_gnu)
150 argc--;
152 switch (td & TYPEMASK) {
154 case DEFITYPE:
155 if (argc > 2)
156 dodefine(argv[2], (argc > 3) ? argv[3] : null);
157 break;
159 case PUSDTYPE:
160 if (argc > 2)
161 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
162 break;
164 case DUMPTYPE:
165 dodump(argv, argc);
166 break;
168 case TRACEONTYPE:
169 dotrace(argv, argc, 1);
170 break;
172 case TRACEOFFTYPE:
173 dotrace(argv, argc, 0);
174 break;
176 case EXPRTYPE:
178 * doexpr - evaluate arithmetic
179 * expression
182 int base = 10;
183 int maxdigits = 0;
184 int e;
186 if (argc > 3) {
187 base = strtoi(argv[3], NULL, 0, 2, 36, &e);
188 if (e) {
189 m4errx(1, "expr: base %s invalid.", argv[3]);
192 if (argc > 4) {
193 maxdigits = strtoi(argv[4], NULL, 0, 0, INT_MAX, &e);
194 if (e) {
195 m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
198 if (argc > 2)
199 pbnumbase(expr(argv[2]), base, maxdigits);
200 break;
203 case IFELTYPE:
204 if (argc > 4)
205 doifelse(argv, argc);
206 break;
208 case IFDFTYPE:
210 * doifdef - select one of two
211 * alternatives based on the existence of
212 * another definition
214 if (argc > 3) {
215 if (lookup_macro_definition(argv[2]) != NULL)
216 pbstr(argv[3]);
217 else if (argc > 4)
218 pbstr(argv[4]);
220 break;
222 case LENGTYPE:
224 * dolen - find the length of the
225 * argument
227 pbnum((argc > 2) ? strlen(argv[2]) : 0);
228 break;
230 case INCRTYPE:
232 * doincr - increment the value of the
233 * argument
235 if (argc > 2)
236 pbnum(atoi(argv[2]) + 1);
237 break;
239 case DECRTYPE:
241 * dodecr - decrement the value of the
242 * argument
244 if (argc > 2)
245 pbnum(atoi(argv[2]) - 1);
246 break;
248 case SYSCTYPE:
250 * dosys - execute system command
252 if (argc > 2) {
253 fflush(stdout);
254 sysval = system(argv[2]);
256 break;
258 case SYSVTYPE:
260 * dosysval - return value of the last
261 * system call.
264 pbnum(sysval);
265 break;
267 case ESYSCMDTYPE:
268 if (argc > 2)
269 doesyscmd(argv[2]);
270 break;
271 case INCLTYPE:
272 if (argc > 2)
273 if (!doincl(argv[2]))
274 err(1, "%s at line %lu: include(%s)",
275 CURRENT_NAME, CURRENT_LINE, argv[2]);
276 break;
278 case SINCTYPE:
279 if (argc > 2)
280 (void) doincl(argv[2]);
281 break;
282 #ifdef EXTENDED
283 case PASTTYPE:
284 if (argc > 2)
285 if (!dopaste(argv[2]))
286 err(1, "%s at line %lu: paste(%s)",
287 CURRENT_NAME, CURRENT_LINE, argv[2]);
288 break;
290 case SPASTYPE:
291 if (argc > 2)
292 (void) dopaste(argv[2]);
293 break;
294 case FORMATTYPE:
295 doformat(argv, argc);
296 break;
297 #endif
298 case CHNQTYPE:
299 dochq(argv, ac);
300 break;
302 case CHNCTYPE:
303 dochc(argv, argc);
304 break;
306 case SUBSTYPE:
308 * dosub - select substring
311 if (argc > 3)
312 dosub(argv, argc);
313 break;
315 case SHIFTYPE:
317 * doshift - push back all arguments
318 * except the first one (i.e. skip
319 * argv[2])
321 if (argc > 3) {
322 for (n = argc - 1; n > 3; n--) {
323 pbstr(rquote);
324 pbstr(argv[n]);
325 pbstr(lquote);
326 pushback(COMMA);
328 pbstr(rquote);
329 pbstr(argv[3]);
330 pbstr(lquote);
332 break;
334 case DIVRTYPE:
335 if (argc > 2 && (n = atoi(argv[2])) != 0)
336 dodiv(n);
337 else {
338 active = stdout;
339 oindex = 0;
341 break;
343 case UNDVTYPE:
344 doundiv(argv, argc);
345 break;
347 case DIVNTYPE:
349 * dodivnum - return the number of
350 * current output diversion
352 pbnum(oindex);
353 break;
355 case UNDFTYPE:
357 * doundefine - undefine a previously
358 * defined macro(s) or m4 keyword(s).
360 if (argc > 2)
361 for (n = 2; n < argc; n++)
362 macro_undefine(argv[n]);
363 break;
365 case POPDTYPE:
367 * dopopdef - remove the topmost
368 * definitions of macro(s) or m4
369 * keyword(s).
371 if (argc > 2)
372 for (n = 2; n < argc; n++)
373 macro_popdef(argv[n]);
374 break;
376 case MKTMTYPE:
378 * dotemp - create a temporary file
380 if (argc > 2) {
381 int fd;
382 char *temp;
384 temp = xstrdup(argv[2]);
386 fd = mkstemp(temp);
387 if (fd == -1)
388 err(1,
389 "%s at line %lu: couldn't make temp file %s",
390 CURRENT_NAME, CURRENT_LINE, argv[2]);
391 close(fd);
392 pbstr(temp);
393 free(temp);
395 break;
397 case TRNLTYPE:
399 * dotranslit - replace all characters in
400 * the source string that appears in the
401 * "from" string with the corresponding
402 * characters in the "to" string.
404 if (argc > 3) {
405 char *temp;
407 temp = xalloc(strlen(argv[2])+1, NULL);
408 if (argc > 4)
409 map(temp, argv[2], argv[3], argv[4]);
410 else
411 map(temp, argv[2], argv[3], null);
412 pbstr(temp);
413 free(temp);
414 } else if (argc > 2)
415 pbstr(argv[2]);
416 break;
418 case INDXTYPE:
420 * doindex - find the index of the second
421 * argument string in the first argument
422 * string. -1 if not present.
424 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
425 break;
427 case ERRPTYPE:
429 * doerrp - print the arguments to stderr
430 * file
432 if (argc > 2) {
433 for (n = 2; n < argc; n++)
434 fprintf(stderr, "%s%s",
435 mimic_gnu && n == 2 ? "" : " ",
436 argv[n]);
437 if (!mimic_gnu)
438 fprintf(stderr, "\n");
440 break;
442 case DNLNTYPE:
444 * dodnl - eat-up-to and including
445 * newline
447 while ((c = gpbc()) != '\n' && c != EOF)
449 break;
451 case M4WRTYPE:
453 * dom4wrap - set up for
454 * wrap-up/wind-down activity
456 if (argc > 2)
457 dom4wrap(argv[2]);
458 break;
460 case EXITTYPE:
462 * doexit - immediate exit from m4.
464 killdiv();
465 exit((argc > 2) ? atoi(argv[2]) : 0);
466 break;
468 case DEFNTYPE:
469 if (argc > 2)
470 for (n = 2; n < argc; n++)
471 dodefn(argv[n]);
472 break;
474 case INDIRTYPE: /* Indirect call */
475 if (argc > 2)
476 doindir(argv, argc);
477 break;
479 case BUILTINTYPE: /* Builtins only */
480 if (argc > 2)
481 dobuiltin(argv, argc);
482 break;
484 case PATSTYPE:
485 if (argc > 2)
486 dopatsubst(argv, argc);
487 break;
488 case REGEXPTYPE:
489 if (argc > 2)
490 doregexp(argv, argc);
491 break;
492 case LINETYPE:
493 doprintlineno(infile+ilevel);
494 break;
495 case FILENAMETYPE:
496 doprintfilename(infile+ilevel);
497 break;
498 case SELFTYPE:
499 pbstr(rquote);
500 pbstr(argv[1]);
501 pbstr(lquote);
502 break;
503 default:
504 m4errx(1, "eval: major botch.");
505 break;
510 * expand_macro - user-defined macro expansion
512 void
513 expand_macro(const char *argv[], int argc)
515 const char *t;
516 const char *p;
517 int n;
518 int argno;
520 t = argv[0]; /* defn string as a whole */
521 p = t;
522 while (*p)
523 p++;
524 p--; /* last character of defn */
525 while (p > t) {
526 if (*(p - 1) != ARGFLAG)
527 PUSHBACK(*p);
528 else {
529 switch (*p) {
531 case '#':
532 pbnum(argc - 2);
533 break;
534 case '0':
535 case '1':
536 case '2':
537 case '3':
538 case '4':
539 case '5':
540 case '6':
541 case '7':
542 case '8':
543 case '9':
544 if ((argno = *p - '0') < argc - 1)
545 pbstr(argv[argno + 1]);
546 break;
547 case '*':
548 if (argc > 2) {
549 for (n = argc - 1; n > 2; n--) {
550 pbstr(argv[n]);
551 pushback(COMMA);
553 pbstr(argv[2]);
555 break;
556 case '@':
557 if (argc > 2) {
558 for (n = argc - 1; n > 2; n--) {
559 pbstr(rquote);
560 pbstr(argv[n]);
561 pbstr(lquote);
562 pushback(COMMA);
564 pbstr(rquote);
565 pbstr(argv[2]);
566 pbstr(lquote);
568 break;
569 default:
570 PUSHBACK(*p);
571 PUSHBACK('$');
572 break;
574 p--;
576 p--;
578 if (p == t) /* do last character */
579 PUSHBACK(*p);
584 * dodefine - install definition in the table
586 void
587 dodefine(const char *name, const char *defn)
589 if (!*name && !mimic_gnu)
590 m4errx(1, "null definition.");
591 else
592 macro_define(name, defn);
596 * dodefn - push back a quoted definition of
597 * the given name.
599 static void
600 dodefn(const char *name)
602 struct macro_definition *p;
604 if ((p = lookup_macro_definition(name)) != NULL) {
605 if ((p->type & TYPEMASK) == MACRTYPE) {
606 pbstr(rquote);
607 pbstr(p->defn);
608 pbstr(lquote);
609 } else {
610 pbstr(p->defn);
611 pbstr(BUILTIN_MARKER);
617 * dopushdef - install a definition in the hash table
618 * without removing a previous definition. Since
619 * each new entry is entered in *front* of the
620 * hash bucket, it hides a previous definition from
621 * lookup.
623 static void
624 dopushdef(const char *name, const char *defn)
626 if (!*name && !mimic_gnu)
627 m4errx(1, "null definition.");
628 else
629 macro_pushdef(name, defn);
633 * dump_one_def - dump the specified definition.
635 static void
636 dump_one_def(const char *name, struct macro_definition *p)
638 if (!traceout)
639 traceout = stderr;
640 if (mimic_gnu) {
641 if ((p->type & TYPEMASK) == MACRTYPE)
642 fprintf(traceout, "%s:\t%s\n", name, p->defn);
643 else {
644 fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
646 } else
647 fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
651 * dodumpdef - dump the specified definitions in the hash
652 * table to stderr. If nothing is specified, the entire
653 * hash table is dumped.
655 static void
656 dodump(const char *argv[], int argc)
658 int n;
659 struct macro_definition *p;
661 if (argc > 2) {
662 for (n = 2; n < argc; n++)
663 if ((p = lookup_macro_definition(argv[n])) != NULL)
664 dump_one_def(argv[n], p);
665 } else
666 macro_for_all(dump_one_def);
670 * dotrace - mark some macros as traced/untraced depending upon on.
672 static void
673 dotrace(const char *argv[], int argc, int on)
675 int n;
677 if (argc > 2) {
678 for (n = 2; n < argc; n++)
679 mark_traced(argv[n], on);
680 } else
681 mark_traced(NULL, on);
685 * doifelse - select one of two alternatives - loop.
687 static void
688 doifelse(const char *argv[], int argc)
690 cycle {
691 if (STREQ(argv[2], argv[3]))
692 pbstr(argv[4]);
693 else if (argc == 6)
694 pbstr(argv[5]);
695 else if (argc > 6) {
696 argv += 3;
697 argc -= 3;
698 continue;
700 break;
705 * doinclude - include a given file.
707 static int
708 doincl(const char *ifile)
710 if (ilevel + 1 == MAXINP)
711 m4errx(1, "too many include files.");
712 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
713 ilevel++;
714 bbase[ilevel] = bufbase = bp;
715 return (1);
716 } else
717 return (0);
720 #ifdef EXTENDED
722 * dopaste - include a given file without any
723 * macro processing.
725 static int
726 dopaste(const char *pfile)
728 FILE *pf;
729 int c;
731 if ((pf = fopen(pfile, "r")) != NULL) {
732 if (synch_lines)
733 fprintf(active, "#line 1 \"%s\"\n", pfile);
734 while ((c = getc(pf)) != EOF)
735 putc(c, active);
736 (void) fclose(pf);
737 emit_synchline();
738 return (1);
739 } else
740 return (0);
742 #endif
745 * dochq - change quote characters
747 static void
748 dochq(const char *argv[], int ac)
750 if (ac == 2) {
751 lquote[0] = LQUOTE; lquote[1] = EOS;
752 rquote[0] = RQUOTE; rquote[1] = EOS;
753 } else {
754 strlcpy(lquote, argv[2], sizeof(lquote));
755 if (ac > 3) {
756 strlcpy(rquote, argv[3], sizeof(rquote));
757 } else {
758 rquote[0] = ECOMMT; rquote[1] = EOS;
764 * dochc - change comment characters
766 static void
767 dochc(const char *argv[], int argc)
769 /* XXX Note that there is no difference between no argument and a single
770 * empty argument.
772 if (argc == 2) {
773 scommt[0] = EOS;
774 ecommt[0] = EOS;
775 } else {
776 strlcpy(scommt, argv[2], sizeof(scommt));
777 if (argc == 3) {
778 ecommt[0] = ECOMMT; ecommt[1] = EOS;
779 } else {
780 strlcpy(ecommt, argv[3], sizeof(ecommt));
786 * dom4wrap - expand text at EOF
788 static void
789 dom4wrap(const char *text)
791 if (wrapindex >= maxwraps) {
792 if (maxwraps == 0)
793 maxwraps = 16;
794 else
795 maxwraps *= 2;
796 m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
797 "too many m4wraps");
799 m4wraps[wrapindex++] = xstrdup(text);
803 * dodivert - divert the output to a temporary file
805 static void
806 dodiv(int n)
808 int fd;
810 oindex = n;
811 if (n >= maxout) {
812 if (mimic_gnu)
813 resizedivs(n + 10);
814 else
815 n = 0; /* bitbucket */
818 if (n < 0)
819 n = 0; /* bitbucket */
820 if (outfile[n] == NULL) {
821 char fname[] = _PATH_DIVNAME;
823 if ((fd = mkstemp(fname)) < 0 ||
824 (outfile[n] = fdopen(fd, "w+")) == NULL)
825 err(1, "%s: cannot divert", fname);
826 if (unlink(fname) == -1)
827 err(1, "%s: cannot unlink", fname);
829 active = outfile[n];
833 * doundivert - undivert a specified output, or all
834 * other outputs, in numerical order.
836 static void
837 doundiv(const char *argv[], int argc)
839 int ind;
840 int n;
842 if (argc > 2) {
843 for (ind = 2; ind < argc; ind++) {
844 int e;
845 n = strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e);
846 if (e) {
847 if (errno == EINVAL && mimic_gnu)
848 getdivfile(argv[ind]);
849 } else {
850 if (n < maxout && outfile[n] != NULL)
851 getdiv(n);
855 else
856 for (n = 1; n < maxout; n++)
857 if (outfile[n] != NULL)
858 getdiv(n);
862 * dosub - select substring
864 static void
865 dosub(const char *argv[], int argc)
867 const char *ap, *fc, *k;
868 int nc;
870 ap = argv[2]; /* target string */
871 #ifdef EXPR
872 fc = ap + expr(argv[3]); /* first char */
873 #else
874 fc = ap + atoi(argv[3]); /* first char */
875 #endif
876 nc = strlen(fc);
877 if (argc >= 5)
878 #ifdef EXPR
879 nc = min(nc, expr(argv[4]));
880 #else
881 nc = min(nc, atoi(argv[4]));
882 #endif
883 if (fc >= ap && fc < ap + strlen(ap))
884 for (k = fc + nc - 1; k >= fc; k--)
885 pushback(*k);
889 * map:
890 * map every character of s1 that is specified in from
891 * into s3 and replace in s. (source s1 remains untouched)
893 * This is a standard implementation of map(s,from,to) function of ICON
894 * language. Within mapvec, we replace every character of "from" with
895 * the corresponding character in "to". If "to" is shorter than "from",
896 * than the corresponding entries are null, which means that those
897 * characters dissapear altogether. Furthermore, imagine
898 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
899 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
900 * ultimately maps to `*'. In order to achieve this effect in an efficient
901 * manner (i.e. without multiple passes over the destination string), we
902 * loop over mapvec, starting with the initial source character. if the
903 * character value (dch) in this location is different than the source
904 * character (sch), sch becomes dch, once again to index into mapvec, until
905 * the character value stabilizes (i.e. sch = dch, in other words
906 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
907 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
908 * end, we restore mapvec* back to normal where mapvec[n] == n for
909 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
910 * about 5 times faster than any algorithm that makes multiple passes over
911 * destination string.
913 static void
914 map(char *dest, const char *src, const char *from, const char *to)
916 const char *tmp;
917 unsigned char sch, dch;
918 static char frombis[257];
919 static char tobis[257];
920 static unsigned char mapvec[256] = {
921 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
922 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
923 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
924 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
925 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
926 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
927 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
928 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
929 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
930 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
931 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
932 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
933 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
934 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
935 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
936 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
937 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
938 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
941 if (*src) {
942 if (mimic_gnu) {
944 * expand character ranges on the fly
946 from = handledash(frombis, frombis + 256, from);
947 to = handledash(tobis, tobis + 256, to);
949 tmp = from;
951 * create a mapping between "from" and
952 * "to"
954 while (*from)
955 mapvec[(unsigned char)(*from++)] = (*to) ?
956 (unsigned char)(*to++) : 0;
958 while (*src) {
959 sch = (unsigned char)(*src++);
960 dch = mapvec[sch];
961 while (dch != sch) {
962 sch = dch;
963 dch = mapvec[sch];
965 if ((*dest = (char)dch))
966 dest++;
969 * restore all the changed characters
971 while (*tmp) {
972 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
973 tmp++;
976 *dest = '\0';
981 * handledash:
982 * use buffer to copy the src string, expanding character ranges
983 * on the way.
985 static const char *
986 handledash(char *buffer, char *end, const char *src)
988 char *p;
990 p = buffer;
991 while(*src) {
992 if (src[1] == '-' && src[2]) {
993 unsigned char i;
994 if ((unsigned char)src[0] <= (unsigned char)src[2]) {
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;
1003 } else {
1004 for (i = (unsigned char)src[0];
1005 i >= (unsigned char)src[2]; i--) {
1006 *p++ = i;
1007 if (p == end) {
1008 *p = '\0';
1009 return buffer;
1013 src += 3;
1014 } else
1015 *p++ = *src++;
1016 if (p == end)
1017 break;
1019 *p = '\0';
1020 return buffer;