xref: /plan9/sys/src/cmd/tr.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include 	<u.h>
2 #include 	<libc.h>
3 
4 typedef struct PCB	/* Control block controlling specification parse */
5 {
6 	char	*base;		/* start of specification */
7 	char	*current;	/* current parse point */
8 	long	last;		/* last Rune returned */
9 	long	final;		/* final Rune in a span */
10 } Pcb;
11 
12 uchar	bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
13 
14 #define	SETBIT(a, c)		((a)[(c)/8] |= bits[(c)&07])
15 #define	CLEARBIT(a,c)		((a)[(c)/8] &= ~bits[(c)&07])
16 #define	BITSET(a,c)		((a)[(c)/8] & bits[(c)&07])
17 
18 #define	MAXRUNE	0xFFFF
19 
20 uchar	f[(MAXRUNE+1)/8];
21 uchar	t[(MAXRUNE+1)/8];
22 char 	wbuf[4096];
23 char	*wptr;
24 
25 Pcb pfrom, pto;
26 
27 int cflag;
28 int dflag;
29 int sflag;
30 
31 void	complement(void);
32 void	delete(void);
33 void	squeeze(void);
34 void	translit(void);
35 void	error(char*);
36 long	canon(Pcb*);
37 char	*getrune(char*, Rune*);
38 void	Pinit(Pcb*, char*);
39 void	Prewind(Pcb *p);
40 int	readrune(int, long*);
41 void	wflush(int);
42 void	writerune(int, Rune);
43 
44 void
45 main(int argc, char **argv)
46 {
47 	ARGBEGIN{
48 	case 's':	sflag++; break;
49 	case 'd':	dflag++; break;
50 	case 'c':	cflag++; break;
51 	default:	error("bad option");
52 	}ARGEND
53 	if(argc>0)
54 		Pinit(&pfrom, argv[0]);
55 	if(argc>1)
56 		Pinit(&pto, argv[1]);
57 	if(argc>2)
58 		error("arg count");
59 	if(dflag) {
60 		if ((sflag && argc != 2) || (!sflag && argc != 1))
61 			error("arg count");
62 		delete();
63 	} else {
64 		if (argc != 2)
65 			error("arg count");
66 		if (cflag)
67 			complement();
68 		else translit();
69 	}
70 	exits(0);
71 }
72 
73 void
74 delete(void)
75 {
76 	long c, last;
77 
78 	if (cflag) {
79 		memset((char *) f, 0xff, sizeof f);
80 		while ((c = canon(&pfrom)) >= 0)
81 			CLEARBIT(f, c);
82 	} else {
83 		while ((c = canon(&pfrom)) >= 0)
84 			SETBIT(f, c);
85 	}
86 	if (sflag) {
87 		while ((c = canon(&pto)) >= 0)
88 			SETBIT(t, c);
89 	}
90 
91 	last = 0x10000;
92 	while (readrune(0, &c) > 0) {
93 		if(!BITSET(f, c) && (c != last || !BITSET(t,c))) {
94 			last = c;
95 			writerune(1, (Rune) c);
96 		}
97 	}
98 	wflush(1);
99 }
100 
101 void
102 complement(void)
103 {
104 	Rune *p;
105 	int i;
106 	long from, to, lastc, high;
107 
108 	lastc = 0;
109 	high = 0;
110 	while ((from = canon(&pfrom)) >= 0) {
111 		if (from > high) high = from;
112 		SETBIT(f, from);
113 	}
114 	while ((to = canon(&pto)) > 0) {
115 		if (to > high) high = to;
116 		SETBIT(t,to);
117 	}
118 	Prewind(&pto);
119 	if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
120 		error("can't allocate memory");
121 	for (i = 0; i <= high; i++){
122 		if (!BITSET(f,i)) {
123 			if ((to = canon(&pto)) < 0)
124 				to = lastc;
125 			else lastc = to;
126 			p[i] = to;
127 		}
128 		else p[i] = i;
129 	}
130 	if (sflag){
131 		lastc = 0x10000;
132 		while (readrune(0, &from) > 0) {
133 			if (from > high)
134 				from = to;
135 			else
136 				from = p[from];
137 			if (from != lastc || !BITSET(t,from)) {
138 				lastc = from;
139 				writerune(1, (Rune) from);
140 			}
141 		}
142 
143 	} else {
144 		while (readrune(0, &from) > 0){
145 			if (from > high)
146 				from = to;
147 			else
148 				from = p[from];
149 			writerune(1, (Rune) from);
150 		}
151 	}
152 	wflush(1);
153 }
154 
155 void
156 translit(void)
157 {
158 	Rune *p;
159 	int i;
160 	long from, to, lastc, high;
161 
162 	lastc = 0;
163 	high = 0;
164 	while ((from = canon(&pfrom)) >= 0)
165 		if (from > high) high = from;
166 	Prewind(&pfrom);
167 	if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
168 		error("can't allocate memory");
169 	for (i = 0; i <= high; i++)
170 		p[i] = i;
171 	while ((from = canon(&pfrom)) >= 0) {
172 		if ((to = canon(&pto)) < 0)
173 			to = lastc;
174 		else lastc = to;
175 		if (BITSET(f,from) && p[from] != to)
176 			error("ambiguous translation");
177 		SETBIT(f,from);
178 		p[from] = to;
179 		SETBIT(t,to);
180 	}
181 	while ((to = canon(&pto)) >= 0) {
182 		SETBIT(t,to);
183 	}
184 	if (sflag){
185 		lastc = 0x10000;
186 		while (readrune(0, &from) > 0) {
187 			if (from <= high)
188 				from = p[from];
189 			if (from != lastc || !BITSET(t,from)) {
190 				lastc = from;
191 				writerune(1, (Rune) from);
192 			}
193 		}
194 
195 	} else {
196 		while (readrune(0, &from) > 0) {
197 			if (from <= high)
198 				from = p[from];
199 			writerune(1, (Rune) from);
200 		}
201 	}
202 	wflush(1);
203 }
204 
205 int
206 readrune(int fd, long *rp)
207 {
208 	Rune r;
209 	int j;
210 	static int i, n;
211 	static char buf[4096];
212 
213 	j = i;
214 	for (;;) {
215 		if (i >= n) {
216 			wflush(1);
217 			if (j != i)
218 				memcpy(buf, buf+j, n-j);
219 			i = n-j;
220 			n = read(fd, &buf[i], sizeof(buf)-i);
221 			if (n < 0)
222 				error("read error");
223 			if (n == 0)
224 				return 0;
225 			j = 0;
226 			n += i;
227 		}
228 		i++;
229 		if (fullrune(&buf[j], i-j))
230 			break;
231 	}
232 	chartorune(&r, &buf[j]);
233 	*rp = r;
234 	return 1;
235 }
236 
237 void
238 writerune(int fd, Rune r)
239 {
240 	char buf[UTFmax];
241 	int n;
242 
243 	if (!wptr)
244 		wptr = wbuf;
245 	n = runetochar(buf, (Rune*)&r);
246 	if (wptr+n >= wbuf+sizeof(wbuf))
247 		wflush(fd);
248 	memcpy(wptr, buf, n);
249 	wptr += n;
250 }
251 
252 void
253 wflush(int fd)
254 {
255 	if (wptr && wptr > wbuf)
256 		if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf)
257 			error("write error");
258 	wptr = wbuf;
259 }
260 
261 char *
262 getrune(char *s, Rune *rp)
263 {
264 	Rune r;
265 	char *save;
266 	int i, n;
267 
268 	s += chartorune(rp, s);
269 	if((r = *rp) == '\\' && *s){
270 		n = 0;
271 		if (*s == 'x') {
272 			s++;
273 			for (i = 0; i < 4; i++) {
274 				save = s;
275 				s += chartorune(&r, s);
276 				if ('0' <= r && r <= '9')
277 					n = 16*n + r - '0';
278 				else if ('a' <= r && r <= 'f')
279 					n = 16*n + r - 'a' + 10;
280 				else if ('A' <= r && r <= 'F')
281 					n = 16*n + r - 'A' + 10;
282 				else {
283 					if (i == 0)
284 						*rp = 'x';
285 					else *rp = n;
286 					return save;
287 				}
288 			}
289 		} else {
290 			for(i = 0; i < 3; i++) {
291 				save = s;
292 				s += chartorune(&r, s);
293 				if('0' <= r && r <= '7')
294 					n = 8*n + r - '0';
295 				else {
296 					if (i == 0)
297 					{
298 						*rp = r;
299 						return s;
300 					}
301 					*rp = n;
302 					return save;
303 				}
304 			}
305 			if(n > 0377)
306 				error("char>0377");
307 		}
308 		*rp = n;
309 	}
310 	return s;
311 }
312 
313 long
314 canon(Pcb *p)
315 {
316 	Rune r;
317 
318 	if (p->final >= 0) {
319 		if (p->last < p->final)
320 			return ++p->last;
321 		p->final = -1;
322 	}
323 	if (*p->current == '\0')
324 		return -1;
325 	if(*p->current == '-' && p->last >= 0 && p->current[1]){
326 		p->current = getrune(p->current+1, &r);
327 		if (r < p->last)
328 			error ("Invalid range specification");
329 		if (r > p->last) {
330 			p->final = r;
331 			return ++p->last;
332 		}
333 	}
334 	p->current = getrune(p->current, &r);
335 	p->last = r;
336 	return p->last;
337 }
338 
339 void
340 Pinit(Pcb *p, char *cp)
341 {
342 	p->current = p->base = cp;
343 	p->last = p->final = -1;
344 }
345 void
346 Prewind(Pcb *p)
347 {
348 	p->current = p->base;
349 	p->last = p->final = -1;
350 }
351 void
352 error(char *s)
353 {
354 	fprint(2, "%s: %s\n", argv0, s);
355 	exits(s);
356 }
357