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