xref: /plan9/sys/src/cmd/tcs/utf.c (revision 2cba34c722cc5343f414835ed47b457dd3b026ca)
1219b2ee8SDavid du Colombier #ifdef PLAN9
23e12c5d1SDavid du Colombier #include	<u.h>
33e12c5d1SDavid du Colombier #include	<libc.h>
43e12c5d1SDavid du Colombier #include	<bio.h>
5219b2ee8SDavid du Colombier #else
6219b2ee8SDavid du Colombier #include	<sys/types.h>
7219b2ee8SDavid du Colombier #include	<stdio.h>
8219b2ee8SDavid du Colombier #include	<stdlib.h>
9219b2ee8SDavid du Colombier #include	<string.h>
10219b2ee8SDavid du Colombier #include	<unistd.h>
11219b2ee8SDavid du Colombier #include	<errno.h>
12219b2ee8SDavid du Colombier #include	"plan9.h"
13219b2ee8SDavid du Colombier #endif
143e12c5d1SDavid du Colombier #include	"hdr.h"
153e12c5d1SDavid du Colombier 
16219b2ee8SDavid du Colombier /*
17219b2ee8SDavid du Colombier 	the our_* routines are implementations for the corresponding library
18219b2ee8SDavid du Colombier 	routines. for a while, i tried to actually name them wctomb etc
19219b2ee8SDavid du Colombier 	but stopped that after i found a system which made wchar_t an
20219b2ee8SDavid du Colombier 	unsigned char.
21219b2ee8SDavid du Colombier */
22219b2ee8SDavid du Colombier 
23219b2ee8SDavid du Colombier int our_wctomb(char *s, unsigned long wc);
24219b2ee8SDavid du Colombier int our_mbtowc(unsigned long *p, char *s, unsigned n);
253e12c5d1SDavid du Colombier int runetoisoutf(char *str, Rune *rune);
263e12c5d1SDavid du Colombier int fullisorune(char *str, int n);
273e12c5d1SDavid du Colombier int isochartorune(Rune *rune, char *str);
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier void
utf_in(int fd,long * notused,struct convert * out)303e12c5d1SDavid du Colombier utf_in(int fd, long *notused, struct convert *out)
313e12c5d1SDavid du Colombier {
32ef9eff0bSDavid du Colombier 	char buf[N];
33ef9eff0bSDavid du Colombier 	int i, j, c, n, tot;
34ef9eff0bSDavid du Colombier 	ulong l;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier 	USED(notused);
37ef9eff0bSDavid du Colombier 	tot = 0;
38ef9eff0bSDavid du Colombier 	while((n = read(fd, buf+tot, N-tot)) >= 0){
39ef9eff0bSDavid du Colombier 		tot += n;
40*2cba34c7SDavid du Colombier 		for(i=j=0; i<=tot-UTFmax || (i<tot && (n==0 || fullrune(buf+i, tot-i))); ){
41ef9eff0bSDavid du Colombier 			c = our_mbtowc(&l, buf+i, tot-i);
42312a1df1SDavid du Colombier 			if(c == -1){
433e12c5d1SDavid du Colombier 				if(squawk)
44ef9eff0bSDavid du Colombier 					EPR "%s: bad UTF sequence near byte %ld in input\n", argv0, ninput+i);
453c2ddefeSDavid du Colombier 				if(clean){
463c2ddefeSDavid du Colombier 					i++;
473e12c5d1SDavid du Colombier 					continue;
483c2ddefeSDavid du Colombier 				}
493e12c5d1SDavid du Colombier 				nerrors++;
503e12c5d1SDavid du Colombier 				l = Runeerror;
51312a1df1SDavid du Colombier 				c = 1;
523e12c5d1SDavid du Colombier 			}
53ef9eff0bSDavid du Colombier 			runes[j++] = l;
54ef9eff0bSDavid du Colombier 			i += c;
553e12c5d1SDavid du Colombier 		}
56ef9eff0bSDavid du Colombier 		OUT(out, runes, j);
57ef9eff0bSDavid du Colombier 		tot -= i;
58ef9eff0bSDavid du Colombier 		ninput += i;
59ef9eff0bSDavid du Colombier 		if(tot)
60ef9eff0bSDavid du Colombier 			memmove(buf, buf+i, tot);
61ef9eff0bSDavid du Colombier 		if(n == 0)
62ef9eff0bSDavid du Colombier 			break;
63ef9eff0bSDavid du Colombier 	}
64ec46fab0SDavid du Colombier 	OUT(out, runes, 0);
653e12c5d1SDavid du Colombier }
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier void
utf_out(Rune * base,int n,long * notused)683e12c5d1SDavid du Colombier utf_out(Rune *base, int n, long *notused)
693e12c5d1SDavid du Colombier {
703e12c5d1SDavid du Colombier 	char *p;
713e12c5d1SDavid du Colombier 	Rune *r;
723e12c5d1SDavid du Colombier 
733e12c5d1SDavid du Colombier 	USED(notused);
743e12c5d1SDavid du Colombier 	nrunes += n;
75219b2ee8SDavid du Colombier 	for(r = base, p = obuf; n-- > 0; r++){
76219b2ee8SDavid du Colombier 		p += our_wctomb(p, *r);
77219b2ee8SDavid du Colombier 	}
783e12c5d1SDavid du Colombier 	noutput += p-obuf;
793e12c5d1SDavid du Colombier 	write(1, obuf, p-obuf);
803e12c5d1SDavid du Colombier }
813e12c5d1SDavid du Colombier 
823e12c5d1SDavid du Colombier void
isoutf_in(int fd,long * notused,struct convert * out)833e12c5d1SDavid du Colombier isoutf_in(int fd, long *notused, struct convert *out)
843e12c5d1SDavid du Colombier {
85ef9eff0bSDavid du Colombier 	char buf[N];
86ef9eff0bSDavid du Colombier 	int i, j, c, n, tot;
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier 	USED(notused);
89ef9eff0bSDavid du Colombier 	tot = 0;
90ef9eff0bSDavid du Colombier 	while((n = read(fd, buf+tot, N-tot)) >= 0){
91ef9eff0bSDavid du Colombier 		tot += n;
92ef9eff0bSDavid du Colombier 		for(i=j=0; i<tot; ){
93ef9eff0bSDavid du Colombier 			if(!fullisorune(buf+i, tot-i))
94ef9eff0bSDavid du Colombier 				break;
95ef9eff0bSDavid du Colombier 			c = isochartorune(&runes[j], buf+i);
963c2ddefeSDavid du Colombier 			if(runes[j] == Runeerror && c == 1){
973e12c5d1SDavid du Colombier 				if(squawk)
98ef9eff0bSDavid du Colombier 					EPR "%s: bad UTF sequence near byte %ld in input\n", argv0, ninput+i);
993c2ddefeSDavid du Colombier 				if(clean){
1003c2ddefeSDavid du Colombier 					i++;
1013e12c5d1SDavid du Colombier 					continue;
1023c2ddefeSDavid du Colombier 				}
1033e12c5d1SDavid du Colombier 				nerrors++;
1043e12c5d1SDavid du Colombier 			}
105ef9eff0bSDavid du Colombier 			j++;
106ef9eff0bSDavid du Colombier 			i += c;
1073e12c5d1SDavid du Colombier 		}
108ef9eff0bSDavid du Colombier 		OUT(out, runes, j);
109ef9eff0bSDavid du Colombier 		tot -= i;
110ef9eff0bSDavid du Colombier 		ninput += i;
111ef9eff0bSDavid du Colombier 		if(tot)
112ef9eff0bSDavid du Colombier 			memmove(buf, buf+i, tot);
113ef9eff0bSDavid du Colombier 		if(n == 0)
114ef9eff0bSDavid du Colombier 			break;
115ef9eff0bSDavid du Colombier 	}
116ec46fab0SDavid du Colombier 	OUT(out, runes, 0);
1173e12c5d1SDavid du Colombier }
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier void
isoutf_out(Rune * base,int n,long * notused)1203e12c5d1SDavid du Colombier isoutf_out(Rune *base, int n, long *notused)
1213e12c5d1SDavid du Colombier {
1223e12c5d1SDavid du Colombier 	char *p;
1233e12c5d1SDavid du Colombier 	Rune *r;
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier 	USED(notused);
1263e12c5d1SDavid du Colombier 	nrunes += n;
1273e12c5d1SDavid du Colombier 	for(r = base, p = obuf; n-- > 0; r++)
1283e12c5d1SDavid du Colombier 		p += runetoisoutf(p, r);
1293e12c5d1SDavid du Colombier 	noutput += p-obuf;
1303e12c5d1SDavid du Colombier 	write(1, obuf, p-obuf);
1313e12c5d1SDavid du Colombier }
1323e12c5d1SDavid du Colombier 
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier enum
1353e12c5d1SDavid du Colombier {
1363e12c5d1SDavid du Colombier 	Char1	= Runeself,	Rune1	= Runeself,
1373e12c5d1SDavid du Colombier 	Char21	= 0xA1,		Rune21	= 0x0100,
1383e12c5d1SDavid du Colombier 	Char22	= 0xF6,		Rune22	= 0x4016,
1393e12c5d1SDavid du Colombier 	Char3	= 0xFC,		Rune3	= 0x10000,	/* really 0x38E2E */
140219b2ee8SDavid du Colombier 	Esc	= 0xBE,		Bad	= Runeerror
1413e12c5d1SDavid du Colombier };
1423e12c5d1SDavid du Colombier 
1433e12c5d1SDavid du Colombier static	uchar	U[256];
1443e12c5d1SDavid du Colombier static	uchar	T[256];
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier static
1473e12c5d1SDavid du Colombier void
mktable(void)1483e12c5d1SDavid du Colombier mktable(void)
1493e12c5d1SDavid du Colombier {
1503e12c5d1SDavid du Colombier 	int i, u;
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	for(i=0; i<256; i++) {
1533e12c5d1SDavid du Colombier 		u = i + (0x5E - 0xA0);
1543e12c5d1SDavid du Colombier 		if(i < 0xA0)
1553e12c5d1SDavid du Colombier 			u = i + (0xDF - 0x7F);
1563e12c5d1SDavid du Colombier 		if(i < 0x7F)
1573e12c5d1SDavid du Colombier 			u = i + (0x00 - 0x21);
1583e12c5d1SDavid du Colombier 		if(i < 0x21)
1593e12c5d1SDavid du Colombier 			u = i + (0xBE - 0x00);
1603e12c5d1SDavid du Colombier 		U[i] = u;
1613e12c5d1SDavid du Colombier 		T[u] = i;
1623e12c5d1SDavid du Colombier 	}
1633e12c5d1SDavid du Colombier }
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier int
isochartorune(Rune * rune,char * str)1663e12c5d1SDavid du Colombier isochartorune(Rune *rune, char *str)
1673e12c5d1SDavid du Colombier {
1683e12c5d1SDavid du Colombier 	int c, c1, c2;
1693e12c5d1SDavid du Colombier 	long l;
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier 	if(U[0] == 0)
1723e12c5d1SDavid du Colombier 		mktable();
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	/*
1753e12c5d1SDavid du Colombier 	 * one character sequence
1763e12c5d1SDavid du Colombier 	 *	00000-0009F => 00-9F
1773e12c5d1SDavid du Colombier 	 */
1783e12c5d1SDavid du Colombier 	c = *(uchar*)str;
1793e12c5d1SDavid du Colombier 	if(c < Char1) {
1803e12c5d1SDavid du Colombier 		*rune = c;
1813e12c5d1SDavid du Colombier 		return 1;
1823e12c5d1SDavid du Colombier 	}
1833e12c5d1SDavid du Colombier 
1843e12c5d1SDavid du Colombier 	/*
1853e12c5d1SDavid du Colombier 	 * two character sequence
1863e12c5d1SDavid du Colombier 	 *	000A0-000FF => A0; A0-FF
1873e12c5d1SDavid du Colombier 	 */
1883e12c5d1SDavid du Colombier 	c1 = *(uchar*)(str+1);
1893e12c5d1SDavid du Colombier 	if(c < Char21) {
1903e12c5d1SDavid du Colombier 		if(c1 >= Rune1 && c1 < Rune21) {
1913e12c5d1SDavid du Colombier 			*rune = c1;
1923e12c5d1SDavid du Colombier 			return 2;
1933e12c5d1SDavid du Colombier 		}
1943e12c5d1SDavid du Colombier 		goto bad;
1953e12c5d1SDavid du Colombier 	}
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	/*
1983e12c5d1SDavid du Colombier 	 * two character sequence
1993e12c5d1SDavid du Colombier 	 *	00100-04015 => A1-F5; 21-7E/A0-FF
2003e12c5d1SDavid du Colombier 	 */
2013e12c5d1SDavid du Colombier 	c1 = U[c1];
2023e12c5d1SDavid du Colombier 	if(c1 >= Esc)
2033e12c5d1SDavid du Colombier 		goto bad;
2043e12c5d1SDavid du Colombier 	if(c < Char22) {
2053e12c5d1SDavid du Colombier 		*rune =  (c-Char21)*Esc + c1 + Rune21;
2063e12c5d1SDavid du Colombier 		return 2;
2073e12c5d1SDavid du Colombier 	}
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	/*
2103e12c5d1SDavid du Colombier 	 * three character sequence
2113e12c5d1SDavid du Colombier 	 *	04016-38E2D => A6-FB; 21-7E/A0-FF
2123e12c5d1SDavid du Colombier 	 */
2133e12c5d1SDavid du Colombier 	c2 = U[*(uchar*)(str+2)];
2143e12c5d1SDavid du Colombier 	if(c2 >= Esc)
2153e12c5d1SDavid du Colombier 		goto bad;
2163e12c5d1SDavid du Colombier 	if(c < Char3) {
2173e12c5d1SDavid du Colombier 		l = (c-Char22)*Esc*Esc + c1*Esc + c2 + Rune22;
2183e12c5d1SDavid du Colombier 		if(l >= Rune3)
2193e12c5d1SDavid du Colombier 			goto bad;
2203e12c5d1SDavid du Colombier 		*rune = l;
2213e12c5d1SDavid du Colombier 		return 3;
2223e12c5d1SDavid du Colombier 	}
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier 	/*
2253e12c5d1SDavid du Colombier 	 * bad decoding
2263e12c5d1SDavid du Colombier 	 */
2273e12c5d1SDavid du Colombier bad:
2283e12c5d1SDavid du Colombier 	*rune = Bad;
2293e12c5d1SDavid du Colombier 	return 1;
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier int
runetoisoutf(char * str,Rune * rune)2333e12c5d1SDavid du Colombier runetoisoutf(char *str, Rune *rune)
2343e12c5d1SDavid du Colombier {
2353e12c5d1SDavid du Colombier 	long c;
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier 	if(T[0] == 0)
2383e12c5d1SDavid du Colombier 		mktable();
2393e12c5d1SDavid du Colombier 
2403e12c5d1SDavid du Colombier 	/*
2413e12c5d1SDavid du Colombier 	 * one character sequence
2423e12c5d1SDavid du Colombier 	 *	00000-0009F => 00-9F
2433e12c5d1SDavid du Colombier 	 */
2443e12c5d1SDavid du Colombier 	c = *rune;
2453e12c5d1SDavid du Colombier 	if(c < Rune1) {
2463e12c5d1SDavid du Colombier 		str[0] = c;
2473e12c5d1SDavid du Colombier 		return 1;
2483e12c5d1SDavid du Colombier 	}
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	/*
2513e12c5d1SDavid du Colombier 	 * two character sequence
2523e12c5d1SDavid du Colombier 	 *	000A0-000FF => A0; A0-FF
2533e12c5d1SDavid du Colombier 	 */
2543e12c5d1SDavid du Colombier 	if(c < Rune21) {
2553e12c5d1SDavid du Colombier 		str[0] = Char1;
2563e12c5d1SDavid du Colombier 		str[1] = c;
2573e12c5d1SDavid du Colombier 		return 2;
2583e12c5d1SDavid du Colombier 	}
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 	/*
2613e12c5d1SDavid du Colombier 	 * two character sequence
2623e12c5d1SDavid du Colombier 	 *	00100-04015 => A1-F5; 21-7E/A0-FF
2633e12c5d1SDavid du Colombier 	 */
2643e12c5d1SDavid du Colombier 	if(c < Rune22) {
2653e12c5d1SDavid du Colombier 		c -= Rune21;
2663e12c5d1SDavid du Colombier 		str[0] = c/Esc + Char21;
2673e12c5d1SDavid du Colombier 		str[1] = T[c%Esc];
2683e12c5d1SDavid du Colombier 		return 2;
2693e12c5d1SDavid du Colombier 	}
2703e12c5d1SDavid du Colombier 
2713e12c5d1SDavid du Colombier 	/*
2723e12c5d1SDavid du Colombier 	 * three character sequence
2733e12c5d1SDavid du Colombier 	 *	04016-38E2D => A6-FB; 21-7E/A0-FF
2743e12c5d1SDavid du Colombier 	 */
2753e12c5d1SDavid du Colombier 	c -= Rune22;
2763e12c5d1SDavid du Colombier 	str[0] = c/(Esc*Esc) + Char22;
2773e12c5d1SDavid du Colombier 	str[1] = T[c/Esc%Esc];
2783e12c5d1SDavid du Colombier 	str[2] = T[c%Esc];
2793e12c5d1SDavid du Colombier 	return 3;
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier int
fullisorune(char * str,int n)2833e12c5d1SDavid du Colombier fullisorune(char *str, int n)
2843e12c5d1SDavid du Colombier {
2853e12c5d1SDavid du Colombier 	int c;
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier 	if(n > 0) {
2883e12c5d1SDavid du Colombier 		c = *(uchar*)str;
2893e12c5d1SDavid du Colombier 		if(c < Char1)
2903e12c5d1SDavid du Colombier 			return 1;
2913e12c5d1SDavid du Colombier 		if(n > 1)
2923e12c5d1SDavid du Colombier 			if(c < Char22 || n > 2)
2933e12c5d1SDavid du Colombier 				return 1;
2943e12c5d1SDavid du Colombier 	}
2953e12c5d1SDavid du Colombier 	return 0;
2963e12c5d1SDavid du Colombier }
2973e12c5d1SDavid du Colombier 
298219b2ee8SDavid du Colombier #ifdef PLAN9
2993e12c5d1SDavid du Colombier int	errno;
300219b2ee8SDavid du Colombier #endif
3013e12c5d1SDavid du Colombier 
3023e12c5d1SDavid du Colombier enum
3033e12c5d1SDavid du Colombier {
3043e12c5d1SDavid du Colombier 	T1	= 0x00,
3053e12c5d1SDavid du Colombier 	Tx	= 0x80,
3063e12c5d1SDavid du Colombier 	T2	= 0xC0,
3073e12c5d1SDavid du Colombier 	T3	= 0xE0,
3083e12c5d1SDavid du Colombier 	T4	= 0xF0,
3093e12c5d1SDavid du Colombier 	T5	= 0xF8,
3103e12c5d1SDavid du Colombier 	T6	= 0xFC,
3113e12c5d1SDavid du Colombier 
3123e12c5d1SDavid du Colombier 	Bit1	= 7,
3133e12c5d1SDavid du Colombier 	Bitx	= 6,
3143e12c5d1SDavid du Colombier 	Bit2	= 5,
3153e12c5d1SDavid du Colombier 	Bit3	= 4,
3163e12c5d1SDavid du Colombier 	Bit4	= 3,
3173e12c5d1SDavid du Colombier 	Bit5	= 2,
3183e12c5d1SDavid du Colombier 	Bit6	= 2,
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	Mask1	= (1<<Bit1)-1,
3213e12c5d1SDavid du Colombier 	Maskx	= (1<<Bitx)-1,
3223e12c5d1SDavid du Colombier 	Mask2	= (1<<Bit2)-1,
3233e12c5d1SDavid du Colombier 	Mask3	= (1<<Bit3)-1,
3243e12c5d1SDavid du Colombier 	Mask4	= (1<<Bit4)-1,
3253e12c5d1SDavid du Colombier 	Mask5	= (1<<Bit5)-1,
3263e12c5d1SDavid du Colombier 	Mask6	= (1<<Bit6)-1,
3273e12c5d1SDavid du Colombier 
328219b2ee8SDavid du Colombier 	Wchar1	= (1UL<<Bit1)-1,
329219b2ee8SDavid du Colombier 	Wchar2	= (1UL<<(Bit2+Bitx))-1,
330219b2ee8SDavid du Colombier 	Wchar3	= (1UL<<(Bit3+2*Bitx))-1,
331219b2ee8SDavid du Colombier 	Wchar4	= (1UL<<(Bit4+3*Bitx))-1,
3323c2ddefeSDavid du Colombier 	Wchar5	= (1UL<<(Bit5+4*Bitx))-1,
3333e12c5d1SDavid du Colombier 
334219b2ee8SDavid du Colombier #ifndef	EILSEQ
3353c2ddefeSDavid du Colombier 	EILSEQ	= 123,
3363c2ddefeSDavid du Colombier #endif /* EILSEQ */
3373e12c5d1SDavid du Colombier };
3383e12c5d1SDavid du Colombier 
3393e12c5d1SDavid du Colombier int
our_wctomb(char * s,unsigned long wc)340219b2ee8SDavid du Colombier our_wctomb(char *s, unsigned long wc)
3413e12c5d1SDavid du Colombier {
3423e12c5d1SDavid du Colombier 	if(s == 0)
3433e12c5d1SDavid du Colombier 		return 0;		/* no shift states */
3443e12c5d1SDavid du Colombier 	if(wc & ~Wchar2) {
3453e12c5d1SDavid du Colombier 		if(wc & ~Wchar4) {
3463e12c5d1SDavid du Colombier 			if(wc & ~Wchar5) {
3473e12c5d1SDavid du Colombier 				/* 6 bytes */
3483e12c5d1SDavid du Colombier 				s[0] = T6 | ((wc >> 5*Bitx) & Mask6);
3493e12c5d1SDavid du Colombier 				s[1] = Tx | ((wc >> 4*Bitx) & Maskx);
3503e12c5d1SDavid du Colombier 				s[2] = Tx | ((wc >> 3*Bitx) & Maskx);
3513e12c5d1SDavid du Colombier 				s[3] = Tx | ((wc >> 2*Bitx) & Maskx);
3523e12c5d1SDavid du Colombier 				s[4] = Tx | ((wc >> 1*Bitx) & Maskx);
3533e12c5d1SDavid du Colombier 				s[5] = Tx |  (wc & Maskx);
3543e12c5d1SDavid du Colombier 				return 6;
3553e12c5d1SDavid du Colombier 			}
3563e12c5d1SDavid du Colombier 			/* 5 bytes */
3573e12c5d1SDavid du Colombier 			s[0] = T5 |  (wc >> 4*Bitx);
3583e12c5d1SDavid du Colombier 			s[1] = Tx | ((wc >> 3*Bitx) & Maskx);
3593e12c5d1SDavid du Colombier 			s[2] = Tx | ((wc >> 2*Bitx) & Maskx);
3603e12c5d1SDavid du Colombier 			s[3] = Tx | ((wc >> 1*Bitx) & Maskx);
3613e12c5d1SDavid du Colombier 			s[4] = Tx |  (wc & Maskx);
3623e12c5d1SDavid du Colombier 			return 5;
3633e12c5d1SDavid du Colombier 		}
3643e12c5d1SDavid du Colombier 		if(wc & ~Wchar3) {
3653e12c5d1SDavid du Colombier 			/* 4 bytes */
3663e12c5d1SDavid du Colombier 			s[0] = T4 |  (wc >> 3*Bitx);
3673e12c5d1SDavid du Colombier 			s[1] = Tx | ((wc >> 2*Bitx) & Maskx);
3683e12c5d1SDavid du Colombier 			s[2] = Tx | ((wc >> 1*Bitx) & Maskx);
3693e12c5d1SDavid du Colombier 			s[3] = Tx |  (wc & Maskx);
3703e12c5d1SDavid du Colombier 			return 4;
3713e12c5d1SDavid du Colombier 		}
3723e12c5d1SDavid du Colombier 		/* 3 bytes */
3733e12c5d1SDavid du Colombier 		s[0] = T3 |  (wc >> 2*Bitx);
3743e12c5d1SDavid du Colombier 		s[1] = Tx | ((wc >> 1*Bitx) & Maskx);
3753e12c5d1SDavid du Colombier 		s[2] = Tx |  (wc & Maskx);
3763e12c5d1SDavid du Colombier 		return 3;
3773e12c5d1SDavid du Colombier 	}
3783e12c5d1SDavid du Colombier 	if(wc & ~Wchar1) {
3793e12c5d1SDavid du Colombier 		/* 2 bytes */
3803e12c5d1SDavid du Colombier 		s[0] = T2 | (wc >> 1*Bitx);
3813e12c5d1SDavid du Colombier 		s[1] = Tx | (wc & Maskx);
3823e12c5d1SDavid du Colombier 		return 2;
3833e12c5d1SDavid du Colombier 	}
3843e12c5d1SDavid du Colombier 	/* 1 byte */
3853e12c5d1SDavid du Colombier 	s[0] = T1 | wc;
3863e12c5d1SDavid du Colombier 	return 1;
3873e12c5d1SDavid du Colombier }
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier int
our_mbtowc(unsigned long * p,char * s,unsigned n)390219b2ee8SDavid du Colombier our_mbtowc(unsigned long *p, char *s, unsigned n)
3913e12c5d1SDavid du Colombier {
3923e12c5d1SDavid du Colombier 	uchar *us;
3933e12c5d1SDavid du Colombier 	int c0, c1, c2, c3, c4, c5;
394219b2ee8SDavid du Colombier 	unsigned long wc;
3953e12c5d1SDavid du Colombier 
3963e12c5d1SDavid du Colombier 	if(s == 0)
3973e12c5d1SDavid du Colombier 		return 0;		/* no shift states */
3983e12c5d1SDavid du Colombier 
3993e12c5d1SDavid du Colombier 	if(n < 1)
4003c2ddefeSDavid du Colombier 		goto bad;
4013e12c5d1SDavid du Colombier 	us = (uchar*)s;
4023e12c5d1SDavid du Colombier 	c0 = us[0];
4033e12c5d1SDavid du Colombier 	if(c0 >= T3) {
4043e12c5d1SDavid du Colombier 		if(n < 3)
4053c2ddefeSDavid du Colombier 			goto bad;
4063e12c5d1SDavid du Colombier 		c1 = us[1] ^ Tx;
4073e12c5d1SDavid du Colombier 		c2 = us[2] ^ Tx;
4083e12c5d1SDavid du Colombier 		if((c1|c2) & T2)
4093e12c5d1SDavid du Colombier 			goto bad;
4103e12c5d1SDavid du Colombier 		if(c0 >= T5) {
4113e12c5d1SDavid du Colombier 			if(n < 5)
4123c2ddefeSDavid du Colombier 				goto bad;
4133e12c5d1SDavid du Colombier 			c3 = us[3] ^ Tx;
4143e12c5d1SDavid du Colombier 			c4 = us[4] ^ Tx;
4153e12c5d1SDavid du Colombier 			if((c3|c4) & T2)
4163e12c5d1SDavid du Colombier 				goto bad;
4173e12c5d1SDavid du Colombier 			if(c0 >= T6) {
4183e12c5d1SDavid du Colombier 				/* 6 bytes */
4193e12c5d1SDavid du Colombier 				if(n < 6)
4203c2ddefeSDavid du Colombier 					goto bad;
4213e12c5d1SDavid du Colombier 				c5 = us[5] ^ Tx;
4223e12c5d1SDavid du Colombier 				if(c5 & T2)
4233e12c5d1SDavid du Colombier 					goto bad;
4243e12c5d1SDavid du Colombier 				wc = ((((((((((c0 & Mask6) << Bitx) |
4253e12c5d1SDavid du Colombier 					c1) << Bitx) | c2) << Bitx) |
4263e12c5d1SDavid du Colombier 					c3) << Bitx) | c4) << Bitx) | c5;
4273e12c5d1SDavid du Colombier 				if(wc <= Wchar5)
4283e12c5d1SDavid du Colombier 					goto bad;
4293e12c5d1SDavid du Colombier 				*p = wc;
4303e12c5d1SDavid du Colombier 				return 6;
4313e12c5d1SDavid du Colombier 			}
4323e12c5d1SDavid du Colombier 			/* 5 bytes */
4333e12c5d1SDavid du Colombier 			wc = ((((((((c0 & Mask5) << Bitx) |
4343e12c5d1SDavid du Colombier 				c1) << Bitx) | c2) << Bitx) |
4353e12c5d1SDavid du Colombier 				c3) << Bitx) | c4;
4363e12c5d1SDavid du Colombier 			if(wc <= Wchar4)
4373e12c5d1SDavid du Colombier 				goto bad;
4383e12c5d1SDavid du Colombier 			*p = wc;
4393e12c5d1SDavid du Colombier 			return 5;
4403e12c5d1SDavid du Colombier 		}
4413e12c5d1SDavid du Colombier 		if(c0 >= T4) {
4423e12c5d1SDavid du Colombier 			/* 4 bytes */
4433e12c5d1SDavid du Colombier 			if(n < 4)
4443c2ddefeSDavid du Colombier 				goto bad;
4453e12c5d1SDavid du Colombier 			c3 = us[3] ^ Tx;
4463e12c5d1SDavid du Colombier 			if(c3 & T2)
4473e12c5d1SDavid du Colombier 				goto bad;
4483e12c5d1SDavid du Colombier 			wc = ((((((c0 & Mask4) << Bitx) |
4493e12c5d1SDavid du Colombier 				c1) << Bitx) | c2) << Bitx) |
4503e12c5d1SDavid du Colombier 				c3;
4513e12c5d1SDavid du Colombier 			if(wc <= Wchar3)
4523e12c5d1SDavid du Colombier 				goto bad;
4533e12c5d1SDavid du Colombier 			*p = wc;
4543e12c5d1SDavid du Colombier 			return 4;
4553e12c5d1SDavid du Colombier 		}
4563e12c5d1SDavid du Colombier 		/* 3 bytes */
4573e12c5d1SDavid du Colombier 		wc = ((((c0 & Mask3) << Bitx) |
4583e12c5d1SDavid du Colombier 			c1) << Bitx) | c2;
4593e12c5d1SDavid du Colombier 		if(wc <= Wchar2)
4603e12c5d1SDavid du Colombier 			goto bad;
4613e12c5d1SDavid du Colombier 		*p = wc;
4623e12c5d1SDavid du Colombier 		return 3;
4633e12c5d1SDavid du Colombier 	}
4643e12c5d1SDavid du Colombier 	if(c0 >= T2) {
4653e12c5d1SDavid du Colombier 		/* 2 bytes */
4663e12c5d1SDavid du Colombier 		if(n < 2)
4673c2ddefeSDavid du Colombier 			goto bad;
4683e12c5d1SDavid du Colombier 		c1 = us[1] ^ Tx;
4693e12c5d1SDavid du Colombier 		if(c1 & T2)
4703e12c5d1SDavid du Colombier 			goto bad;
4713e12c5d1SDavid du Colombier 		wc = ((c0 & Mask2) << Bitx) |
4723e12c5d1SDavid du Colombier 			c1;
4733e12c5d1SDavid du Colombier 		if(wc <= Wchar1)
4743e12c5d1SDavid du Colombier 			goto bad;
4753e12c5d1SDavid du Colombier 		*p = wc;
4763e12c5d1SDavid du Colombier 		return 2;
4773e12c5d1SDavid du Colombier 	}
4783e12c5d1SDavid du Colombier 	/* 1 byte */
4793e12c5d1SDavid du Colombier 	if(c0 >= Tx)
4803e12c5d1SDavid du Colombier 		goto bad;
4813e12c5d1SDavid du Colombier 	*p = c0;
4823e12c5d1SDavid du Colombier 	return 1;
4833e12c5d1SDavid du Colombier 
4843e12c5d1SDavid du Colombier bad:
4853e12c5d1SDavid du Colombier 	errno = EILSEQ;
4863e12c5d1SDavid du Colombier 	return -1;
4873e12c5d1SDavid du Colombier }
488