aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/string.c
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-06-17 00:36:23 -0700
committerKeith Randall <khr@golang.org>2014-06-17 00:36:23 -0700
commit0f4b53c1c2db3ae7f3ed25ba7e5149baf14fc46c (patch)
tree41042f48f85f1a5038404c7a2980619737fe0743 /src/pkg/runtime/string.c
parentee8e687874b56f7c3ab1dd5585390b84dc74b14e (diff)
downloadgo-0f4b53c1c2db3ae7f3ed25ba7e5149baf14fc46c.tar.xz
runtime: reconstitute runetochar for use by gostringw.
Fixes windows builds (hopefully). LGTM=bradfitz R=golang-codereviews, bradfitz, alex.brainman CC=golang-codereviews https://golang.org/cl/103470045
Diffstat (limited to 'src/pkg/runtime/string.c')
-rw-r--r--src/pkg/runtime/string.c92
1 files changed, 90 insertions, 2 deletions
diff --git a/src/pkg/runtime/string.c b/src/pkg/runtime/string.c
index d5b668bd61..60a0545a9a 100644
--- a/src/pkg/runtime/string.c
+++ b/src/pkg/runtime/string.c
@@ -100,6 +100,94 @@ runtime·gostringnocopy(byte *str)
return s;
}
+// TODO: move this elsewhere
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+ Bit5 = 2,
+
+ 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 */
+
+ Runeerror = 0xFFFD,
+
+ SurrogateMin = 0xD800,
+ SurrogateMax = 0xDFFF,
+
+ Runemax = 0x10FFFF, /* maximum rune value */
+};
+
+static int32
+runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
+{
+ /* Runes are signed, so convert to unsigned for range check. */
+ uint32 c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ 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
+ */
+ 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;
+}
+
String
runtime·gostringw(uint16 *str)
{
@@ -109,14 +197,14 @@ runtime·gostringw(uint16 *str)
n1 = 0;
for(i=0; str[i]; i++)
- n1 += runtime·runetochar(buf, str[i]);
+ n1 += runetochar(buf, str[i]);
s = gostringsize(n1+4);
n2 = 0;
for(i=0; str[i]; i++) {
// check for race
if(n2 >= n1)
break;
- n2 += runtime·runetochar(s.str+n2, str[i]);
+ n2 += runetochar(s.str+n2, str[i]);
}
s.len = n2;
s.str[s.len] = 0;