github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/strconv/makeisprint.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build ignore 6 // +build ignore 7 8 // 9 // usage: 10 // 11 // go run makeisprint.go -output isprint.go 12 // 13 14 package main 15 16 import ( 17 "bytes" 18 "flag" 19 "fmt" 20 "go/format" 21 "log" 22 "os" 23 "unicode" 24 ) 25 26 var filename = flag.String("output", "isprint.go", "output file name") 27 28 var ( 29 range16 []uint16 30 except16 []uint16 31 range32 []uint32 32 except32 []uint32 33 ) 34 35 // bsearch16 returns the smallest i such that a[i] >= x. 36 // If there is no such i, bsearch16 returns len(a). 37 func bsearch16(a []uint16, x uint16) int { 38 i, j := 0, len(a) 39 for i < j { 40 h := i + (j-i)>>1 41 if a[h] < x { 42 i = h + 1 43 } else { 44 j = h 45 } 46 } 47 return i 48 } 49 50 // bsearch32 returns the smallest i such that a[i] >= x. 51 // If there is no such i, bsearch32 returns len(a). 52 func bsearch32(a []uint32, x uint32) int { 53 i, j := 0, len(a) 54 for i < j { 55 h := i + (j-i)>>1 56 if a[h] < x { 57 i = h + 1 58 } else { 59 j = h 60 } 61 } 62 return i 63 } 64 65 func isPrint(r rune) bool { 66 // Same algorithm, either on uint16 or uint32 value. 67 // First, find first i such that rang[i] >= x. 68 // This is the index of either the start or end of a pair that might span x. 69 // The start is even (rang[i&^1]) and the end is odd (rang[i|1]). 70 // If we find x in a range, make sure x is not in exception list. 71 72 if 0 <= r && r < 1<<16 { 73 rr, rang, except := uint16(r), range16, except16 74 i := bsearch16(rang, rr) 75 if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { 76 return false 77 } 78 j := bsearch16(except, rr) 79 return j >= len(except) || except[j] != rr 80 } 81 82 rr, rang, except := uint32(r), range32, except32 83 i := bsearch32(rang, rr) 84 if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { 85 return false 86 } 87 j := bsearch32(except, rr) 88 return j >= len(except) || except[j] != rr 89 } 90 91 func scan(min, max rune) (rang, except []uint32) { 92 lo := rune(-1) 93 for i := min; ; i++ { 94 if (i > max || !unicode.IsPrint(i)) && lo >= 0 { 95 // End range, but avoid flip flop. 96 if i+1 <= max && unicode.IsPrint(i+1) { 97 except = append(except, uint32(i)) 98 continue 99 } 100 rang = append(rang, uint32(lo), uint32(i-1)) 101 lo = -1 102 } 103 if i > max { 104 break 105 } 106 if lo < 0 && unicode.IsPrint(i) { 107 lo = i 108 } 109 } 110 return 111 } 112 113 func to16(x []uint32) []uint16 { 114 var y []uint16 115 for _, v := range x { 116 if uint32(uint16(v)) != v { 117 panic("bad 32->16 conversion") 118 } 119 y = append(y, uint16(v)) 120 } 121 return y 122 } 123 124 func main() { 125 flag.Parse() 126 127 rang, except := scan(0, 0xFFFF) 128 range16 = to16(rang) 129 except16 = to16(except) 130 range32, except32 = scan(0x10000, unicode.MaxRune) 131 132 for i := rune(0); i <= unicode.MaxRune; i++ { 133 if isPrint(i) != unicode.IsPrint(i) { 134 log.Fatalf("%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i)) 135 } 136 } 137 138 var buf bytes.Buffer 139 140 fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. 141 // Use of this source code is governed by a BSD-style 142 // license that can be found in the LICENSE file.`+"\n\n") 143 fmt.Fprintf(&buf, "// Code generated by go run makeisprint.go -output isprint.go; DO NOT EDIT.\n\n") 144 fmt.Fprintf(&buf, "package strconv\n\n") 145 146 fmt.Fprintf(&buf, "// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n", 147 len(range16), len(except16), len(except32), 148 len(range32), 149 (len(range16)+len(except16)+len(except32))*2+ 150 (len(range32))*4) 151 152 fmt.Fprintf(&buf, "var isPrint16 = []uint16{\n") 153 for i := 0; i < len(range16); i += 2 { 154 fmt.Fprintf(&buf, "\t%#04x, %#04x,\n", range16[i], range16[i+1]) 155 } 156 fmt.Fprintf(&buf, "}\n\n") 157 158 fmt.Fprintf(&buf, "var isNotPrint16 = []uint16{\n") 159 for _, r := range except16 { 160 fmt.Fprintf(&buf, "\t%#04x,\n", r) 161 } 162 fmt.Fprintf(&buf, "}\n\n") 163 164 fmt.Fprintf(&buf, "var isPrint32 = []uint32{\n") 165 for i := 0; i < len(range32); i += 2 { 166 fmt.Fprintf(&buf, "\t%#06x, %#06x,\n", range32[i], range32[i+1]) 167 } 168 fmt.Fprintf(&buf, "}\n\n") 169 170 fmt.Fprintf(&buf, "var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n") 171 for _, r := range except32 { 172 if r >= 0x20000 { 173 log.Fatalf("%U too big for isNotPrint32\n", r) 174 } 175 fmt.Fprintf(&buf, "\t%#04x,\n", r-0x10000) 176 } 177 fmt.Fprintf(&buf, "}\n\n") 178 179 // The list of graphic but not "printable" runes is short. Just make one easy table. 180 fmt.Fprintf(&buf, "// isGraphic lists the graphic runes not matched by IsPrint.\n") 181 fmt.Fprintf(&buf, "var isGraphic = []uint16{\n") 182 for r := rune(0); r <= unicode.MaxRune; r++ { 183 if unicode.IsPrint(r) != unicode.IsGraphic(r) { 184 // Sanity check. 185 if !unicode.IsGraphic(r) { 186 log.Fatalf("%U is printable but not graphic\n", r) 187 } 188 if r > 0xFFFF { // We expect only 16-bit values. 189 log.Fatalf("%U too big for isGraphic\n", r) 190 } 191 fmt.Fprintf(&buf, "\t%#04x,\n", r) 192 } 193 } 194 fmt.Fprintf(&buf, "}\n") 195 196 data, err := format.Source(buf.Bytes()) 197 if err != nil { 198 log.Fatal(err) 199 } 200 err = os.WriteFile(*filename, data, 0644) 201 if err != nil { 202 log.Fatal(err) 203 } 204 }