cxgbe/t4_tom: Read the chip's DDP page sizes and save them in a
[freebsd-src.git] / usr.bin / m4 / eval.c
blobf3d72b647e03b192164bdfa3109f3fbc05d8e987
1 /* $OpenBSD: eval.c,v 1.74 2015/02/05 12:59:57 millert Exp $ */
2 /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk 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.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
41 * eval.c
42 * Facility: m4 macro processor
43 * by: oz
46 #include <sys/types.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <unistd.h>
51 #include <stdio.h>
52 #include <stdint.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"
62 static void dodefn(const char *);
63 static void dopushdef(const char *, const char *);
64 static void dodump(const char *[], int);
65 static void dotrace(const char *[], int, int);
66 static void doifelse(const char *[], int);
67 static int doincl(const char *);
68 static int dopaste(const char *);
69 static void dochq(const char *[], int);
70 static void dochc(const char *[], int);
71 static void dom4wrap(const char *);
72 static void dodiv(int);
73 static void doundiv(const char *[], int);
74 static void dosub(const char *[], int);
75 static void map(char *, const char *, const char *, const char *);
76 static const char *handledash(char *, char *, const char *);
77 static void expand_builtin(const char *[], int, int);
78 static void expand_macro(const char *[], int);
79 static void dump_one_def(const char *, struct macro_definition *);
81 unsigned long expansion_id;
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 * .
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
100 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
102 void
103 eval(const char *argv[], int argc, int td, int is_traced)
105 size_t mark = SIZE_MAX;
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);
121 * expand_builtin - evaluate built-in macros.
123 void
124 expand_builtin(const char *argv[], int argc, int td)
126 int c, n;
127 int ac;
128 static int sysval = 0;
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
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..
142 /* we keep the initial value for those built-ins that differentiate
143 * between builtin() and builtin.
145 ac = argc;
147 if (argc == 3 && !*(argv[2]) && !mimic_gnu)
148 argc--;
150 switch (td & TYPEMASK) {
152 case DEFITYPE:
153 if (argc > 2)
154 dodefine(argv[2], (argc > 3) ? argv[3] : null);
155 break;
157 case PUSDTYPE:
158 if (argc > 2)
159 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
160 break;
162 case DUMPTYPE:
163 dodump(argv, argc);
164 break;
166 case TRACEONTYPE:
167 dotrace(argv, argc, 1);
168 break;
170 case TRACEOFFTYPE:
171 dotrace(argv, argc, 0);
172 break;
174 case EXPRTYPE:
176 * doexpr - evaluate arithmetic
177 * expression
180 int base = 10;
181 int maxdigits = 0;
182 const char *errstr;
184 if (argc > 3) {
185 base = strtonum(argv[3], 2, 36, &errstr);
186 if (errstr) {
187 m4errx(1, "expr: base %s invalid.", argv[3]);
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]);
196 if (argc > 2)
197 pbnumbase(expr(argv[2]), base, maxdigits);
198 break;
201 case IFELTYPE:
202 if (argc > 4)
203 doifelse(argv, argc);
204 break;
206 case IFDFTYPE:
208 * doifdef - select one of two
209 * alternatives based on the existence of
210 * another definition
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]);
218 break;
220 case LENGTYPE:
222 * dolen - find the length of the
223 * argument
225 pbnum((argc > 2) ? strlen(argv[2]) : 0);
226 break;
228 case INCRTYPE:
230 * doincr - increment the value of the
231 * argument
233 if (argc > 2)
234 pbnum(atoi(argv[2]) + 1);
235 break;
237 case DECRTYPE:
239 * dodecr - decrement the value of the
240 * argument
242 if (argc > 2)
243 pbnum(atoi(argv[2]) - 1);
244 break;
246 case SYSCTYPE:
248 * dosys - execute system command
250 if (argc > 2) {
251 fflush(stdout);
252 sysval = system(argv[2]);
254 break;
256 case SYSVTYPE:
258 * dosysval - return value of the last
259 * system call.
262 pbnum(sysval);
263 break;
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 exit_code = 1;
276 } else
277 err(1, "%s at line %lu: include(%s)",
278 CURRENT_NAME, CURRENT_LINE, argv[2]);
281 break;
283 case SINCTYPE:
284 if (argc > 2)
285 (void) doincl(argv[2]);
286 break;
287 #ifdef EXTENDED
288 case PASTTYPE:
289 if (argc > 2)
290 if (!dopaste(argv[2]))
291 err(1, "%s at line %lu: paste(%s)",
292 CURRENT_NAME, CURRENT_LINE, argv[2]);
293 break;
295 case SPASTYPE:
296 if (argc > 2)
297 (void) dopaste(argv[2]);
298 break;
299 case FORMATTYPE:
300 doformat(argv, argc);
301 break;
302 #endif
303 case CHNQTYPE:
304 dochq(argv, ac);
305 break;
307 case CHNCTYPE:
308 dochc(argv, argc);
309 break;
311 case SUBSTYPE:
313 * dosub - select substring
316 if (argc > 3)
317 dosub(argv, argc);
318 break;
320 case SHIFTYPE:
322 * doshift - push back all arguments
323 * except the first one (i.e. skip
324 * argv[2])
326 if (argc > 3) {
327 for (n = argc - 1; n > 3; n--) {
328 pbstr(rquote);
329 pbstr(argv[n]);
330 pbstr(lquote);
331 pushback(COMMA);
333 pbstr(rquote);
334 pbstr(argv[3]);
335 pbstr(lquote);
337 break;
339 case DIVRTYPE:
340 if (argc > 2 && (n = atoi(argv[2])) != 0)
341 dodiv(n);
342 else {
343 active = stdout;
344 oindex = 0;
346 break;
348 case UNDVTYPE:
349 doundiv(argv, argc);
350 break;
352 case DIVNTYPE:
354 * dodivnum - return the number of
355 * current output diversion
357 pbnum(oindex);
358 break;
360 case UNDFTYPE:
362 * doundefine - undefine a previously
363 * defined macro(s) or m4 keyword(s).
365 if (argc > 2)
366 for (n = 2; n < argc; n++)
367 macro_undefine(argv[n]);
368 break;
370 case POPDTYPE:
372 * dopopdef - remove the topmost
373 * definitions of macro(s) or m4
374 * keyword(s).
376 if (argc > 2)
377 for (n = 2; n < argc; n++)
378 macro_popdef(argv[n]);
379 break;
381 case MKTMTYPE:
383 * dotemp - create a temporary file
385 if (argc > 2) {
386 int fd;
387 char *temp;
389 temp = xstrdup(argv[2]);
391 fd = mkstemp(temp);
392 if (fd == -1)
393 err(1,
394 "%s at line %lu: couldn't make temp file %s",
395 CURRENT_NAME, CURRENT_LINE, argv[2]);
396 close(fd);
397 pbstr(temp);
398 free(temp);
400 break;
402 case TRNLTYPE:
404 * dotranslit - replace all characters in
405 * the source string that appears in the
406 * "from" string with the corresponding
407 * characters in the "to" string.
409 if (argc > 3) {
410 char *temp;
412 temp = xalloc(strlen(argv[2])+1, NULL);
413 if (argc > 4)
414 map(temp, argv[2], argv[3], argv[4]);
415 else
416 map(temp, argv[2], argv[3], null);
417 pbstr(temp);
418 free(temp);
419 } else if (argc > 2)
420 pbstr(argv[2]);
421 break;
423 case INDXTYPE:
425 * doindex - find the index of the second
426 * argument string in the first argument
427 * string. -1 if not present.
429 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
430 break;
432 case ERRPTYPE:
434 * doerrp - print the arguments to stderr
435 * file
437 if (argc > 2) {
438 for (n = 2; n < argc; n++)
439 fprintf(stderr, "%s ", argv[n]);
440 fprintf(stderr, "\n");
442 break;
444 case DNLNTYPE:
446 * dodnl - eat-up-to and including
447 * newline
449 while ((c = gpbc()) != '\n' && c != EOF)
451 break;
453 case M4WRTYPE:
455 * dom4wrap - set up for
456 * wrap-up/wind-down activity
458 if (argc > 2)
459 dom4wrap(argv[2]);
460 break;
462 case EXITTYPE:
464 * doexit - immediate exit from m4.
466 killdiv();
467 exit((argc > 2) ? atoi(argv[2]) : 0);
468 break;
470 case DEFNTYPE:
471 if (argc > 2)
472 for (n = 2; n < argc; n++)
473 dodefn(argv[n]);
474 break;
476 case INDIRTYPE: /* Indirect call */
477 if (argc > 2)
478 doindir(argv, argc);
479 break;
481 case BUILTINTYPE: /* Builtins only */
482 if (argc > 2)
483 dobuiltin(argv, argc);
484 break;
486 case PATSTYPE:
487 if (argc > 2)
488 dopatsubst(argv, argc);
489 break;
490 case REGEXPTYPE:
491 if (argc > 2)
492 doregexp(argv, argc);
493 break;
494 case LINETYPE:
495 doprintlineno(infile+ilevel);
496 break;
497 case FILENAMETYPE:
498 doprintfilename(infile+ilevel);
499 break;
500 case SELFTYPE:
501 pbstr(rquote);
502 pbstr(argv[1]);
503 pbstr(lquote);
504 break;
505 default:
506 m4errx(1, "eval: major botch.");
507 break;
512 * expand_macro - user-defined macro expansion
514 void
515 expand_macro(const char *argv[], int argc)
517 const char *t;
518 const char *p;
519 int n;
520 int argno;
522 t = argv[0]; /* defn string as a whole */
523 p = t;
524 while (*p)
525 p++;
526 p--; /* last character of defn */
527 while (p > t) {
528 if (*(p - 1) != ARGFLAG)
529 PUSHBACK(*p);
530 else {
531 switch (*p) {
533 case '#':
534 pbnum(argc - 2);
535 break;
536 case '0':
537 case '1':
538 case '2':
539 case '3':
540 case '4':
541 case '5':
542 case '6':
543 case '7':
544 case '8':
545 case '9':
546 if ((argno = *p - '0') < argc - 1)
547 pbstr(argv[argno + 1]);
548 break;
549 case '*':
550 if (argc > 2) {
551 for (n = argc - 1; n > 2; n--) {
552 pbstr(argv[n]);
553 pushback(COMMA);
555 pbstr(argv[2]);
557 break;
558 case '@':
559 if (argc > 2) {
560 for (n = argc - 1; n > 2; n--) {
561 pbstr(rquote);
562 pbstr(argv[n]);
563 pbstr(lquote);
564 pushback(COMMA);
566 pbstr(rquote);
567 pbstr(argv[2]);
568 pbstr(lquote);
570 break;
571 default:
572 PUSHBACK(*p);
573 PUSHBACK('$');
574 break;
576 p--;
578 p--;
580 if (p == t) /* do last character */
581 PUSHBACK(*p);
586 * dodefine - install definition in the table
588 void
589 dodefine(const char *name, const char *defn)
591 if (!*name && !mimic_gnu)
592 m4errx(1, "null definition.");
593 else
594 macro_define(name, defn);
598 * dodefn - push back a quoted definition of
599 * the given name.
601 static void
602 dodefn(const char *name)
604 struct macro_definition *p;
606 if ((p = lookup_macro_definition(name)) != NULL) {
607 if ((p->type & TYPEMASK) == MACRTYPE) {
608 pbstr(rquote);
609 pbstr(p->defn);
610 pbstr(lquote);
611 } else {
612 pbstr(p->defn);
613 pbstr(BUILTIN_MARKER);
619 * dopushdef - install a definition in the hash table
620 * without removing a previous definition. Since
621 * each new entry is entered in *front* of the
622 * hash bucket, it hides a previous definition from
623 * lookup.
625 static void
626 dopushdef(const char *name, const char *defn)
628 if (!*name && !mimic_gnu)
629 m4errx(1, "null definition.");
630 else
631 macro_pushdef(name, defn);
635 * dump_one_def - dump the specified definition.
637 static void
638 dump_one_def(const char *name, struct macro_definition *p)
640 if (!traceout)
641 traceout = stderr;
642 if (mimic_gnu) {
643 if ((p->type & TYPEMASK) == MACRTYPE)
644 fprintf(traceout, "%s:\t%s\n", name, p->defn);
645 else {
646 fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
648 } else
649 fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
653 * dodumpdef - dump the specified definitions in the hash
654 * table to stderr. If nothing is specified, the entire
655 * hash table is dumped.
657 static void
658 dodump(const char *argv[], int argc)
660 int n;
661 struct macro_definition *p;
663 if (argc > 2) {
664 for (n = 2; n < argc; n++)
665 if ((p = lookup_macro_definition(argv[n])) != NULL)
666 dump_one_def(argv[n], p);
667 } else
668 macro_for_all(dump_one_def);
672 * dotrace - mark some macros as traced/untraced depending upon on.
674 static void
675 dotrace(const char *argv[], int argc, int on)
677 int n;
679 if (argc > 2) {
680 for (n = 2; n < argc; n++)
681 mark_traced(argv[n], on);
682 } else
683 mark_traced(NULL, on);
687 * doifelse - select one of two alternatives - loop.
689 static void
690 doifelse(const char *argv[], int argc)
692 cycle {
693 if (STREQ(argv[2], argv[3]))
694 pbstr(argv[4]);
695 else if (argc == 6)
696 pbstr(argv[5]);
697 else if (argc > 6) {
698 argv += 3;
699 argc -= 3;
700 continue;
702 break;
707 * doinclude - include a given file.
709 static int
710 doincl(const char *ifile)
712 if (ilevel + 1 == MAXINP)
713 m4errx(1, "too many include files.");
714 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
715 ilevel++;
716 bbase[ilevel] = bufbase = bp;
717 return (1);
718 } else
719 return (0);
722 #ifdef EXTENDED
724 * dopaste - include a given file without any
725 * macro processing.
727 static int
728 dopaste(const char *pfile)
730 FILE *pf;
731 int c;
733 if ((pf = fopen(pfile, "r")) != NULL) {
734 if (synch_lines)
735 fprintf(active, "#line 1 \"%s\"\n", pfile);
736 while ((c = getc(pf)) != EOF)
737 putc(c, active);
738 (void) fclose(pf);
739 emit_synchline();
740 return (1);
741 } else
742 return (0);
744 #endif
747 * dochq - change quote characters
749 static void
750 dochq(const char *argv[], int ac)
752 if (ac == 2) {
753 lquote[0] = LQUOTE; lquote[1] = EOS;
754 rquote[0] = RQUOTE; rquote[1] = EOS;
755 } else {
756 strlcpy(lquote, argv[2], sizeof(lquote));
757 if (ac > 3) {
758 strlcpy(rquote, argv[3], sizeof(rquote));
759 } else {
760 rquote[0] = ECOMMT; rquote[1] = EOS;
766 * dochc - change comment characters
768 static void
769 dochc(const char *argv[], int argc)
771 /* XXX Note that there is no difference between no argument and a single
772 * empty argument.
774 if (argc == 2) {
775 scommt[0] = EOS;
776 ecommt[0] = EOS;
777 } else {
778 strlcpy(scommt, argv[2], sizeof(scommt));
779 if (argc == 3) {
780 ecommt[0] = ECOMMT; ecommt[1] = EOS;
781 } else {
782 strlcpy(ecommt, argv[3], sizeof(ecommt));
788 * dom4wrap - expand text at EOF
790 static void
791 dom4wrap(const char *text)
793 if (wrapindex >= maxwraps) {
794 if (maxwraps == 0)
795 maxwraps = 16;
796 else
797 maxwraps *= 2;
798 m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
799 "too many m4wraps");
801 m4wraps[wrapindex++] = xstrdup(text);
805 * dodivert - divert the output to a temporary file
807 static void
808 dodiv(int n)
810 int fd;
812 oindex = n;
813 if (n >= maxout) {
814 if (mimic_gnu)
815 resizedivs(n + 10);
816 else
817 n = 0; /* bitbucket */
820 if (n < 0)
821 n = 0; /* bitbucket */
822 if (outfile[n] == NULL) {
823 char fname[] = _PATH_DIVNAME;
825 if ((fd = mkstemp(fname)) < 0 ||
826 unlink(fname) == -1 ||
827 (outfile[n] = fdopen(fd, "w+")) == NULL)
828 err(1, "%s: cannot divert", fname);
830 active = outfile[n];
834 * doundivert - undivert a specified output, or all
835 * other outputs, in numerical order.
837 static void
838 doundiv(const char *argv[], int argc)
840 int ind;
841 int n;
843 if (argc > 2) {
844 for (ind = 2; ind < argc; ind++) {
845 const char *errstr;
846 n = strtonum(argv[ind], 1, INT_MAX, &errstr);
847 if (errstr) {
848 if (errno == EINVAL && mimic_gnu)
849 getdivfile(argv[ind]);
850 } else {
851 if (n < maxout && outfile[n] != NULL)
852 getdiv(n);
856 else
857 for (n = 1; n < maxout; n++)
858 if (outfile[n] != NULL)
859 getdiv(n);
863 * dosub - select substring
865 static void
866 dosub(const char *argv[], int argc)
868 const char *ap, *fc, *k;
869 int nc;
871 ap = argv[2]; /* target string */
872 #ifdef EXPR
873 fc = ap + expr(argv[3]); /* first char */
874 #else
875 fc = ap + atoi(argv[3]); /* first char */
876 #endif
877 nc = strlen(fc);
878 if (argc >= 5)
879 #ifdef EXPR
880 nc = min(nc, expr(argv[4]));
881 #else
882 nc = min(nc, atoi(argv[4]));
883 #endif
884 if (fc >= ap && fc < ap + strlen(ap))
885 for (k = fc + nc - 1; k >= fc; k--)
886 pushback(*k);
890 * map:
891 * map every character of s1 that is specified in from
892 * into s3 and replace in s. (source s1 remains untouched)
894 * This is derived from the a standard implementation of map(s,from,to)
895 * function of ICON language. Within mapvec, we replace every character
896 * of "from" with the corresponding character in "to".
897 * If "to" is shorter than "from", than the corresponding entries are null,
898 * which means that those characters disappear altogether.
900 static void
901 map(char *dest, const char *src, const char *from, const char *to)
903 const char *tmp;
904 unsigned char sch, dch;
905 static char frombis[257];
906 static char tobis[257];
907 int i;
908 char seen[256];
909 static unsigned char mapvec[256] = {
910 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
911 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
912 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
913 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
914 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
915 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
916 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
917 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
918 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
919 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
920 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
921 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
922 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
923 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
924 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
925 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
926 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
927 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
930 if (*src) {
931 if (mimic_gnu) {
933 * expand character ranges on the fly
935 from = handledash(frombis, frombis + 256, from);
936 to = handledash(tobis, tobis + 256, to);
938 tmp = from;
940 * create a mapping between "from" and
941 * "to"
943 for (i = 0; i < 256; i++)
944 seen[i] = 0;
945 while (*from) {
946 if (!seen[(unsigned char)(*from)]) {
947 mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
948 seen[(unsigned char)(*from)] = 1;
950 from++;
951 if (*to)
952 to++;
955 while (*src) {
956 sch = (unsigned char)(*src++);
957 dch = mapvec[sch];
958 if ((*dest = (char)dch))
959 dest++;
962 * restore all the changed characters
964 while (*tmp) {
965 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
966 tmp++;
969 *dest = '\0';
974 * handledash:
975 * use buffer to copy the src string, expanding character ranges
976 * on the way.
978 static const char *
979 handledash(char *buffer, char *end, const char *src)
981 char *p;
983 p = buffer;
984 while(*src) {
985 if (src[1] == '-' && src[2]) {
986 unsigned char i;
987 if ((unsigned char)src[0] <= (unsigned char)src[2]) {
988 for (i = (unsigned char)src[0];
989 i <= (unsigned char)src[2]; i++) {
990 *p++ = i;
991 if (p == end) {
992 *p = '\0';
993 return buffer;
996 } else {
997 for (i = (unsigned char)src[0];
998 i >= (unsigned char)src[2]; i--) {
999 *p++ = i;
1000 if (p == end) {
1001 *p = '\0';
1002 return buffer;
1006 src += 3;
1007 } else
1008 *p++ = *src++;
1009 if (p == end)
1010 break;
1012 *p = '\0';
1013 return buffer;