Source file
src/strconv/makeisprint.go
1
2
3
4
5
6
7
8
9
10
11
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
36
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
51
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
67
68
69
70
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
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
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
185 if !unicode.IsGraphic(r) {
186 log.Fatalf("%U is printable but not graphic\n", r)
187 }
188 if r > 0xFFFF {
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 }
205
View as plain text