Source file
src/strconv/makeisprint.go
1
2
3
4
5
6
7
8
9
10
11
12
13 package main
14
15 import (
16 "bytes"
17 "flag"
18 "fmt"
19 "go/format"
20 "log"
21 "os"
22 "slices"
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 func isPrint(r rune) bool {
36
37
38
39
40
41
42 if 0 <= r && r < 1<<16 {
43 rr, rang, except := uint16(r), range16, except16
44 i, _ := slices.BinarySearch(rang, rr)
45 if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
46 return false
47 }
48 _, found := slices.BinarySearch(except, rr)
49 return !found
50 }
51
52 rr, rang, except := uint32(r), range32, except32
53 i, _ := slices.BinarySearch(rang, rr)
54 if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
55 return false
56 }
57 _, found := slices.BinarySearch(except, rr)
58 return !found
59 }
60
61 func scan(min, max rune) (rang, except []uint32) {
62 lo := rune(-1)
63 for i := min; ; i++ {
64 if (i > max || !unicode.IsPrint(i)) && lo >= 0 {
65
66 if i+1 <= max && unicode.IsPrint(i+1) {
67 except = append(except, uint32(i))
68 continue
69 }
70 rang = append(rang, uint32(lo), uint32(i-1))
71 lo = -1
72 }
73 if i > max {
74 break
75 }
76 if lo < 0 && unicode.IsPrint(i) {
77 lo = i
78 }
79 }
80 return
81 }
82
83 func to16(x []uint32) []uint16 {
84 var y []uint16
85 for _, v := range x {
86 if uint32(uint16(v)) != v {
87 panic("bad 32->16 conversion")
88 }
89 y = append(y, uint16(v))
90 }
91 return y
92 }
93
94 func main() {
95 flag.Parse()
96
97 rang, except := scan(0, 0xFFFF)
98 range16 = to16(rang)
99 except16 = to16(except)
100 range32, except32 = scan(0x10000, unicode.MaxRune)
101
102 for i := rune(0); i <= unicode.MaxRune; i++ {
103 if isPrint(i) != unicode.IsPrint(i) {
104 log.Fatalf("%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
105 }
106 }
107
108 var buf bytes.Buffer
109
110 fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved.
111 // Use of this source code is governed by a BSD-style
112 // license that can be found in the LICENSE file.`+"\n\n")
113 fmt.Fprintf(&buf, "// Code generated by go run makeisprint.go -output isprint.go; DO NOT EDIT.\n\n")
114 fmt.Fprintf(&buf, "package strconv\n\n")
115
116 fmt.Fprintf(&buf, "// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
117 len(range16), len(except16), len(except32),
118 len(range32),
119 (len(range16)+len(except16)+len(except32))*2+
120 (len(range32))*4)
121
122 fmt.Fprintf(&buf, "var isPrint16 = []uint16{\n")
123 for i := 0; i < len(range16); i += 2 {
124 fmt.Fprintf(&buf, "\t%#04x, %#04x,\n", range16[i], range16[i+1])
125 }
126 fmt.Fprintf(&buf, "}\n\n")
127
128 fmt.Fprintf(&buf, "var isNotPrint16 = []uint16{\n")
129 for _, r := range except16 {
130 fmt.Fprintf(&buf, "\t%#04x,\n", r)
131 }
132 fmt.Fprintf(&buf, "}\n\n")
133
134 fmt.Fprintf(&buf, "var isPrint32 = []uint32{\n")
135 for i := 0; i < len(range32); i += 2 {
136 fmt.Fprintf(&buf, "\t%#06x, %#06x,\n", range32[i], range32[i+1])
137 }
138 fmt.Fprintf(&buf, "}\n\n")
139
140 fmt.Fprintf(&buf, "var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
141 for _, r := range except32 {
142 if r >= 0x20000 {
143 log.Fatalf("%U too big for isNotPrint32\n", r)
144 }
145 fmt.Fprintf(&buf, "\t%#04x,\n", r-0x10000)
146 }
147 fmt.Fprintf(&buf, "}\n\n")
148
149
150 fmt.Fprintf(&buf, "// isGraphic lists the graphic runes not matched by IsPrint.\n")
151 fmt.Fprintf(&buf, "var isGraphic = []uint16{\n")
152 for r := rune(0); r <= unicode.MaxRune; r++ {
153 if unicode.IsPrint(r) != unicode.IsGraphic(r) {
154
155 if !unicode.IsGraphic(r) {
156 log.Fatalf("%U is printable but not graphic\n", r)
157 }
158 if r > 0xFFFF {
159 log.Fatalf("%U too big for isGraphic\n", r)
160 }
161 fmt.Fprintf(&buf, "\t%#04x,\n", r)
162 }
163 }
164 fmt.Fprintf(&buf, "}\n")
165
166 data, err := format.Source(buf.Bytes())
167 if err != nil {
168 log.Fatal(err)
169 }
170 err = os.WriteFile(*filename, data, 0644)
171 if err != nil {
172 log.Fatal(err)
173 }
174 }
175
View as plain text