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