tr.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tr.c (6008B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 | |
4 typedef struct PCB /* Control block controlling specification par… | |
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 } |