xref: /original-bsd/usr.bin/tr/tr.c (revision b4971bb3)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)tr.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "extern.h"
23 
24 static int string1[NCHARS] = {
25 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,		/* ASCII */
26 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
27 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
28 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
29 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
30 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
31 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
32 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
33 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
34 	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
35 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
36 	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
37 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
38 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
39 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
40 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
41 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
42 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
43 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
44 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
45 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
46 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
47 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
48 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
49 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
50 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
51 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
52 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
53 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
54 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
55 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
56 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
57 }, string2[NCHARS];
58 
59 STR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
60 STR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
61 
62 static void setup __P((int *, char *, STR *, int));
63 static void usage __P((void));
64 
65 int
66 main(argc, argv)
67 	int argc;
68 	char **argv;
69 {
70 	register int ch, cnt, lastch, *p;
71 	int cflag, dflag, sflag, isstring2;
72 
73 	cflag = dflag = sflag = 0;
74 	while ((ch = getopt(argc, argv, "cds")) != EOF)
75 		switch((char)ch) {
76 		case 'c':
77 			cflag = 1;
78 			break;
79 		case 'd':
80 			dflag = 1;
81 			break;
82 		case 's':
83 			sflag = 1;
84 			break;
85 		case '?':
86 		default:
87 			usage();
88 		}
89 	argc -= optind;
90 	argv += optind;
91 
92 	switch(argc) {
93 	case 0:
94 	default:
95 		usage();
96 		/* NOTREACHED */
97 	case 1:
98 		isstring2 = 0;
99 		break;
100 	case 2:
101 		isstring2 = 1;
102 		break;
103 	}
104 
105 	/*
106 	 * tr -ds [-c] string1 string2
107 	 * Delete all characters (or complemented characters) in string1.
108 	 * Squeeze all characters in string2.
109 	 */
110 	if (dflag && sflag) {
111 		if (!isstring2)
112 			usage();
113 
114 		setup(string1, argv[0], &s1, cflag);
115 		setup(string2, argv[1], &s2, 0);
116 
117 		for (lastch = OOBCH; (ch = getchar()) != EOF;)
118 			if (!string1[ch] && (!string2[ch] || lastch != ch)) {
119 				lastch = ch;
120 				(void)putchar(ch);
121 			}
122 		exit(0);
123 	}
124 
125 	/*
126 	 * tr -d [-c] string1
127 	 * Delete all characters (or complemented characters) in string1.
128 	 */
129 	if (dflag) {
130 		if (isstring2)
131 			usage();
132 
133 		setup(string1, argv[0], &s1, cflag);
134 
135 		while ((ch = getchar()) != EOF)
136 			if (!string1[ch])
137 				(void)putchar(ch);
138 		exit(0);
139 	}
140 
141 	/*
142 	 * tr -s [-c] string1
143 	 * Squeeze all characters (or complemented characters) in string1.
144 	 */
145 	if (sflag && !isstring2) {
146 		setup(string1, argv[0], &s1, cflag);
147 
148 		for (lastch = OOBCH; (ch = getchar()) != EOF;)
149 			if (!string1[ch] || lastch != ch) {
150 				lastch = ch;
151 				(void)putchar(ch);
152 			}
153 		exit(0);
154 	}
155 
156 	/*
157 	 * tr [-cs] string1 string2
158 	 * Replace all characters (or complemented characters) in string1 with
159 	 * the character in the same position in string2.  If the -s option is
160 	 * specified, squeeze all the characters in string2.
161 	 */
162 	if (!isstring2)
163 		usage();
164 
165 	s1.str = argv[0];
166 	s2.str = argv[1];
167 
168 	if (cflag)
169 		for (cnt = NCHARS, p = string1; cnt--;)
170 			*p++ = OOBCH;
171 
172 	if (!next(&s2))
173 		err("empty string2");
174 
175 	/* If string2 runs out of characters, use the last one specified. */
176 	if (sflag)
177 		while (next(&s1)) {
178 			string1[s1.lastch] = ch = s2.lastch;
179 			string2[ch] = 1;
180 			(void)next(&s2);
181 		}
182 	else
183 		while (next(&s1)) {
184 			string1[s1.lastch] = ch = s2.lastch;
185 			(void)next(&s2);
186 		}
187 
188 	if (cflag)
189 		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
190 			*p = *p == OOBCH ? ch : cnt;
191 
192 	if (sflag)
193 		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
194 			ch = string1[ch];
195 			if (!string2[ch] || lastch != ch) {
196 				lastch = ch;
197 				(void)putchar(ch);
198 			}
199 		}
200 	else
201 		while ((ch = getchar()) != EOF)
202 			(void)putchar(string1[ch]);
203 	exit (0);
204 }
205 
206 static void
207 setup(string, arg, str, cflag)
208 	int *string;
209 	char *arg;
210 	STR *str;
211 	int cflag;
212 {
213 	register int cnt, *p;
214 
215 	str->str = arg;
216 	bzero(string, NCHARS * sizeof(int));
217 	while (next(str))
218 		string[str->lastch] = 1;
219 	if (cflag)
220 		for (p = string, cnt = NCHARS; cnt--; ++p)
221 			*p = !*p;
222 }
223 
224 static void
225 usage()
226 {
227 	(void)fprintf(stderr, "usage: tr [-cs] string1 string2\n");
228 	(void)fprintf(stderr, "       tr [-c] -d string1\n");
229 	(void)fprintf(stderr, "       tr [-c] -s string1\n");
230 	(void)fprintf(stderr, "       tr [-c] -ds string1 string2\n");
231 	exit(1);
232 }
233 
234 #if __STDC__
235 #include <stdarg.h>
236 #else
237 #include <varargs.h>
238 #endif
239 
240 void
241 #if __STDC__
242 err(const char *fmt, ...)
243 #else
244 err(fmt, va_alist)
245 	char *fmt;
246         va_dcl
247 #endif
248 {
249 	va_list ap;
250 #if __STDC__
251 	va_start(ap, fmt);
252 #else
253 	va_start(ap);
254 #endif
255 	(void)fprintf(stderr, "tr: ");
256 	(void)vfprintf(stderr, fmt, ap);
257 	va_end(ap);
258 	(void)fprintf(stderr, "\n");
259 	exit(1);
260 	/* NOTREACHED */
261 }
262