sbin/*hammer: Add missing braces to conform to code style
[dragonfly.git] / usr.bin / m4 / eval.c
blob09d0acf882489deb097cc0000b34f073169832ac
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 $ */
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.
35 * $FreeBSD: src/usr.bin/m4/eval.c,v 1.28 2012/11/17 01:54:24 svnexp Exp $
40 * eval.c
41 * Facility: m4 macro processor
42 * by: oz
45 #include <sys/types.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <unistd.h>
50 #include <stdint.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <stddef.h>
54 #include <string.h>
55 #include <fcntl.h>
56 #include "mdef.h"
57 #include "stdd.h"
58 #include "extern.h"
59 #include "pathnames.h"
61 static void dodefn(const char *);
62 static void dopushdef(const char *, const char *);
63 static void dodump(const char *[], int);
64 static void dotrace(const char *[], int, int);
65 static void doifelse(const char *[], int);
66 static int doincl(const char *);
67 static int dopaste(const char *);
68 static void dochq(const char *[], int);
69 static void dochc(const char *[], int);
70 static void dom4wrap(const char *);
71 static void dodiv(int);
72 static void doundiv(const char *[], int);
73 static void dosub(const char *[], int);
74 static void map(char *, const char *, const char *, const char *);
75 static const char *handledash(char *, char *, const char *);
76 static void expand_builtin(const char *[], int, int);
77 static void expand_macro(const char *[], int);
78 static void dump_one_def(const char *, struct macro_definition *);
80 unsigned long expansion_id;
83 * eval - eval all macros and builtins calls
84 * argc - number of elements in argv.
85 * argv - element vector :
86 * argv[0] = definition of a user
87 * macro or NULL if built-in.
88 * argv[1] = name of the macro or
89 * built-in.
90 * argv[2] = parameters to user-defined
91 * . macro or built-in.
92 * .
94 * A call in the form of macro-or-builtin() will result in:
95 * argv[0] = nullstr
96 * argv[1] = macro-or-builtin
97 * argv[2] = nullstr
99 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
101 void
102 eval(const char *argv[], int argc, int td, int is_traced)
104 size_t mark = SIZE_MAX;
106 expansion_id++;
107 if (td & RECDEF)
108 m4errx(1, "expanding recursive definition for %s.", argv[1]);
109 if (is_traced)
110 mark = trace(argv, argc, infile + ilevel);
111 if (td == MACRTYPE)
112 expand_macro(argv, argc);
113 else
114 expand_builtin(argv, argc, td);
115 if (mark != SIZE_MAX)
116 finish_trace(mark);
120 * expand_builtin - evaluate built-in macros.
122 void
123 expand_builtin(const char *argv[], int argc, int td)
125 int c, n;
126 int ac;
127 static int sysval = 0;
129 #ifdef DEBUG
130 printf("argc = %d\n", argc);
131 for (n = 0; n < argc; n++)
132 printf("argv[%d] = %s\n", n, argv[n]);
133 fflush(stdout);
134 #endif
137 * if argc == 3 and argv[2] is null, then we
138 * have macro-or-builtin() type call. We adjust
139 * argc to avoid further checking.
141 /* we keep the initial value for those built-ins that differentiate
142 * between builtin() and builtin.
144 ac = argc;
146 if (argc == 3 && !*(argv[2]) && !mimic_gnu)
147 argc--;
149 switch (td & TYPEMASK) {
151 case DEFITYPE:
152 if (argc > 2)
153 dodefine(argv[2], (argc > 3) ? argv[3] : null);
154 break;
156 case PUSDTYPE:
157 if (argc > 2)
158 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
159 break;
161 case DUMPTYPE:
162 dodump(argv, argc);
163 break;
165 case TRACEONTYPE:
166 dotrace(argv, argc, 1);
167 break;
169 case TRACEOFFTYPE:
170 dotrace(argv, argc, 0);
171 break;
173 case EXPRTYPE:
175 * doexpr - evaluate arithmetic
176 * expression
179 int base = 10;
180 int maxdigits = 0;
181 const char *errstr;
183 if (argc > 3) {
184 base = strtonum(argv[3], 2, 36, &errstr);
185 if (errstr) {
186 m4errx(1, "expr: base %s invalid.", argv[3]);
189 if (argc > 4) {
190 maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
191 if (errstr) {
192 m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
195 if (argc > 2)
196 pbnumbase(expr(argv[2]), base, maxdigits);
197 break;
200 case IFELTYPE:
201 if (argc > 4)
202 doifelse(argv, argc);
203 break;
205 case IFDFTYPE:
207 * doifdef - select one of two
208 * alternatives based on the existence of
209 * another definition
211 if (argc > 3) {
212 if (lookup_macro_definition(argv[2]) != NULL)
213 pbstr(argv[3]);
214 else if (argc > 4)
215 pbstr(argv[4]);
217 break;
219 case LENGTYPE:
221 * dolen - find the length of the
222 * argument
224 pbnum((argc > 2) ? strlen(argv[2]) : 0);
225 break;
227 case INCRTYPE:
229 * doincr - increment the value of the
230 * argument
232 if (argc > 2)
233 pbnum(atoi(argv[2]) + 1);
234 break;
236 case DECRTYPE:
238 * dodecr - decrement the value of the
239 * argument
241 if (argc > 2)
242 pbnum(atoi(argv[2]) - 1);
243 break;
245 case SYSCTYPE:
247 * dosys - execute system command
249 if (argc > 2) {
250 fflush(stdout);
251 sysval = system(argv[2]);
253 break;
255 case SYSVTYPE:
257 * dosysval - return value of the last
258 * system call.
261 pbnum(sysval);
262 break;
264 case ESYSCMDTYPE:
265 if (argc > 2)
266 doesyscmd(argv[2]);
267 break;
268 case INCLTYPE:
269 if (argc > 2)
270 if (!doincl(argv[2])) {
271 if (mimic_gnu) {
272 warn("%s at line %lu: include(%s)",
273 CURRENT_NAME, CURRENT_LINE, argv[2]);
274 exit_code = 1;
275 } else
276 err(1, "%s at line %lu: include(%s)",
277 CURRENT_NAME, CURRENT_LINE, argv[2]);
279 break;
281 case SINCTYPE:
282 if (argc > 2)
283 doincl(argv[2]);
284 break;
285 #ifdef EXTENDED
286 case PASTTYPE:
287 if (argc > 2)
288 if (!dopaste(argv[2]))
289 err(1, "%s at line %lu: paste(%s)",
290 CURRENT_NAME, CURRENT_LINE, argv[2]);
291 break;
293 case SPASTYPE:
294 if (argc > 2)
295 dopaste(argv[2]);
296 break;
297 case FORMATTYPE:
298 doformat(argv, argc);
299 break;
300 #endif
301 case CHNQTYPE:
302 dochq(argv, ac);
303 break;
305 case CHNCTYPE:
306 dochc(argv, argc);
307 break;
309 case SUBSTYPE:
311 * dosub - select substring
314 if (argc > 3)
315 dosub(argv, argc);
316 break;
318 case SHIFTYPE:
320 * doshift - push back all arguments
321 * except the first one (i.e. skip
322 * argv[2])
324 if (argc > 3) {
325 for (n = argc - 1; n > 3; n--) {
326 pbstr(rquote);
327 pbstr(argv[n]);
328 pbstr(lquote);
329 pushback(COMMA);
331 pbstr(rquote);
332 pbstr(argv[3]);
333 pbstr(lquote);
335 break;
337 case DIVRTYPE:
338 if (argc > 2 && (n = atoi(argv[2])) != 0)
339 dodiv(n);
340 else {
341 active = stdout;
342 oindex = 0;
344 break;
346 case UNDVTYPE:
347 doundiv(argv, argc);
348 break;
350 case DIVNTYPE:
352 * dodivnum - return the number of
353 * current output diversion
355 pbnum(oindex);
356 break;
358 case UNDFTYPE:
360 * doundefine - undefine a previously
361 * defined macro(s) or m4 keyword(s).
363 if (argc > 2)
364 for (n = 2; n < argc; n++)
365 macro_undefine(argv[n]);
366 break;
368 case POPDTYPE:
370 * dopopdef - remove the topmost
371 * definitions of macro(s) or m4
372 * keyword(s).
374 if (argc > 2)
375 for (n = 2; n < argc; n++)
376 macro_popdef(argv[n]);
377 break;
379 case MKTMTYPE:
381 * dotemp - create a temporary file
383 if (argc > 2) {
384 int fd;
385 char *temp;
387 temp = xstrdup(argv[2]);
389 fd = mkstemp(temp);
390 if (fd == -1)
391 err(1,
392 "%s at line %lu: couldn't make temp file %s",
393 CURRENT_NAME, CURRENT_LINE, argv[2]);
394 close(fd);
395 pbstr(temp);
396 free(temp);
398 break;
400 case TRNLTYPE:
402 * dotranslit - replace all characters in
403 * the source string that appears in the
404 * "from" string with the corresponding
405 * characters in the "to" string.
407 if (argc > 3) {
408 char *temp;
410 temp = xalloc(strlen(argv[2]) + 1, NULL);
411 if (argc > 4)
412 map(temp, argv[2], argv[3], argv[4]);
413 else
414 map(temp, argv[2], argv[3], null);
415 pbstr(temp);
416 free(temp);
417 } else if (argc > 2)
418 pbstr(argv[2]);
419 break;
421 case INDXTYPE:
423 * doindex - find the index of the second
424 * argument string in the first argument
425 * string. -1 if not present.
427 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
428 break;
430 case ERRPTYPE:
432 * doerrp - print the arguments to stderr
433 * file
435 if (argc > 2) {
436 for (n = 2; n < argc; n++)
437 fprintf(stderr, "%s ", argv[n]);
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);
645 } else
646 fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
650 * dodumpdef - dump the specified definitions in the hash
651 * table to stderr. If nothing is specified, the entire
652 * hash table is dumped.
654 static void
655 dodump(const char *argv[], int argc)
657 int n;
658 struct macro_definition *p;
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);
669 * dotrace - mark some macros as traced/untraced depending upon on.
671 static void
672 dotrace(const char *argv[], int argc, int on)
674 int n;
676 if (argc > 2) {
677 for (n = 2; n < argc; n++)
678 mark_traced(argv[n], on);
679 } else
680 mark_traced(NULL, on);
684 * doifelse - select one of two alternatives - loop.
686 static void
687 doifelse(const char *argv[], int argc)
689 for(;;) {
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;
699 break;
704 * doinclude - include a given file.
706 static int
707 doincl(const char *ifile)
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);
719 #ifdef EXTENDED
721 * dopaste - include a given file without any
722 * macro processing.
724 static int
725 dopaste(const char *pfile)
727 FILE *pf;
728 int c;
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 fclose(pf);
736 emit_synchline();
737 return (1);
738 } else
739 return (0);
741 #endif
744 * dochq - change quote characters
746 static void
747 dochq(const char *argv[], int ac)
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;
763 * dochc - change comment characters
765 static void
766 dochc(const char *argv[], int argc)
768 /* XXX Note that there is no difference between no argument and a single
769 * empty argument.
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));
785 * dom4wrap - expand text at EOF
787 static void
788 dom4wrap(const char *text)
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");
798 m4wraps[wrapindex++] = xstrdup(text);
802 * dodivert - divert the output to a temporary file
804 static void
805 dodiv(int n)
807 int fd;
809 oindex = n;
810 if (n >= maxout) {
811 if (mimic_gnu)
812 resizedivs(n + 10);
813 else
814 n = 0; /* bitbucket */
817 if (n < 0)
818 n = 0; /* bitbucket */
819 if (outfile[n] == NULL) {
820 char fname[] = _PATH_DIVNAME;
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);
828 active = outfile[n];
832 * doundivert - undivert a specified output, or all
833 * other outputs, in numerical order.
835 static void
836 doundiv(const char *argv[], int argc)
838 int ind;
839 int n;
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);
854 else
855 for (n = 1; n < maxout; n++)
856 if (outfile[n] != NULL)
857 getdiv(n);
861 * dosub - select substring
863 static void
864 dosub(const char *argv[], int argc)
866 const char *ap, *fc, *k;
867 int nc;
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);
888 * map:
889 * map every character of s1 that is specified in from
890 * into s3 and replace in s. (source s1 remains untouched)
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.
898 static void
899 map(char *dest, const char *src, const char *from, const char *to)
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
928 if (*src) {
929 if (mimic_gnu) {
931 * expand character ranges on the fly
933 from = handledash(frombis, frombis + 256, from);
934 to = handledash(tobis, tobis + 256, to);
936 tmp = from;
938 * create a mapping between "from" and
939 * "to"
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;
948 from++;
949 if (*to)
950 to++;
953 while (*src) {
954 sch = (unsigned char)(*src++);
955 dch = mapvec[sch];
956 if ((*dest = (char)dch))
957 dest++;
960 * restore all the changed characters
962 while (*tmp) {
963 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
964 tmp++;
967 *dest = '\0';
972 * handledash:
973 * use buffer to copy the src string, expanding character ranges
974 * on the way.
976 static const char *
977 handledash(char *buffer, char *end, const char *src)
979 char *p;
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;
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;
1004 src += 3;
1005 } else
1006 *p++ = *src++;
1007 if (p == end)
1008 break;
1010 *p = '\0';
1011 return buffer;