BSD 4_3_Reno release
[unix-history] / usr / src / usr.bin / tr / tr.c
CommitLineData
5ad3291e
KB
1/*
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
1c15e888
C
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.
5ad3291e
KB
18 */
19
20#ifndef lint
21char 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
1c15e888 27static char sccsid[] = "@(#)tr.c 4.7 (Berkeley) 7/23/90";
5ad3291e
KB
28#endif /* not lint */
29
30#include <sys/types.h>
14db73f8 31#include <stdio.h>
5ad3291e 32#include <ctype.h>
14db73f8 33
5ad3291e
KB
34#define NCHARS 256 /* size of u_char */
35#define OOBCH 257 /* out of band value */
14db73f8 36
5ad3291e
KB
37typedef struct {
38 char *str;
39 int lastch, endrange;
40 enum { NORM, INRANGE, EOS } state;
41} STR;
14db73f8 42
5ad3291e
KB
43main(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];
14db73f8 52
5ad3291e
KB
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);
14db73f8 70 }
5ad3291e
KB
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);
14db73f8
BJ
84 }
85
5ad3291e
KB
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);
bbcc5e9f 146 }
5ad3291e
KB
147 else
148 while ((ch = getchar()) != EOF)
149 putchar((int)tab[ch]);
14db73f8
BJ
150 }
151 exit(0);
152}
153
154next(s)
20f87434 155 register STR *s;
14db73f8 156{
5ad3291e 157 register int ch;
14db73f8 158
5ad3291e
KB
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);
14db73f8 169 }
44ec1783
KB
170 if (ch == '\\') { /* \### */
171 s->lastch = tran(s);
5ad3291e
KB
172 return(1);
173 }
174 if (ch == '-') { /* ranges */
44ec1783
KB
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);
5ad3291e 181 if (s->lastch > ch) { /* "z-a" */
44ec1783
KB
182fail1: --s->str;
183fail2: s->lastch = '-';
5ad3291e 184 return(1);
14db73f8 185 }
5ad3291e
KB
186 if (s->lastch == ch) /* "a-a" */
187 return(next(s));
188 s->state = INRANGE; /* "a-z" */
44ec1783 189 s->endrange = ch;
5ad3291e 190 return(1);
14db73f8 191 }
5ad3291e
KB
192 s->lastch = ch;
193 return(1);
14db73f8 194}
44ec1783 195
20f87434
CT
196/*
197 * Translate \-escapes. Up to 3 octal digits => char; no digits => literal.
198 * Unadorned backslash "\" is like \000.
199 */
44ec1783
KB
200tran(s)
201 register STR *s;
202{
20f87434 203 register int ch, cnt = 0, val = 0;
44ec1783 204
20f87434
CT
205 for (;;) {
206 ch = *s->str++;
207 if (!isascii(ch) || !isdigit(ch) || ++cnt > 3)
208 break;
44ec1783 209 val = val * 8 + ch - '0';
20f87434
CT
210 }
211 if (cnt || ch == 0)
212 s->str--;
213 return (cnt ? val : ch);
44ec1783 214}