1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)tr.c 4.5 (Berkeley) 05/10/90"; 26 #endif /* not lint */ 27 28 #include <sys/types.h> 29 #include <stdio.h> 30 #include <ctype.h> 31 32 #define NCHARS 256 /* size of u_char */ 33 #define OOBCH 257 /* out of band value */ 34 35 typedef struct { 36 char *str; 37 int lastch, endrange; 38 enum { NORM, INRANGE, EOS } state; 39 } STR; 40 41 main(argc, argv) 42 int argc; 43 char **argv; 44 { 45 extern int optind; 46 STR s1, s2; 47 register int ch, indx, lastch; 48 int cflag, dflag, sflag; 49 u_char *tp, tab[NCHARS], squeeze[NCHARS]; 50 51 cflag = dflag = sflag = 0; 52 while ((ch = getopt(argc, argv, "cds")) != EOF) 53 switch((char)ch) { 54 case 'c': 55 cflag = 1; 56 break; 57 case 'd': 58 dflag = 1; 59 break; 60 case 's': 61 sflag = 1; 62 break; 63 case '?': 64 default: 65 fprintf(stderr, 66 "usage: tr [-cds] [string1 [string2]]\n"); 67 exit(1); 68 } 69 argc -= optind; 70 argv += optind; 71 72 /* 73 * the original tr was amazingly tolerant of the command line. 74 * Neither -c or -s have any effect unless there are two strings. 75 * Extra arguments are silently ignored. Bag this noise, they 76 * should all be errors. 77 */ 78 if (argc < 2 && !dflag) { 79 while ((ch = getchar()) != EOF) 80 putchar(ch); 81 exit(0); 82 } 83 84 bzero(tab, NCHARS); 85 if (sflag) { 86 s1.str = argv[1]; 87 s1.state = NORM; 88 s1.lastch = OOBCH; 89 while (next(&s1)) 90 squeeze[s1.lastch] = 1; 91 } 92 if (dflag) { 93 s1.str = argv[0]; 94 s1.state = NORM; 95 s1.lastch = OOBCH; 96 while (next(&s1)) 97 tab[s1.lastch] = 1; 98 if (cflag) 99 for (tp = tab, indx = 0; indx < NCHARS; ++tp, ++indx) 100 *tp = !*tp; 101 if (sflag) 102 for (lastch = OOBCH; (ch = getchar()) != EOF;) { 103 if (tab[ch] || (squeeze[ch] && lastch == ch)) 104 continue; 105 lastch = ch; 106 putchar(ch); 107 } 108 else 109 while ((ch = getchar()) != EOF) 110 if (!tab[ch]) 111 putchar(ch); 112 } else { 113 s1.str = argv[0]; 114 s2.str = argv[1]; 115 s1.state = s2.state = NORM; 116 s1.lastch = s2.lastch = OOBCH; 117 if (cflag) { 118 /* 119 * if cflag is set, tr just pretends it only got one 120 * character in string2. As reasonable as anything 121 * else. Should really be an error. 122 */ 123 while (next(&s2)); 124 lastch = s2.lastch; 125 for (tp = tab, indx = 0; indx < NCHARS; ++tp, ++indx) 126 *tp = lastch; 127 while (next(&s1)) 128 tab[s1.lastch] = s1.lastch; 129 } else { 130 for (tp = tab, indx = 0; indx < NCHARS; ++tp, ++indx) 131 *tp = indx; 132 while (next(&s1)) { 133 (void)next(&s2); 134 tab[s1.lastch] = s2.lastch; 135 } 136 } 137 if (sflag) 138 for (lastch = OOBCH; (ch = getchar()) != EOF;) { 139 ch = tab[ch]; 140 if (squeeze[ch] && lastch == ch) 141 continue; 142 lastch = ch; 143 putchar(ch); 144 } 145 else 146 while ((ch = getchar()) != EOF) 147 putchar((int)tab[ch]); 148 } 149 exit(0); 150 } 151 152 next(s) 153 STR *s; 154 { 155 register int ch; 156 157 if (s->state == EOS) 158 return(0); 159 if (s->state == INRANGE) { 160 if (++s->lastch == s->endrange) 161 s->state = NORM; 162 return(1); 163 } 164 if (!(ch = *s->str++)) { 165 s->state = EOS; 166 return(0); 167 } 168 if (ch == '\\') { /* \### */ 169 s->lastch = tran(s); 170 return(1); 171 } 172 if (ch == '-') { /* ranges */ 173 if (s->lastch == OOBCH) /* "-a" */ 174 goto fail2; 175 if (!(ch = *s->str++)) /* "a-" */ 176 goto fail1; 177 if (ch == '\\') /* \### */ 178 ch = tran(s); 179 if (s->lastch > ch) { /* "z-a" */ 180 fail1: --s->str; 181 fail2: s->lastch = '-'; 182 return(1); 183 } 184 if (s->lastch == ch) /* "a-a" */ 185 return(next(s)); 186 s->state = INRANGE; /* "a-z" */ 187 s->endrange = ch; 188 return(1); 189 } 190 s->lastch = ch; 191 return(1); 192 } 193 194 tran(s) 195 register STR *s; 196 { 197 register int ch, cnt, val; 198 199 for (val = cnt = 0; isascii(ch = *s->str++) && isdigit(ch) 200 && cnt++ < 3;) 201 val = val * 8 + ch - '0'; 202 return(cnt ? val : ch); 203 } 204