1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
//go:build unix
package term
import (
"time"
)
type byteReaderWithTimeout interface {
// ReadByteWithTimeout reads a single byte with a timeout. A negative
// timeout means no timeout.
ReadByteWithTimeout(timeout time.Duration) (byte, error)
}
const badRune = '\ufffd'
var utf8SeqTimeout = 10 * time.Millisecond
// Reads a rune from the reader. The timeout applies to the first byte; a
// negative value means no timeout.
func readRune(rd byteReaderWithTimeout, timeout time.Duration) (rune, error) {
leader, err := rd.ReadByteWithTimeout(timeout)
if err != nil {
return badRune, err
}
var r rune
pending := 0
switch {
case leader>>7 == 0:
r = rune(leader)
case leader>>5 == 0x6:
r = rune(leader & 0x1f)
pending = 1
case leader>>4 == 0xe:
r = rune(leader & 0xf)
pending = 2
case leader>>3 == 0x1e:
r = rune(leader & 0x7)
pending = 3
}
for i := 0; i < pending; i++ {
b, err := rd.ReadByteWithTimeout(utf8SeqTimeout)
if err != nil {
return badRune, err
}
r = r<<6 + rune(b&0x3f)
}
return r, nil
}
|