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