xref: /original-bsd/usr.bin/tr/tr.c (revision e59fb703)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)tr.c	5.2 (Berkeley) 10/27/91";
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 }, string2[NCHARS];
42 
43 STR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
44 STR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
45 
46 static void setup __P((int *, char *, STR *, int));
47 static void usage __P((void));
48 
49 int
50 main(argc, argv)
51 	int argc;
52 	char **argv;
53 {
54 	register int ch, cnt, lastch, *p;
55 	int cflag, dflag, sflag, isstring2;
56 
57 	cflag = dflag = sflag = 0;
58 	while ((ch = getopt(argc, argv, "cds")) != EOF)
59 		switch((char)ch) {
60 		case 'c':
61 			cflag = 1;
62 			break;
63 		case 'd':
64 			dflag = 1;
65 			break;
66 		case 's':
67 			sflag = 1;
68 			break;
69 		case '?':
70 		default:
71 			usage();
72 		}
73 	argc -= optind;
74 	argv += optind;
75 
76 	switch(argc) {
77 	case 0:
78 	default:
79 		usage();
80 		/* NOTREACHED */
81 	case 1:
82 		isstring2 = 0;
83 		break;
84 	case 2:
85 		isstring2 = 1;
86 		break;
87 	}
88 
89 	/*
90 	 * tr -ds [-c] string1 string2
91 	 * Delete all characters (or complemented characters) in string1.
92 	 * Squeeze all characters in string2.
93 	 */
94 	if (dflag && sflag) {
95 		if (!isstring2)
96 			usage();
97 
98 		setup(string1, argv[0], &s1, cflag);
99 		setup(string2, argv[1], &s2, 0);
100 
101 		for (lastch = OOBCH; (ch = getchar()) != EOF;)
102 			if (!string1[ch] && (!string2[ch] || lastch != ch)) {
103 				lastch = ch;
104 				(void)putchar(ch);
105 			}
106 		exit(0);
107 	}
108 
109 	/*
110 	 * tr -d [-c] string1
111 	 * Delete all characters (or complemented characters) in string1.
112 	 */
113 	if (dflag) {
114 		if (isstring2)
115 			usage();
116 
117 		setup(string1, argv[0], &s1, cflag);
118 
119 		while ((ch = getchar()) != EOF)
120 			if (!string1[ch])
121 				(void)putchar(ch);
122 		exit(0);
123 	}
124 
125 	/*
126 	 * tr -s [-c] string1
127 	 * Squeeze all characters (or complemented characters) in string1.
128 	 */
129 	if (sflag && !isstring2) {
130 		setup(string1, argv[0], &s1, cflag);
131 
132 		for (lastch = OOBCH; (ch = getchar()) != EOF;)
133 			if (!string1[ch] || lastch != ch) {
134 				lastch = ch;
135 				(void)putchar(ch);
136 			}
137 		exit(0);
138 	}
139 
140 	/*
141 	 * tr [-cs] string1 string2
142 	 * Replace all characters (or complemented characters) in string1 with
143 	 * the character in the same position in string2.  If the -s option is
144 	 * specified, squeeze all the characters in string2.
145 	 */
146 	if (!isstring2)
147 		usage();
148 
149 	s1.str = argv[0];
150 	s2.str = argv[1];
151 
152 	if (cflag)
153 		for (cnt = NCHARS, p = string1; cnt--;)
154 			*p++ = OOBCH;
155 
156 	if (!next(&s2))
157 		err("empty string2");
158 
159 	/* If string2 runs out of characters, use the last one specified. */
160 	if (sflag)
161 		while (next(&s1)) {
162 			ch = s2.lastch;
163 			string1[s1.lastch] = ch;
164 			string2[ch] = 1;
165 			(void)next(&s2);
166 		}
167 	else
168 		while (next(&s1)) {
169 			ch = s2.lastch;
170 			string1[s1.lastch] = ch;
171 			(void)next(&s2);
172 		}
173 
174 	if (cflag)
175 		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
176 			*p = *p == OOBCH ? ch : cnt;
177 
178 	if (sflag)
179 		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
180 			ch = string1[ch];
181 			if (!string2[ch] || lastch != ch) {
182 				lastch = ch;
183 				(void)putchar(ch);
184 			}
185 		}
186 	else
187 		while ((ch = getchar()) != EOF)
188 			(void)putchar(string1[ch]);
189 	exit (0);
190 }
191 
192 static void
193 setup(string, arg, str, cflag)
194 	int *string;
195 	char *arg;
196 	STR *str;
197 	int cflag;
198 {
199 	register int cnt, *p;
200 
201 	str->str = arg;
202 	bzero(string, NCHARS * sizeof(int));
203 	while (next(str))
204 		string[str->lastch] = 1;
205 	if (cflag)
206 		for (p = string, cnt = NCHARS; cnt--; ++p)
207 			*p = !*p;
208 }
209 
210 static void
211 usage()
212 {
213 	(void)fprintf(stderr, "usage: tr [-cs] string1 string2\n");
214 	(void)fprintf(stderr, "       tr [-c] -d string1\n");
215 	(void)fprintf(stderr, "       tr [-c] -s string1\n");
216 	(void)fprintf(stderr, "       tr [-c] -ds string1 string2\n");
217 	exit(1);
218 }
219 
220 #if __STDC__
221 #include <stdarg.h>
222 #else
223 #include <varargs.h>
224 #endif
225 
226 void
227 #if __STDC__
228 err(const char *fmt, ...)
229 #else
230 err(fmt, va_alist)
231 	char *fmt;
232         va_dcl
233 #endif
234 {
235 	va_list ap;
236 #if __STDC__
237 	va_start(ap, fmt);
238 #else
239 	va_start(ap);
240 #endif
241 	(void)fprintf(stderr, "tr: ");
242 	(void)vfprintf(stderr, fmt, ap);
243 	va_end(ap);
244 	(void)fprintf(stderr, "\n");
245 	exit(1);
246 	/* NOTREACHED */
247 }
248