xref: /plan9/sys/src/cmd/tr.c (revision 82726826a7b3d40fb66339b4b0e95b60314f98b9)
13e12c5d1SDavid du Colombier #include 	<u.h>
23e12c5d1SDavid du Colombier #include 	<libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier typedef struct PCB	/* Control block controlling specification parse */
53e12c5d1SDavid du Colombier {
63e12c5d1SDavid du Colombier 	char	*base;		/* start of specification */
73e12c5d1SDavid du Colombier 	char	*current;	/* current parse point */
83e12c5d1SDavid du Colombier 	long	last;		/* last Rune returned */
93e12c5d1SDavid du Colombier 	long	final;		/* final Rune in a span */
103e12c5d1SDavid du Colombier } Pcb;
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier uchar	bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
133e12c5d1SDavid du Colombier 
143e12c5d1SDavid du Colombier #define	SETBIT(a, c)		((a)[(c)/8] |= bits[(c)&07])
153e12c5d1SDavid du Colombier #define	CLEARBIT(a,c)		((a)[(c)/8] &= ~bits[(c)&07])
163e12c5d1SDavid du Colombier #define	BITSET(a,c)		((a)[(c)/8] & bits[(c)&07])
173e12c5d1SDavid du Colombier 
18*82726826SDavid du Colombier uchar	f[(Runemax+1)/8];
19*82726826SDavid du Colombier uchar	t[(Runemax+1)/8];
20219b2ee8SDavid du Colombier char 	wbuf[4096];
21219b2ee8SDavid du Colombier char	*wptr;
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier Pcb pfrom, pto;
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier int cflag;
263e12c5d1SDavid du Colombier int dflag;
273e12c5d1SDavid du Colombier int sflag;
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier void	complement(void);
303e12c5d1SDavid du Colombier void	delete(void);
313e12c5d1SDavid du Colombier void	squeeze(void);
323e12c5d1SDavid du Colombier void	translit(void);
333e12c5d1SDavid du Colombier long	canon(Pcb*);
343e12c5d1SDavid du Colombier char	*getrune(char*, Rune*);
353e12c5d1SDavid du Colombier void	Pinit(Pcb*, char*);
363e12c5d1SDavid du Colombier void	Prewind(Pcb *p);
37219b2ee8SDavid du Colombier int	readrune(int, long*);
38219b2ee8SDavid du Colombier void	wflush(int);
39219b2ee8SDavid du Colombier void	writerune(int, Rune);
403e12c5d1SDavid du Colombier 
419b004bddSDavid du Colombier static void
usage(void)429b004bddSDavid du Colombier usage(void)
439b004bddSDavid du Colombier {
449b004bddSDavid du Colombier 	fprint(2, "usage: %s [-cds] [string1 [string2]]\n", argv0);
459b004bddSDavid du Colombier 	exits("usage");
469b004bddSDavid du Colombier }
479b004bddSDavid du Colombier 
483e12c5d1SDavid du Colombier void
main(int argc,char ** argv)493e12c5d1SDavid du Colombier main(int argc, char **argv)
503e12c5d1SDavid du Colombier {
513e12c5d1SDavid du Colombier 	ARGBEGIN{
523e12c5d1SDavid du Colombier 	case 's':	sflag++; break;
533e12c5d1SDavid du Colombier 	case 'd':	dflag++; break;
543e12c5d1SDavid du Colombier 	case 'c':	cflag++; break;
559b004bddSDavid du Colombier 	default:	usage();
563e12c5d1SDavid du Colombier 	}ARGEND
573e12c5d1SDavid du Colombier 	if(argc>0)
583e12c5d1SDavid du Colombier 		Pinit(&pfrom, argv[0]);
593e12c5d1SDavid du Colombier 	if(argc>1)
603e12c5d1SDavid du Colombier 		Pinit(&pto, argv[1]);
613e12c5d1SDavid du Colombier 	if(argc>2)
629b004bddSDavid du Colombier 		usage();
633e12c5d1SDavid du Colombier 	if(dflag) {
64219b2ee8SDavid du Colombier 		if ((sflag && argc != 2) || (!sflag && argc != 1))
659b004bddSDavid du Colombier 			usage();
663e12c5d1SDavid du Colombier 		delete();
673e12c5d1SDavid du Colombier 	} else {
683e12c5d1SDavid du Colombier 		if (argc != 2)
699b004bddSDavid du Colombier 			usage();
703e12c5d1SDavid du Colombier 		if (cflag)
713e12c5d1SDavid du Colombier 			complement();
723e12c5d1SDavid du Colombier 		else translit();
733e12c5d1SDavid du Colombier 	}
743e12c5d1SDavid du Colombier 	exits(0);
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier void
delete(void)783e12c5d1SDavid du Colombier delete(void)
793e12c5d1SDavid du Colombier {
803e12c5d1SDavid du Colombier 	long c, last;
813e12c5d1SDavid du Colombier 
823e12c5d1SDavid du Colombier 	if (cflag) {
833e12c5d1SDavid du Colombier 		memset((char *) f, 0xff, sizeof f);
843e12c5d1SDavid du Colombier 		while ((c = canon(&pfrom)) >= 0)
853e12c5d1SDavid du Colombier 			CLEARBIT(f, c);
863e12c5d1SDavid du Colombier 	} else {
873e12c5d1SDavid du Colombier 		while ((c = canon(&pfrom)) >= 0)
883e12c5d1SDavid du Colombier 			SETBIT(f, c);
893e12c5d1SDavid du Colombier 	}
903e12c5d1SDavid du Colombier 	if (sflag) {
913e12c5d1SDavid du Colombier 		while ((c = canon(&pto)) >= 0)
923e12c5d1SDavid du Colombier 			SETBIT(t, c);
933e12c5d1SDavid du Colombier 	}
943e12c5d1SDavid du Colombier 
953e12c5d1SDavid du Colombier 	last = 0x10000;
96219b2ee8SDavid du Colombier 	while (readrune(0, &c) > 0) {
973e12c5d1SDavid du Colombier 		if(!BITSET(f, c) && (c != last || !BITSET(t,c))) {
983e12c5d1SDavid du Colombier 			last = c;
99219b2ee8SDavid du Colombier 			writerune(1, (Rune) c);
1003e12c5d1SDavid du Colombier 		}
1013e12c5d1SDavid du Colombier 	}
102219b2ee8SDavid du Colombier 	wflush(1);
1033e12c5d1SDavid du Colombier }
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier void
complement(void)1063e12c5d1SDavid du Colombier complement(void)
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier 	Rune *p;
1093e12c5d1SDavid du Colombier 	int i;
1103e12c5d1SDavid du Colombier 	long from, to, lastc, high;
1113e12c5d1SDavid du Colombier 
1123e12c5d1SDavid du Colombier 	lastc = 0;
1133e12c5d1SDavid du Colombier 	high = 0;
1143e12c5d1SDavid du Colombier 	while ((from = canon(&pfrom)) >= 0) {
1153e12c5d1SDavid du Colombier 		if (from > high) high = from;
1163e12c5d1SDavid du Colombier 		SETBIT(f, from);
1173e12c5d1SDavid du Colombier 	}
1183e12c5d1SDavid du Colombier 	while ((to = canon(&pto)) > 0) {
1193e12c5d1SDavid du Colombier 		if (to > high) high = to;
1203e12c5d1SDavid du Colombier 		SETBIT(t,to);
1213e12c5d1SDavid du Colombier 	}
1223e12c5d1SDavid du Colombier 	Prewind(&pto);
1233e12c5d1SDavid du Colombier 	if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
1249b004bddSDavid du Colombier 		sysfatal("no memory");
1253e12c5d1SDavid du Colombier 	for (i = 0; i <= high; i++){
1263e12c5d1SDavid du Colombier 		if (!BITSET(f,i)) {
1273e12c5d1SDavid du Colombier 			if ((to = canon(&pto)) < 0)
1283e12c5d1SDavid du Colombier 				to = lastc;
1293e12c5d1SDavid du Colombier 			else lastc = to;
1303e12c5d1SDavid du Colombier 			p[i] = to;
1313e12c5d1SDavid du Colombier 		}
1323e12c5d1SDavid du Colombier 		else p[i] = i;
1333e12c5d1SDavid du Colombier 	}
1343e12c5d1SDavid du Colombier 	if (sflag){
1353e12c5d1SDavid du Colombier 		lastc = 0x10000;
136219b2ee8SDavid du Colombier 		while (readrune(0, &from) > 0) {
137219b2ee8SDavid du Colombier 			if (from > high)
138219b2ee8SDavid du Colombier 				from = to;
139219b2ee8SDavid du Colombier 			else
140219b2ee8SDavid du Colombier 				from = p[from];
1413e12c5d1SDavid du Colombier 			if (from != lastc || !BITSET(t,from)) {
1423e12c5d1SDavid du Colombier 				lastc = from;
143219b2ee8SDavid du Colombier 				writerune(1, (Rune) from);
1443e12c5d1SDavid du Colombier 			}
1453e12c5d1SDavid du Colombier 		}
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier 	} else {
148219b2ee8SDavid du Colombier 		while (readrune(0, &from) > 0){
149219b2ee8SDavid du Colombier 			if (from > high)
150219b2ee8SDavid du Colombier 				from = to;
151219b2ee8SDavid du Colombier 			else
152219b2ee8SDavid du Colombier 				from = p[from];
153219b2ee8SDavid du Colombier 			writerune(1, (Rune) from);
1543e12c5d1SDavid du Colombier 		}
1553e12c5d1SDavid du Colombier 	}
156219b2ee8SDavid du Colombier 	wflush(1);
1573e12c5d1SDavid du Colombier }
1583e12c5d1SDavid du Colombier 
1593e12c5d1SDavid du Colombier void
translit(void)1603e12c5d1SDavid du Colombier translit(void)
1613e12c5d1SDavid du Colombier {
1623e12c5d1SDavid du Colombier 	Rune *p;
1633e12c5d1SDavid du Colombier 	int i;
1643e12c5d1SDavid du Colombier 	long from, to, lastc, high;
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier 	lastc = 0;
1673e12c5d1SDavid du Colombier 	high = 0;
1683e12c5d1SDavid du Colombier 	while ((from = canon(&pfrom)) >= 0)
1693e12c5d1SDavid du Colombier 		if (from > high) high = from;
1703e12c5d1SDavid du Colombier 	Prewind(&pfrom);
1713e12c5d1SDavid du Colombier 	if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
1729b004bddSDavid du Colombier 		sysfatal("no memory");
1733e12c5d1SDavid du Colombier 	for (i = 0; i <= high; i++)
1743e12c5d1SDavid du Colombier 		p[i] = i;
1753e12c5d1SDavid du Colombier 	while ((from = canon(&pfrom)) >= 0) {
1763e12c5d1SDavid du Colombier 		if ((to = canon(&pto)) < 0)
1773e12c5d1SDavid du Colombier 			to = lastc;
1783e12c5d1SDavid du Colombier 		else lastc = to;
1793e12c5d1SDavid du Colombier 		if (BITSET(f,from) && p[from] != to)
1809b004bddSDavid du Colombier 			sysfatal("ambiguous translation");
1813e12c5d1SDavid du Colombier 		SETBIT(f,from);
1823e12c5d1SDavid du Colombier 		p[from] = to;
1833e12c5d1SDavid du Colombier 		SETBIT(t,to);
1843e12c5d1SDavid du Colombier 	}
1853e12c5d1SDavid du Colombier 	while ((to = canon(&pto)) >= 0) {
1863e12c5d1SDavid du Colombier 		SETBIT(t,to);
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier 	if (sflag){
1893e12c5d1SDavid du Colombier 		lastc = 0x10000;
190219b2ee8SDavid du Colombier 		while (readrune(0, &from) > 0) {
191219b2ee8SDavid du Colombier 			if (from <= high)
192219b2ee8SDavid du Colombier 				from = p[from];
1933e12c5d1SDavid du Colombier 			if (from != lastc || !BITSET(t,from)) {
1943e12c5d1SDavid du Colombier 				lastc = from;
195219b2ee8SDavid du Colombier 				writerune(1, (Rune) from);
1963e12c5d1SDavid du Colombier 			}
1973e12c5d1SDavid du Colombier 		}
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	} else {
200219b2ee8SDavid du Colombier 		while (readrune(0, &from) > 0) {
201219b2ee8SDavid du Colombier 			if (from <= high)
202219b2ee8SDavid du Colombier 				from = p[from];
203219b2ee8SDavid du Colombier 			writerune(1, (Rune) from);
204219b2ee8SDavid du Colombier 		}
205219b2ee8SDavid du Colombier 	}
206219b2ee8SDavid du Colombier 	wflush(1);
207219b2ee8SDavid du Colombier }
208219b2ee8SDavid du Colombier 
209219b2ee8SDavid du Colombier int
readrune(int fd,long * rp)210219b2ee8SDavid du Colombier readrune(int fd, long *rp)
211219b2ee8SDavid du Colombier {
212219b2ee8SDavid du Colombier 	Rune r;
213219b2ee8SDavid du Colombier 	int j;
214219b2ee8SDavid du Colombier 	static int i, n;
215219b2ee8SDavid du Colombier 	static char buf[4096];
216219b2ee8SDavid du Colombier 
217219b2ee8SDavid du Colombier 	j = i;
218219b2ee8SDavid du Colombier 	for (;;) {
219219b2ee8SDavid du Colombier 		if (i >= n) {
220219b2ee8SDavid du Colombier 			wflush(1);
221219b2ee8SDavid du Colombier 			if (j != i)
222219b2ee8SDavid du Colombier 				memcpy(buf, buf+j, n-j);
223219b2ee8SDavid du Colombier 			i = n-j;
224219b2ee8SDavid du Colombier 			n = read(fd, &buf[i], sizeof(buf)-i);
225219b2ee8SDavid du Colombier 			if (n < 0)
2269b004bddSDavid du Colombier 				sysfatal("read error: %r");
227219b2ee8SDavid du Colombier 			if (n == 0)
228219b2ee8SDavid du Colombier 				return 0;
229219b2ee8SDavid du Colombier 			j = 0;
230219b2ee8SDavid du Colombier 			n += i;
231219b2ee8SDavid du Colombier 		}
232219b2ee8SDavid du Colombier 		i++;
233219b2ee8SDavid du Colombier 		if (fullrune(&buf[j], i-j))
234219b2ee8SDavid du Colombier 			break;
235219b2ee8SDavid du Colombier 	}
236219b2ee8SDavid du Colombier 	chartorune(&r, &buf[j]);
237219b2ee8SDavid du Colombier 	*rp = r;
238219b2ee8SDavid du Colombier 	return 1;
239219b2ee8SDavid du Colombier }
240219b2ee8SDavid du Colombier 
241219b2ee8SDavid du Colombier void
writerune(int fd,Rune r)242219b2ee8SDavid du Colombier writerune(int fd, Rune r)
243219b2ee8SDavid du Colombier {
244219b2ee8SDavid du Colombier 	char buf[UTFmax];
245219b2ee8SDavid du Colombier 	int n;
246219b2ee8SDavid du Colombier 
247219b2ee8SDavid du Colombier 	if (!wptr)
248219b2ee8SDavid du Colombier 		wptr = wbuf;
249219b2ee8SDavid du Colombier 	n = runetochar(buf, (Rune*)&r);
250219b2ee8SDavid du Colombier 	if (wptr+n >= wbuf+sizeof(wbuf))
251219b2ee8SDavid du Colombier 		wflush(fd);
252219b2ee8SDavid du Colombier 	memcpy(wptr, buf, n);
253219b2ee8SDavid du Colombier 	wptr += n;
254219b2ee8SDavid du Colombier }
255219b2ee8SDavid du Colombier 
256219b2ee8SDavid du Colombier void
wflush(int fd)257219b2ee8SDavid du Colombier wflush(int fd)
258219b2ee8SDavid du Colombier {
259219b2ee8SDavid du Colombier 	if (wptr && wptr > wbuf)
260219b2ee8SDavid du Colombier 		if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf)
2619b004bddSDavid du Colombier 			sysfatal("write error: %r");
262219b2ee8SDavid du Colombier 	wptr = wbuf;
2633e12c5d1SDavid du Colombier }
2643e12c5d1SDavid du Colombier 
2653e12c5d1SDavid du Colombier char *
getrune(char * s,Rune * rp)2663e12c5d1SDavid du Colombier getrune(char *s, Rune *rp)
2673e12c5d1SDavid du Colombier {
2683e12c5d1SDavid du Colombier 	Rune r;
2693e12c5d1SDavid du Colombier 	char *save;
2703e12c5d1SDavid du Colombier 	int i, n;
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	s += chartorune(rp, s);
2733e12c5d1SDavid du Colombier 	if((r = *rp) == '\\' && *s){
2743e12c5d1SDavid du Colombier 		n = 0;
2753e12c5d1SDavid du Colombier 		if (*s == 'x') {
2763e12c5d1SDavid du Colombier 			s++;
2773e12c5d1SDavid du Colombier 			for (i = 0; i < 4; i++) {
2783e12c5d1SDavid du Colombier 				save = s;
2793e12c5d1SDavid du Colombier 				s += chartorune(&r, s);
2803e12c5d1SDavid du Colombier 				if ('0' <= r && r <= '9')
2813e12c5d1SDavid du Colombier 					n = 16*n + r - '0';
2823e12c5d1SDavid du Colombier 				else if ('a' <= r && r <= 'f')
2833e12c5d1SDavid du Colombier 					n = 16*n + r - 'a' + 10;
2843e12c5d1SDavid du Colombier 				else if ('A' <= r && r <= 'F')
2853e12c5d1SDavid du Colombier 					n = 16*n + r - 'A' + 10;
2863e12c5d1SDavid du Colombier 				else {
2873e12c5d1SDavid du Colombier 					if (i == 0)
2883e12c5d1SDavid du Colombier 						*rp = 'x';
2893e12c5d1SDavid du Colombier 					else *rp = n;
2903e12c5d1SDavid du Colombier 					return save;
2913e12c5d1SDavid du Colombier 				}
2923e12c5d1SDavid du Colombier 			}
2933e12c5d1SDavid du Colombier 		} else {
2943e12c5d1SDavid du Colombier 			for(i = 0; i < 3; i++) {
2953e12c5d1SDavid du Colombier 				save = s;
2963e12c5d1SDavid du Colombier 				s += chartorune(&r, s);
2973e12c5d1SDavid du Colombier 				if('0' <= r && r <= '7')
2983e12c5d1SDavid du Colombier 					n = 8*n + r - '0';
2993e12c5d1SDavid du Colombier 				else {
3003e12c5d1SDavid du Colombier 					if (i == 0)
3013e12c5d1SDavid du Colombier 					{
3023e12c5d1SDavid du Colombier 						*rp = r;
3033e12c5d1SDavid du Colombier 						return s;
3043e12c5d1SDavid du Colombier 					}
3053e12c5d1SDavid du Colombier 					*rp = n;
3063e12c5d1SDavid du Colombier 					return save;
3073e12c5d1SDavid du Colombier 				}
3083e12c5d1SDavid du Colombier 			}
3093e12c5d1SDavid du Colombier 			if(n > 0377)
3109b004bddSDavid du Colombier 				sysfatal("character > 0377");
3113e12c5d1SDavid du Colombier 		}
3123e12c5d1SDavid du Colombier 		*rp = n;
3133e12c5d1SDavid du Colombier 	}
3143e12c5d1SDavid du Colombier 	return s;
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier long
canon(Pcb * p)3183e12c5d1SDavid du Colombier canon(Pcb *p)
3193e12c5d1SDavid du Colombier {
3203e12c5d1SDavid du Colombier 	Rune r;
3213e12c5d1SDavid du Colombier 
3223e12c5d1SDavid du Colombier 	if (p->final >= 0) {
3233e12c5d1SDavid du Colombier 		if (p->last < p->final)
3243e12c5d1SDavid du Colombier 			return ++p->last;
3253e12c5d1SDavid du Colombier 		p->final = -1;
3263e12c5d1SDavid du Colombier 	}
3273e12c5d1SDavid du Colombier 	if (*p->current == '\0')
3283e12c5d1SDavid du Colombier 		return -1;
3293e12c5d1SDavid du Colombier 	if(*p->current == '-' && p->last >= 0 && p->current[1]){
3303e12c5d1SDavid du Colombier 		p->current = getrune(p->current+1, &r);
3313e12c5d1SDavid du Colombier 		if (r < p->last)
3329b004bddSDavid du Colombier 			sysfatal("invalid range specification");
3333e12c5d1SDavid du Colombier 		if (r > p->last) {
3343e12c5d1SDavid du Colombier 			p->final = r;
3353e12c5d1SDavid du Colombier 			return ++p->last;
3363e12c5d1SDavid du Colombier 		}
3373e12c5d1SDavid du Colombier 	}
3383e12c5d1SDavid du Colombier 	p->current = getrune(p->current, &r);
3393e12c5d1SDavid du Colombier 	p->last = r;
3403e12c5d1SDavid du Colombier 	return p->last;
3413e12c5d1SDavid du Colombier }
3423e12c5d1SDavid du Colombier 
3433e12c5d1SDavid du Colombier void
Pinit(Pcb * p,char * cp)3443e12c5d1SDavid du Colombier Pinit(Pcb *p, char *cp)
3453e12c5d1SDavid du Colombier {
3463e12c5d1SDavid du Colombier 	p->current = p->base = cp;
3473e12c5d1SDavid du Colombier 	p->last = p->final = -1;
3483e12c5d1SDavid du Colombier }
3493e12c5d1SDavid du Colombier void
Prewind(Pcb * p)3503e12c5d1SDavid du Colombier Prewind(Pcb *p)
3513e12c5d1SDavid du Colombier {
3523e12c5d1SDavid du Colombier 	p->current = p->base;
3533e12c5d1SDavid du Colombier 	p->last = p->final = -1;
3543e12c5d1SDavid du Colombier }
355