diff options
| author | Ken Thompson <ken@golang.org> | 2009-04-10 19:49:31 -0700 |
|---|---|---|
| committer | Ken Thompson <ken@golang.org> | 2009-04-10 19:49:31 -0700 |
| commit | a91a8042b47e58d718e0af0edaf2eda485cc8880 (patch) | |
| tree | d031515005f681cd92520471e0db9d84513a3c28 /src/runtime/string.c | |
| parent | 72d867660d73107681da68c7f79b1b9442476f0a (diff) | |
| download | go-a91a8042b47e58d718e0af0edaf2eda485cc8880.tar.xz | |
range over strings
R=r
OCL=27332
CL=27332
Diffstat (limited to 'src/runtime/string.c')
| -rw-r--r-- | src/runtime/string.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/runtime/string.c b/src/runtime/string.c index 212fa5c28c..37f6ff0a1b 100644 --- a/src/runtime/string.c +++ b/src/runtime/string.c @@ -188,3 +188,159 @@ sys·arraystring(Array b, String s) mcpy(s.str, b.array, s.len); FLUSH(&s); } + +static int32 chartorune(int32 *rune, byte *str); +enum +{ + Runeself = 0x80, + Runeerror = 0xfff8, // fffd in plan9 +}; + +// func stringiter(string, int) (retk int); +void +sys·stringiter(String s, int32 k, int32 retk) +{ + int32 l, n; + + if(k >= s.len) { + // retk=0 is end of iteration + retk = 0; + goto out; + } + + l = s.str[k]; + n = 1; + + if(l >= Runeself) { + // multi-char rune + n = chartorune(&l, s.str+k); + if(k+n > s.len) { + // special case of multi-char rune + // that ran off end of string + l = Runeerror; + n = 1; + } + } + + retk = k+n; + +out: + FLUSH(&retk); +} + +// func stringiter2(string, int) (retk int, retv any); +void +sys·stringiter2(String s, int32 k, int32 retk, int32 retv) +{ + int32 l, n; + + if(k >= s.len) { + // retk=0 is end of iteration + retk = 0; + retv = 0; + goto out; + } + + l = s.str[k]; + n = 1; + + if(l >= Runeself) { + // multi-char rune + n = chartorune(&l, s.str+k); + if(k+n > s.len) { + // special case of multi-char rune + // that ran off end of string + l = Runeerror; + n = 1; + } + } + + retk = k+n; + retv = l; + +out: + FLUSH(&retk); + FLUSH(&retv); +} + +// +// copied from plan9 library +// + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + + 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<<Bitx)-1, /* 0011 1111 */ + Testx = Maskx ^ 0xFF, /* 1100 0000 */ +}; + +static int32 +chartorune(int32 *rune, byte *str) +{ + int32 c, c1, c2; + int32 l; + + /* + * one character sequence + * 00000-0007F => T1 + */ + c = str[0]; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = str[1] ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = str[2] ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * bad decoding + */ +bad: + *rune = Runeerror; + return 1; +} |
