]> Cypherpunks repositories - gostls13.git/commitdiff
fix string range to have full unicode range (up to 10FFFF).
authorRob Pike <r@golang.org>
Mon, 13 Apr 2009 00:01:17 +0000 (17:01 -0700)
committerRob Pike <r@golang.org>
Mon, 13 Apr 2009 00:01:17 +0000 (17:01 -0700)
add test for string range.

test has minor failure: after loop the index == len(s); should be len(s)-1
in this case.  according to spec, vars are left at position at last
iteration.

R=ken,rsc
DELTA=259  (161 added, 96 deleted, 2 changed)
OCL=27343
CL=27343

src/runtime/rune.c
src/runtime/runtime.h
src/runtime/string.c
test/golden.out
test/stringrange.go [new file with mode: 0644]

index 9e731ad219dfdac2baccd5de241630ed1ae95aa5..2acf421cb069daac99c35fa3478beee610d97083 100644 (file)
@@ -52,6 +52,119 @@ enum
        Runemax = 0x10FFFF,     /* maximum rune value */
 };
 
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ * 
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer.  This is to avoid
+ * possible access violations.  If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int32
+charntorune(int32 *rune, uint8 *str, int32 length)
+{
+       int32 c, c1, c2, c3, l;
+
+       /* When we're not allowed to read anything */
+       if(length <= 0) {
+               goto badlen;
+       }
+
+       /*
+        * one character sequence (7-bit value)
+        *      00000-0007F => T1
+        */
+       c = *(uint8*)str;
+       if(c < Tx) {
+               *rune = c;
+               return 1;
+       }
+
+       // If we can't read more than one character we must stop
+       if(length <= 1) {
+               goto badlen;
+       }
+
+       /*
+        * two character sequence (11-bit value)
+        *      0080-07FF => T2 Tx
+        */
+       c1 = *(uint8*)(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;
+       }
+
+       // If we can't read more than two characters we must stop
+       if(length <= 2) {
+               goto badlen;
+       }
+
+       /*
+        * three character sequence (16-bit value)
+        *      0800-FFFF => T3 Tx Tx
+        */
+       c2 = *(uint8*)(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;
+       }
+
+       if (length <= 3)
+               goto badlen;
+
+       /*
+        * four character sequence (21-bit value)
+        *      10000-1FFFFF => T4 Tx Tx Tx
+        */
+       c3 = *(uint8*)(str+3) ^ Tx;
+       if (c3 & Testx)
+               goto bad;
+       if (c < T5) {
+               l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+               if (l <= Rune3 || l > Runemax)
+                       goto bad;
+               *rune = l;
+               return 4;
+       }
+
+       // Support for 5-byte or longer UTF-8 would go here, but
+       // since we don't have that, we'll just fall through to bad.
+
+       /*
+        * bad decoding
+        */
+bad:
+       *rune = Bad;
+       return 1;
+badlen:
+       *rune = Bad;
+       return 0;
+
+}
+
 int32
 runetochar(byte *str, int32 rune)  /* note: in original, arg2 was pointer */
 {
index bdadbfc17ee2ddd1d888d01820dc527373a08a1d..6b398c2bfa0bc9785bf73f58f7264f5aaa04bec7 100644 (file)
@@ -272,6 +272,7 @@ int32       strcmp(byte*, byte*);
 int32  findnull(byte*);
 void   dump(byte*, int32);
 int32  runetochar(byte*, int32);
+int32  charntorune(int32*, uint8*, int32);
 
 /*
  * very low level c-called
index 4d89e960012c0f0ba0d6991cb80f013c49d83557..b9b361861e364942e74e8cfdb17237d878a468ab 100644 (file)
@@ -189,11 +189,9 @@ sys·arraystring(Array b, String s)
        FLUSH(&s);
 }
 
-static int32   chartorune(int32 *rune, byte *str);
 enum
 {
        Runeself        = 0x80,
-       Runeerror       = 0xfffd,
 };
 
 // func        stringiter(string, int) (retk int);
@@ -213,13 +211,7 @@ sys·stringiter(String s, int32 k, int32 retk)
 
        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;
-               }
+               n = charntorune(&l, s.str+k, s.len-k);
        }
 
        retk = k+n;
@@ -246,13 +238,7 @@ sys·stringiter2(String s, int32 k, int32 retk, int32 retv)
 
        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;
-               }
+               n = charntorune(&l, s.str+k, s.len-k);
        }
 
        retk = k+n;
@@ -262,85 +248,3 @@ 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;
-}
index b3cc4fb54334c0ad8c1a430cb1aeb92f3625ef6c..7cb408b8e2ad95f4b4b4fcbda14b7b26b5f51e84 100644 (file)
@@ -67,6 +67,10 @@ panic PC=xxx
 =========== ./sigchld.go
 survived SIGCHLD
 
+=========== ./stringrange.go
+after loop i is 18 not 17
+FAIL
+
 =========== ./turing.go
 Hello World!
 
diff --git a/test/stringrange.go b/test/stringrange.go
new file mode 100644 (file)
index 0000000..66d25e1
--- /dev/null
@@ -0,0 +1,47 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import(
+        "fmt";
+        "utf8";
+)
+
+func main() {
+       s := "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe\U0010FFFFx";
+       expect := []int{ 0, 0123, 0, 0xFFFD, 0xFFFD, 0x123, 0xbabe, 0xbabe, 0x10FFFF, 'x' };
+       var rune, size int;
+       offset := 0;
+       var i, c int;
+       ok := true;
+       cnum := 0;
+       for i, c = range s {
+               rune, size := utf8.DecodeRuneInString(s, i);  // check it another way
+               if i != offset {
+                       fmt.Printf("unexpected offset %d not %d\n", i, offset);
+                       ok = false;
+               }
+               if rune != expect[cnum] {
+                       fmt.Printf("unexpected rune %d from DecodeRuneInString: %x not %x\n", i, rune, expect[cnum]);
+                       ok = false;
+               }
+               if c != expect[cnum] {
+                       fmt.Printf("unexpected rune %d from range: %x not %x\n", i, rune, expect[cnum]);
+                       ok = false;
+               }
+               offset += size;
+               cnum++;
+       }
+       if i != len(s)-1 {
+               fmt.Println("after loop i is", i, "not", len(s)-1);
+               ok = false;
+       }
+       if !ok {
+               fmt.Println("FAIL");
+               sys.Exit(1)
+       }
+}