make all the commands agnostic about Rune width. Reference: /n/sources/patch/applied/rune2-cmds Date: Wed Apr 24 01:14:03 CES 2013 Signed-off-by: geoff@plan9.bell-labs.com --- /sys/src/cmd/rc/rc.h Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/rc/rc.h Wed Apr 24 01:13:14 2013 @@ -128,13 +128,12 @@ * GLOBGLOB matches GLOB */ #define GLOB ((char)0x01) + /* - * onebyte(c), twobyte(c), threebyte(c) - * Is c the first character of a one- two- or three-byte utf sequence? + * onebyte(c) + * Is c the first character of a one-byte utf sequence? */ #define onebyte(c) ((c&0x80)==0x00) -#define twobyte(c) ((c&0xe0)==0xc0) -#define threebyte(c) ((c&0xf0)==0xe0) char **argp; char **args; --- /sys/src/cmd/rc/glob.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/rc/glob.c Wed Apr 24 01:13:14 2013 @@ -111,25 +111,22 @@ else globsort(globv, svglobv); } + /* * Do p and q point at equal utf codes */ - int equtf(uchar *p, uchar *q) { + Rune pr, qr; if(*p!=*q) return 0; - if(twobyte(*p)) return p[1]==q[1]; - if(threebyte(*p)){ - if(p[1]!=q[1]) - return 0; - if(p[1]=='\0') - return 1; /* broken code at end of string! */ - return p[2]==q[2]; - } - return 1; + + chartorune(&pr, (char*)p); + chartorune(&qr, (char*)q); + return pr == qr; } + /* * Return a pointer to the next utf code in the string, * not jumping past nuls in broken utf codes! @@ -138,10 +135,10 @@ uchar* nextutf(uchar *p) { - if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; - if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; - return p+1; + Rune dummy; + return p + chartorune(&dummy, (char*)p); } + /* * Convert the utf code at *p to a unicode value */ @@ -149,14 +146,12 @@ int unicode(uchar *p) { - int u = *p; + Rune r; - if(twobyte(u)) - return ((u&0x1f)<<6)|(p[1]&0x3f); - if(threebyte(u)) - return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); - return u; + chartorune(&r, (char*)p); + return r; } + /* * Does the string s match the pattern p * . and .. are only matched by patterns starting with . --- /sys/src/cmd/rc/lex.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/rc/lex.c Wed Apr 24 01:13:14 2013 @@ -166,15 +166,25 @@ char* addutf(char *p, int c) { - p = addtok(p, c); - if(twobyte(c)) /* 2-byte escape */ - return addtok(p, advance()); - if(threebyte(c)){ /* 3-byte escape */ + uchar b, m; + int i; + + p = addtok(p, c); /* 1-byte UTF runes are special */ + if(onebyte(c)) + return p; + + m = 0xc0; + b = 0x80; + for(i=1; i < UTFmax; i++){ + if((c&m) == b) + break; p = addtok(p, advance()); - return addtok(p, advance()); + b = m; + m = (m >> 1)|0x80; } return p; } + int lastdol; /* was the last token read '$' or '$#' or '"'? */ int lastword; /* was the last token read a word or compound word terminator? */ --- /sys/src/cmd/unicode.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/unicode.c Wed Apr 24 01:13:14 2013 @@ -51,13 +51,13 @@ return "bad range"; } min = strtoul(q, &q, 16); - if(min<0 || min>0xFFFF || *q!='-') + if(min<0 || min>Runemax || *q!='-') goto err; q++; if(strchr(hex, *q) == 0) goto err; max = strtoul(q, &q, 16); - if(max<0 || max>0xFFFF || maxRunemax || max0xFFFF || *q!=0) + if(m<0 || m>Runemax || *q!=0) goto err; Bprint(&bout, "%C", m); if(!text) --- /sys/src/cmd/cc/cc.h Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/cc.h Wed Apr 24 01:13:14 2013 @@ -20,6 +20,8 @@ typedef struct Init Init; typedef struct Bits Bits; +typedef Rune TRune; /* target system type */ + #define NHUNK 50000L #define BUFSIZ 8192 #define NSYMB 1500 @@ -51,7 +53,7 @@ double fconst; /* fp constant */ vlong vconst; /* non fp const */ char* cstring; /* character string */ - ushort* rstring; /* rune string */ + TRune* rstring; /* rune string */ Sym* sym; Type* type; @@ -336,6 +338,9 @@ TFILE, TOLD, NALLTYPES, + + /* adapt size of Rune to target system's size */ + TRUNE = sizeof(TRune)==4? TUINT: TUSHORT, }; enum { @@ -740,7 +745,7 @@ void gextern(Sym*, Node*, long, long); void ginit(void); long outstring(char*, long); -long outlstring(ushort*, long); +long outlstring(TRune*, long); void xcom(Node*); long exreg(Type*); long align(long, Type*, int); --- /sys/src/cmd/cc/cc.y Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/cc.y Wed Apr 24 01:13:14 2013 @@ -855,9 +855,9 @@ LLSTRING { $$ = new(OLSTRING, Z, Z); - $$->type = typ(TARRAY, types[TUSHORT]); - $$->type->width = $1.l + sizeof(ushort); - $$->rstring = (ushort*)$1.s; + $$->type = typ(TARRAY, types[TRUNE]); + $$->type->width = $1.l + sizeof(TRune); + $$->rstring = (TRune*)$1.s; $$->sym = symstring; $$->etype = TARRAY; $$->class = CSTATIC; @@ -867,16 +867,16 @@ char *s; int n; - n = $1->type->width - sizeof(ushort); + n = $1->type->width - sizeof(TRune); s = alloc(n+$2.l+MAXALIGN); memcpy(s, $1->rstring, n); memcpy(s+n, $2.s, $2.l); - *(ushort*)(s+n+$2.l) = 0; + *(TRune*)(s+n+$2.l) = 0; $$ = $1; $$->type->width += $2.l; - $$->rstring = (ushort*)s; + $$->rstring = (TRune*)s; } zelist: --- /sys/src/cmd/cc/com.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/com.c Wed Apr 24 01:13:14 2013 @@ -67,6 +67,7 @@ Node *l, *r; Type *t; int o; + static TRune zer; if(n == Z) { diag(Z, "Z in tcom"); @@ -633,10 +634,10 @@ break; case OLSTRING: - if(n->type->link != types[TUSHORT]) { + if(n->type->link != types[TRUNE]) { o = outstring(0, 0); while(o & 3) { - outlstring(L"", sizeof(ushort)); + outlstring(&zer, sizeof(TRune)); o = outlstring(0, 0); } } --- /sys/src/cmd/cc/dcl.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/dcl.c Wed Apr 24 01:13:14 2013 @@ -232,7 +232,7 @@ a->cstring++; } if(a->op == OLSTRING) { - b->vconst = convvtox(*a->rstring, TUSHORT); + b->vconst = convvtox(*a->rstring, TRUNE); a->rstring++; } a->type->width -= b->type->width; --- /sys/src/cmd/cc/lex.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/lex.c Wed Apr 24 01:13:14 2013 @@ -80,7 +80,8 @@ case 'I': p = ARGF(); - setinclude(p); + if(p) + setinclude(p); break; } ARGEND if(argc < 1 && outfile == 0) { @@ -465,7 +466,7 @@ yyerror("missing '"); peekc = c1; } - yylval.vval = convvtox(c, TUSHORT); + yylval.vval = convvtox(c, TRUNE); return LUCONST; } if(c == '"') { @@ -539,15 +540,15 @@ c = escchar('"', 1, 0); if(c == EOF) break; - cp = allocn(cp, c1, sizeof(ushort)); - *(ushort*)(cp + c1) = c; - c1 += sizeof(ushort); + cp = allocn(cp, c1, sizeof(TRune)); + *(TRune*)(cp + c1) = c; + c1 += sizeof(TRune); } yylval.sval.l = c1; do { - cp = allocn(cp, c1, sizeof(ushort)); - *(ushort*)(cp + c1) = 0; - c1 += sizeof(ushort); + cp = allocn(cp, c1, sizeof(TRune)); + *(TRune*)(cp + c1) = 0; + c1 += sizeof(TRune); } while(c1 & MAXALIGN); yylval.sval.s = cp; return LLSTRING; @@ -1025,7 +1026,7 @@ } else c = GETC(); for(;;) { - if(!isspace(c)) + if(c >= Runeself || !isspace(c)) return c; if(c == '\n') { lineno++; --- /sys/src/cmd/cc/pswt.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/pswt.c Wed Apr 24 01:13:14 2013 @@ -132,28 +132,29 @@ } long -outlstring(ushort *s, long n) +outlstring(TRune *s, long n) { - char buf[2]; - int c; + char buf[sizeof(TRune)]; + uint c; + int i; long r; if(suppress) return nstring; - while(nstring & 1) + while(nstring & (sizeof(TRune)-1)) outstring("", 1); r = nstring; while(n > 0) { c = *s++; if(align(0, types[TCHAR], Aarg1)) { - buf[0] = c>>8; - buf[1] = c; + for(i = 0; i < sizeof(TRune); i++) + buf[i] = c>>(8*(sizeof(TRune) - i - 1)); } else { - buf[0] = c; - buf[1] = c>>8; + for(i = 0; i < sizeof(TRune); i++) + buf[i] = c>>(8*i); } - outstring(buf, 2); - n -= sizeof(ushort); + outstring(buf, sizeof(TRune)); + n -= sizeof(TRune); } return r; } --- /sys/src/cmd/cc/sub.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/cc/sub.c Wed Apr 24 01:13:14 2013 @@ -85,7 +85,10 @@ break; case OLSTRING: - print(" \"%S\"", n->rstring); + if(sizeof(TRune) == sizeof(Rune)) + print(" \"%S\"", (Rune*)n->rstring); + else + print(" \"...\""); i = 0; break; --- /sys/src/cmd/ed.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/ed.c Wed Apr 24 01:13:14 2013 @@ -15,7 +15,7 @@ ESIZE = 256, /* max size of reg exp */ GBSIZE = 256, /* max size of global command */ MAXSUB = 9, /* max number of sub reg exp */ - ESCFLG = 0xFFFF, /* escape Rune - user defined code */ + ESCFLG = Runemax, /* escape Rune - user defined code */ EOF = -1, }; @@ -54,7 +54,7 @@ int peekc; int pflag; int rescuing; -Rune rhsbuf[LBSIZE/2]; +Rune rhsbuf[LBSIZE/sizeof(Rune)]; char savedfile[FNSIZE]; jmp_buf savej; int subnewa; @@ -735,7 +735,7 @@ if(c == 0) continue; *p++ = c; - if(p >= &linebuf[LBSIZE-2]) + if(p >= &linebuf[LBSIZE-sizeof(Rune)]) error(Q); } } @@ -988,11 +988,12 @@ lp = linebuf; bp = getblock(tl, OREAD); nl = nleft; - tl &= ~((BLKSIZE/2) - 1); + tl &= ~((BLKSIZE/sizeof(Rune)) - 1); while(*lp++ = *bp++) { nl -= sizeof(Rune); if(nl == 0) { - bp = getblock(tl += BLKSIZE/2, OREAD); + tl += BLKSIZE/sizeof(Rune); + bp = getblock(tl, OREAD); nl = nleft; } } @@ -1010,7 +1011,7 @@ tl = tline; bp = getblock(tl, OWRITE); nl = nleft; - tl &= ~((BLKSIZE/2)-1); + tl &= ~((BLKSIZE/sizeof(Rune))-1); while(*bp = *lp++) { if(*bp++ == '\n') { bp[-1] = 0; @@ -1019,7 +1020,7 @@ } nl -= sizeof(Rune); if(nl == 0) { - tl += BLKSIZE/2; + tl += BLKSIZE/sizeof(Rune); bp = getblock(tl, OWRITE); nl = nleft; } @@ -1046,8 +1047,9 @@ static uchar ibuff[BLKSIZE]; static uchar obuff[BLKSIZE]; - bno = atl / (BLKSIZE/2); - off = (atl<<1) & (BLKSIZE-1) & ~03; + bno = atl / (BLKSIZE/sizeof(Rune)); + /* &~3 so the ptr is aligned to 4 (?) */ + off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~3; if(bno >= NBLK) { lastc = '\n'; error(T); @@ -1160,7 +1162,7 @@ for(a1=addr1; a1<=addr2; a1++) { lp = getline(*a1); while(*gp = *lp++) - if(gp++ >= &genbuf[LBSIZE-2]) + if(gp++ >= &genbuf[LBSIZE-sizeof(Rune)]) error(Q); } lp = linebuf; @@ -1238,7 +1240,7 @@ if(c == '\\') { c = getchr(); *p++ = ESCFLG; - if(p >= &rhsbuf[LBSIZE/2]) + if(p >= &rhsbuf[LBSIZE/sizeof(Rune)]) error(Q); } else if(c == '\n' && (!globp || !globp[0])) { @@ -1249,7 +1251,7 @@ if(c == seof) break; *p++ = c; - if(p >= &rhsbuf[LBSIZE/2]) + if(p >= &rhsbuf[LBSIZE/sizeof(Rune)]) error(Q); } *p = 0; --- /sys/src/cmd/freq.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/freq.c Wed Apr 24 01:13:14 2013 @@ -2,7 +2,7 @@ #include #include -uvlong count[1<<16]; +uvlong count[Runemax+1]; Biobuf bout; void usage(void); --- /sys/src/cmd/htmlroff/char.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/htmlroff/char.c Wed Apr 24 01:13:14 2013 @@ -16,6 +16,12 @@ if(r == '\n') return L("\n"); + if(((uint)r&~0xFFFF) != 0){ + /* The cache must grow a lot to handle them */ + fprint(2, "%s: can't handle rune '%C'\n", argv0, r); + return L("?"); + } + if(tcscache[r>>8] && tcscache[r>>8][r&0xFF]) return tcscache[r>>8][r&0xFF]; @@ -59,7 +65,7 @@ typedef struct Trtab Trtab; struct Trtab { - char t[3]; + char t[UTFmax]; Rune r; }; --- /sys/src/cmd/sed.c Wed Apr 24 01:13:14 2013 +++ /sys/src/cmd/sed.c Wed Apr 24 01:13:14 2013 @@ -623,7 +623,7 @@ while ((r = *cp++) != '\0') { if(r == '\\') { if (rhs < end) - *rhs++ = 0xFFFF; + *rhs++ = Runemax; else return 0; r = *cp++; @@ -1050,7 +1050,7 @@ sp = place(sp, loc1, loc2); continue; } - if (c == 0xFFFF && (c = *rp++) >= '1' && c < MAXSUB + '0') { + if (c == Runemax && (c = *rp++) >= '1' && c < MAXSUB + '0') { n = c-'0'; if (subexp[n].rsp && subexp[n].rep) { sp = place(sp, subexp[n].rsp, subexp[n].rep); --- /sys/src/cmd/tr.c Wed Apr 24 01:13:15 2013 +++ /sys/src/cmd/tr.c Wed Apr 24 01:13:15 2013 @@ -15,10 +15,8 @@ #define CLEARBIT(a,c) ((a)[(c)/8] &= ~bits[(c)&07]) #define BITSET(a,c) ((a)[(c)/8] & bits[(c)&07]) -#define MAXRUNE 0xFFFF - -uchar f[(MAXRUNE+1)/8]; -uchar t[(MAXRUNE+1)/8]; +uchar f[(Runemax+1)/8]; +uchar t[(Runemax+1)/8]; char wbuf[4096]; char *wptr; --- /sys/src/cmd/unix/drawterm/libc/rune.c Wed Apr 24 01:13:15 2013 +++ /sys/src/cmd/unix/drawterm/libc/rune.c Wed Apr 24 01:13:15 2013 @@ -14,21 +14,26 @@ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ - Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ - Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ - Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */ + Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ Maskx = (1< T2 Tx + * 00080-007FF => T2 Tx */ c1 = *(uchar*)(str+1) ^ Tx; if(c1 & Testx) @@ -60,20 +65,42 @@ /* * three character sequence - * 0800-FFFF => T3 Tx Tx + * 00800-0FFFF => T3 Tx Tx */ c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) goto bad; if(c < T4) { l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; if(l <= Rune2) goto bad; + if (SurrogateMin <= l && l <= SurrogateMax) + goto bad; *rune = l; return 3; } /* + * four character sequence + * 10000-10FFFF => T4 Tx Tx Tx + */ + if(UTFmax >= 4) { + c3 = *(uchar*)(str+3) ^ Tx; + if(c3 & Testx) + goto bad; + if(c < T5) { + l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; + if(l <= Rune3) + goto bad; + if(l > Runemax) + goto bad; + *rune = l; + return 4; + } + } + + /* * bad decoding */ bad: @@ -105,15 +132,37 @@ str[1] = Tx | (c & Maskx); return 2; } + /* + * If the Rune is out of range or a surrogate half, convert it to the error rune. + * Do this test here because the error rune encodes to three bytes. + * Doing it earlier would duplicate work, since an out of range + * Rune wouldn't have fit in one or two bytes. + */ + if (c > Runemax) + c = Runeerror; + if (SurrogateMin <= c && c <= SurrogateMax) + c = Runeerror; /* * three character sequence * 0800-FFFF => T3 Tx Tx */ - str[0] = T3 | (c >> 2*Bitx); - str[1] = Tx | ((c >> 1*Bitx) & Maskx); - str[2] = Tx | (c & Maskx); - return 3; + if (c <= Rune3) { + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; + } + + /* + * four character sequence (21-bit value) + * 10000-1FFFFF => T4 Tx Tx Tx + */ + str[0] = T4 | (c >> 3*Bitx); + str[1] = Tx | ((c >> 2*Bitx) & Maskx); + str[2] = Tx | ((c >> 1*Bitx) & Maskx); + str[3] = Tx | (c & Maskx); + return 4; } int @@ -136,11 +185,12 @@ c = *r++; if(c <= Rune1) nb++; - else - if(c <= Rune2) + else if(c <= Rune2) nb += 2; + else if(c <= Rune3) + nb += 3; else - nb += 3; + nb += 4; } return nb; } @@ -149,14 +199,14 @@ fullrune(char *str, int n) { int c; - - if(n > 0) { - c = *(uchar*)str; - if(c < Tx) - return 1; - if(n > 1) - if(c < T3 || n > 2) - return 1; - } - return 0; + if(n <= 0) + return 0; + c = *(uchar*)str; + if(c < Tx) + return 1; + if(c < T3) + return n >= 2; + if(c < T4) + return n >= 3; + return n >= 4; } --- /sys/src/cmd/unix/u9fs/rune.c Wed Apr 24 01:13:15 2013 +++ /sys/src/cmd/unix/u9fs/rune.c Wed Apr 24 01:13:15 2013 @@ -14,21 +14,27 @@ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */ + Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ - Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ - Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ - Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ Maskx = (1< T2 Tx + * 00080-007FF => T2 Tx */ c1 = *(uchar*)(str+1) ^ Tx; if(c1 & Testx) @@ -60,20 +66,42 @@ /* * three character sequence - * 0800-FFFF => T3 Tx Tx + * 00800-0FFFF => T3 Tx Tx */ c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) goto bad; if(c < T4) { l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; if(l <= Rune2) goto bad; + if (SurrogateMin <= l && l <= SurrogateMax) + goto bad; *rune = l; return 3; } /* + * four character sequence + * 10000-10FFFF => T4 Tx Tx Tx + */ + if(UTFmax >= 4) { + c3 = *(uchar*)(str+3) ^ Tx; + if(c3 & Testx) + goto bad; + if(c < T5) { + l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; + if(l <= Rune3) + goto bad; + if(l > Runemax) + goto bad; + *rune = l; + return 4; + } + } + + /* * bad decoding */ bad: @@ -105,15 +133,37 @@ str[1] = Tx | (c & Maskx); return 2; } + /* + * If the Rune is out of range or a surrogate half, convert it to the error rune. + * Do this test here because the error rune encodes to three bytes. + * Doing it earlier would duplicate work, since an out of range + * Rune wouldn't have fit in one or two bytes. + */ + if (c > Runemax) + c = Runeerror; + if (SurrogateMin <= c && c <= SurrogateMax) + c = Runeerror; /* * three character sequence * 0800-FFFF => T3 Tx Tx */ - str[0] = T3 | (c >> 2*Bitx); - str[1] = Tx | ((c >> 1*Bitx) & Maskx); - str[2] = Tx | (c & Maskx); - return 3; + if (c <= Rune3) { + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; + } + + /* + * four character sequence (21-bit value) + * 10000-1FFFFF => T4 Tx Tx Tx + */ + str[0] = T4 | (c >> 3*Bitx); + str[1] = Tx | ((c >> 2*Bitx) & Maskx); + str[2] = Tx | ((c >> 1*Bitx) & Maskx); + str[3] = Tx | (c & Maskx); + return 4; } int --- /sys/src/cmd/vnc/devcons.c Wed Apr 24 01:13:15 2013 +++ /sys/src/cmd/vnc/devcons.c Wed Apr 24 01:13:15 2013 @@ -158,7 +158,7 @@ kbdputc(int ch) { int n; - char buf[3]; + char buf[UTFmax]; Rune r; r = ch;