]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tcs/utf.c
ip/ipconfig: use ewrite() to enable routing command for sendra
[plan9front.git] / sys / src / cmd / tcs / utf.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        <bio.h>
4 #include        "hdr.h"
5
6 /*
7         the our_* routines are implementations for the corresponding library
8         routines. for a while, i tried to actually name them wctomb etc
9         but stopped that after i found a system which made wchar_t an
10         unsigned char.
11 */
12
13 int our_wctomb(char *s, unsigned long wc);
14 int our_mbtowc(unsigned long *p, char *s, unsigned n);
15 int runetoisoutf(char *str, Rune *rune);
16 int fullisorune(char *str, int n);
17 int isochartorune(Rune *rune, char *str);
18
19 void
20 utf_in(int fd, long *, struct convert *out)
21 {
22         char buf[N];
23         int i, j, c, n, tot;
24         unsigned long l;
25
26         tot = 0;
27         while((n = read(fd, buf+tot, N-tot)) >= 0){
28                 tot += n;
29                 for(i=j=0; i<=tot-UTFmax || (i<tot && (n==0 || fullrune(buf+i, tot-i))); ){
30                         c = our_mbtowc(&l, buf+i, tot-i);
31                         if(c == -1){
32                                 if(squawk)
33                                         warn("bad UTF sequence near byte %ld in input", ninput+i);
34                                 if(clean){
35                                         i++;
36                                         continue;
37                                 }
38                                 nerrors++;
39                                 l = Runeerror;
40                                 c = 1;
41                         }
42                         runes[j++] = l;
43                         i += c;
44                 }
45                 OUT(out, runes, j);
46                 tot -= i;
47                 ninput += i;
48                 if(tot)
49                         memmove(buf, buf+i, tot);
50                 if(n == 0)
51                         break;
52         }
53         OUT(out, runes, 0);
54 }
55
56 void
57 utf_out(Rune *base, int n, long *)
58 {
59         char *p;
60         Rune *r;
61
62         nrunes += n;
63         for(r = base, p = obuf; n-- > 0; r++){
64                 p += our_wctomb(p, *r);
65         }
66         noutput += p-obuf;
67         if(p > obuf)
68                 write(1, obuf, p-obuf);
69 }
70
71 void
72 isoutf_in(int fd, long *, struct convert *out)
73 {
74         char buf[N];
75         int i, j, c, n, tot;
76
77         tot = 0;
78         while((n = read(fd, buf+tot, N-tot)) >= 0){
79                 tot += n;
80                 for(i=j=0; i<tot; ){
81                         if(!fullisorune(buf+i, tot-i))
82                                 break;
83                         c = isochartorune(&runes[j], buf+i);
84                         if(runes[j] == Runeerror){
85                                 if(squawk)
86                                         warn("bad UTF sequence near byte %ld in input", ninput+i);
87                                 if(clean){
88                                         i++;
89                                         continue;
90                                 }
91                                 nerrors++;
92                         }
93                         j++;
94                         i += c;
95                 }
96                 OUT(out, runes, j);
97                 tot -= i;
98                 ninput += i;
99                 if(tot)
100                         memmove(buf, buf+i, tot);
101                 if(n == 0)
102                         break;
103         }
104         OUT(out, runes, 0);
105 }
106
107 void
108 isoutf_out(Rune *base, int n, long *)
109 {
110         char *p;
111         Rune *r;
112
113         nrunes += n;
114         for(r = base, p = obuf; n-- > 0; r++)
115                 p += runetoisoutf(p, r);
116         noutput += p-obuf;
117         if(p > obuf)
118                 write(1, obuf, p-obuf);
119 }
120
121
122 enum
123 {
124         Char1   = Runeself,     Rune1   = Runeself,
125         Char21  = 0xA1,         Rune21  = 0x0100,
126         Char22  = 0xF6,         Rune22  = 0x4016,
127         Char3   = 0xFC,         Rune3   = 0x10000,      /* really 0x38E2E */
128         Esc     = 0xBE,         Bad     = Runeerror
129 };
130
131 static  uchar   U[256];
132 static  uchar   T[256];
133
134 static
135 void
136 mktable(void)
137 {
138         int i, u;
139
140         for(i=0; i<256; i++) {
141                 u = i + (0x5E - 0xA0);
142                 if(i < 0xA0)
143                         u = i + (0xDF - 0x7F);
144                 if(i < 0x7F)
145                         u = i + (0x00 - 0x21);
146                 if(i < 0x21)
147                         u = i + (0xBE - 0x00);
148                 U[i] = u;
149                 T[u] = i;
150         }
151 }
152
153 int
154 isochartorune(Rune *rune, char *str)
155 {
156         int c, c1, c2;
157         long l;
158
159         if(U[0] == 0)
160                 mktable();
161
162         /*
163          * one character sequence
164          *      00000-0009F => 00-9F
165          */
166         c = *(uchar*)str;
167         if(c < Char1) {
168                 *rune = c;
169                 return 1;
170         }
171
172         /*
173          * two character sequence
174          *      000A0-000FF => A0; A0-FF
175          */
176         c1 = *(uchar*)(str+1);
177         if(c < Char21) {
178                 if(c1 >= Rune1 && c1 < Rune21) {
179                         *rune = c1;
180                         return 2;
181                 }
182                 goto bad;
183         }
184
185         /*
186          * two character sequence
187          *      00100-04015 => A1-F5; 21-7E/A0-FF
188          */
189         c1 = U[c1];
190         if(c1 >= Esc)
191                 goto bad;
192         if(c < Char22) {
193                 *rune =  (c-Char21)*Esc + c1 + Rune21;
194                 return 2;
195         }
196
197         /*
198          * three character sequence
199          *      04016-38E2D => A6-FB; 21-7E/A0-FF
200          */
201         c2 = U[*(uchar*)(str+2)];
202         if(c2 >= Esc)
203                 goto bad;
204         if(c < Char3) {
205                 l = (c-Char22)*Esc*Esc + c1*Esc + c2 + Rune22;
206                 if(l >= Rune3)
207                         goto bad;
208                 *rune = l;
209                 return 3;
210         }
211
212         /*
213          * bad decoding
214          */
215 bad:
216         *rune = Bad;
217         return 1;
218 }
219
220 int
221 runetoisoutf(char *str, Rune *rune)
222 {
223         long c;
224
225         if(T[0] == 0)
226                 mktable();
227
228         /*
229          * one character sequence
230          *      00000-0009F => 00-9F
231          */
232         c = *rune;
233         if(c < Rune1) {
234                 str[0] = c;
235                 return 1;
236         }
237
238         /*
239          * two character sequence
240          *      000A0-000FF => A0; A0-FF
241          */
242         if(c < Rune21) {
243                 str[0] = Char1;
244                 str[1] = c;
245                 return 2;
246         }
247
248         /*
249          * two character sequence
250          *      00100-04015 => A1-F5; 21-7E/A0-FF
251          */
252         if(c < Rune22) {
253                 c -= Rune21;
254                 str[0] = c/Esc + Char21;
255                 str[1] = T[c%Esc];
256                 return 2;
257         }
258
259         /*
260          * three character sequence
261          *      04016-38E2D => A6-FB; 21-7E/A0-FF
262          */
263         c -= Rune22;
264         str[0] = c/(Esc*Esc) + Char22;
265         str[1] = T[c/Esc%Esc];
266         str[2] = T[c%Esc];
267         return 3;
268 }
269
270 int
271 fullisorune(char *str, int n)
272 {
273         int c;
274
275         if(n > 0) {
276                 c = *(uchar*)str;
277                 if(c < Char1)
278                         return 1;
279                 if(n > 1)
280                         if(c < Char22 || n > 2)
281                                 return 1;
282         }
283         return 0;
284 }
285
286 enum
287 {
288         T1      = 0x00,
289         Tx      = 0x80,
290         T2      = 0xC0,
291         T3      = 0xE0,
292         T4      = 0xF0,
293         T5      = 0xF8,
294         T6      = 0xFC,
295
296         Bit1    = 7,
297         Bitx    = 6,
298         Bit2    = 5,
299         Bit3    = 4,
300         Bit4    = 3,
301         Bit5    = 2,
302         Bit6    = 2,
303
304         Mask1   = (1<<Bit1)-1,
305         Maskx   = (1<<Bitx)-1,
306         Mask2   = (1<<Bit2)-1,
307         Mask3   = (1<<Bit3)-1,
308         Mask4   = (1<<Bit4)-1,
309         Mask5   = (1<<Bit5)-1,
310         Mask6   = (1<<Bit6)-1,
311
312         Wchar1  = (1UL<<Bit1)-1,
313         Wchar2  = (1UL<<(Bit2+Bitx))-1,
314         Wchar3  = (1UL<<(Bit3+2*Bitx))-1,
315         Wchar4  = (1UL<<(Bit4+3*Bitx))-1,
316         Wchar5  = (1UL<<(Bit5+4*Bitx))-1,
317 };
318
319 int
320 our_wctomb(char *s, unsigned long wc)
321 {
322         if(s == 0)
323                 return 0;               /* no shift states */
324         if(wc & ~Wchar2) {
325                 if(wc & ~Wchar4) {
326                         if(wc & ~Wchar5) {
327                                 /* 6 bytes */
328                                 s[0] = T6 | ((wc >> 5*Bitx) & Mask6);
329                                 s[1] = Tx | ((wc >> 4*Bitx) & Maskx);
330                                 s[2] = Tx | ((wc >> 3*Bitx) & Maskx);
331                                 s[3] = Tx | ((wc >> 2*Bitx) & Maskx);
332                                 s[4] = Tx | ((wc >> 1*Bitx) & Maskx);
333                                 s[5] = Tx |  (wc & Maskx);
334                                 return 6;
335                         }
336                         /* 5 bytes */
337                         s[0] = T5 |  (wc >> 4*Bitx);
338                         s[1] = Tx | ((wc >> 3*Bitx) & Maskx);
339                         s[2] = Tx | ((wc >> 2*Bitx) & Maskx);
340                         s[3] = Tx | ((wc >> 1*Bitx) & Maskx);
341                         s[4] = Tx |  (wc & Maskx);
342                         return 5;
343                 }
344                 if(wc & ~Wchar3) {
345                         /* 4 bytes */
346                         s[0] = T4 |  (wc >> 3*Bitx);
347                         s[1] = Tx | ((wc >> 2*Bitx) & Maskx);
348                         s[2] = Tx | ((wc >> 1*Bitx) & Maskx);
349                         s[3] = Tx |  (wc & Maskx);
350                         return 4;
351                 }
352                 /* 3 bytes */
353                 s[0] = T3 |  (wc >> 2*Bitx);
354                 s[1] = Tx | ((wc >> 1*Bitx) & Maskx);
355                 s[2] = Tx |  (wc & Maskx);
356                 return 3;
357         }
358         if(wc & ~Wchar1) {
359                 /* 2 bytes */
360                 s[0] = T2 | (wc >> 1*Bitx);
361                 s[1] = Tx | (wc & Maskx);
362                 return 2;
363         }
364         /* 1 byte */
365         s[0] = T1 | wc;
366         return 1;
367 }
368
369 int
370 our_mbtowc(unsigned long *p, char *s, unsigned n)
371 {
372         uchar *us;
373         int c0, c1, c2, c3, c4, c5;
374         unsigned long wc;
375
376         if(s == 0)
377                 return 0;               /* no shift states */
378
379         if(n < 1)
380                 goto bad;
381         us = (uchar*)s;
382         c0 = us[0];
383         if(c0 >= T3) {
384                 if(n < 3)
385                         goto bad;
386                 c1 = us[1] ^ Tx;
387                 c2 = us[2] ^ Tx;
388                 if((c1|c2) & T2)
389                         goto bad;
390                 if(c0 >= T5) {
391                         if(n < 5)
392                                 goto bad;
393                         c3 = us[3] ^ Tx;
394                         c4 = us[4] ^ Tx;
395                         if((c3|c4) & T2)
396                                 goto bad;
397                         if(c0 >= T6) {
398                                 /* 6 bytes */
399                                 if(n < 6)
400                                         goto bad;
401                                 c5 = us[5] ^ Tx;
402                                 if(c5 & T2)
403                                         goto bad;
404                                 wc = ((((((((((c0 & Mask6) << Bitx) |
405                                         c1) << Bitx) | c2) << Bitx) |
406                                         c3) << Bitx) | c4) << Bitx) | c5;
407                                 if(wc <= Wchar5)
408                                         goto bad;
409                                 *p = wc;
410                                 return 6;
411                         }
412                         /* 5 bytes */
413                         wc = ((((((((c0 & Mask5) << Bitx) |
414                                 c1) << Bitx) | c2) << Bitx) |
415                                 c3) << Bitx) | c4;
416                         if(wc <= Wchar4)
417                                 goto bad;
418                         *p = wc;
419                         return 5;
420                 }
421                 if(c0 >= T4) {
422                         /* 4 bytes */
423                         if(n < 4)
424                                 goto bad;
425                         c3 = us[3] ^ Tx;
426                         if(c3 & T2)
427                                 goto bad;
428                         wc = ((((((c0 & Mask4) << Bitx) |
429                                 c1) << Bitx) | c2) << Bitx) |
430                                 c3;
431                         if(wc <= Wchar3)
432                                 goto bad;
433                         *p = wc;
434                         return 4;
435                 }
436                 /* 3 bytes */
437                 wc = ((((c0 & Mask3) << Bitx) |
438                         c1) << Bitx) | c2;
439                 if(wc <= Wchar2)
440                         goto bad;
441                 *p = wc;
442                 return 3;
443         }
444         if(c0 >= T2) {
445                 /* 2 bytes */
446                 if(n < 2)
447                         goto bad;
448                 c1 = us[1] ^ Tx;
449                 if(c1 & T2)
450                         goto bad;
451                 wc = ((c0 & Mask2) << Bitx) |
452                         c1;
453                 if(wc <= Wchar1)
454                         goto bad;
455                 *p = wc;
456                 return 2;
457         }
458         /* 1 byte */
459         if(c0 >= Tx)
460                 goto bad;
461         *p = c0;
462         return 1;
463
464 bad:
465         return -1;
466 }