xref: /original-bsd/usr.bin/tr/tr.c (revision 753853ba)
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.3 (Berkeley) 01/16/92";
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 			string1[s1.lastch] = ch = s2.lastch;
163 			string2[ch] = 1;
164 			(void)next(&s2);
165 		}
166 	else
167 		while (next(&s1)) {
168 			string1[s1.lastch] = ch = s2.lastch;
169 			(void)next(&s2);
170 		}
171 
172 	if (cflag)
173 		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
174 			*p = *p == OOBCH ? ch : cnt;
175 
176 	if (sflag)
177 		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
178 			ch = string1[ch];
179 			if (!string2[ch] || lastch != ch) {
180 				lastch = ch;
181 				(void)putchar(ch);
182 			}
183 		}
184 	else
185 		while ((ch = getchar()) != EOF)
186 			(void)putchar(string1[ch]);
187 	exit (0);
188 }
189 
190 static void
191 setup(string, arg, str, cflag)
192 	int *string;
193 	char *arg;
194 	STR *str;
195 	int cflag;
196 {
197 	register int cnt, *p;
198 
199 	str->str = arg;
200 	bzero(string, NCHARS * sizeof(int));
201 	while (next(str))
202 		string[str->lastch] = 1;
203 	if (cflag)
204 		for (p = string, cnt = NCHARS; cnt--; ++p)
205 			*p = !*p;
206 }
207 
208 static void
209 usage()
210 {
211 	(void)fprintf(stderr, "usage: tr [-cs] string1 string2\n");
212 	(void)fprintf(stderr, "       tr [-c] -d string1\n");
213 	(void)fprintf(stderr, "       tr [-c] -s string1\n");
214 	(void)fprintf(stderr, "       tr [-c] -ds string1 string2\n");
215 	exit(1);
216 }
217 
218 #if __STDC__
219 #include <stdarg.h>
220 #else
221 #include <varargs.h>
222 #endif
223 
224 void
225 #if __STDC__
226 err(const char *fmt, ...)
227 #else
228 err(fmt, va_alist)
229 	char *fmt;
230         va_dcl
231 #endif
232 {
233 	va_list ap;
234 #if __STDC__
235 	va_start(ap, fmt);
236 #else
237 	va_start(ap);
238 #endif
239 	(void)fprintf(stderr, "tr: ");
240 	(void)vfprintf(stderr, fmt, ap);
241 	va_end(ap);
242 	(void)fprintf(stderr, "\n");
243 	exit(1);
244 	/* NOTREACHED */
245 }
246