1 // Copyright 2009 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.
5 // Simple file i/o and string manipulation, to avoid
6 // depending on strconv and bufio and strings.
14 _
"unsafe" // For go:linkname
23 func (f
*file
) close() { f
.file
.Close() }
25 func (f
*file
) getLineFromData() (s
string, ok
bool) {
28 for i
= 0; i
< len(data
); i
++ {
35 copy(data
[0:], data
[i
:])
40 if f
.atEOF
&& len(f
.data
) > 0 {
41 // EOF, return all we have
49 func (f
*file
) readLine() (s
string, ok
bool) {
50 if s
, ok
= f
.getLineFromData(); ok
{
53 if len(f
.data
) < cap(f
.data
) {
55 n
, err
:= io
.ReadFull(f
.file
, f
.data
[ln
:cap(f
.data
)])
57 f
.data
= f
.data
[0 : ln
+n
]
59 if err
== io
.EOF || err
== io
.ErrUnexpectedEOF
{
63 s
, ok
= f
.getLineFromData()
67 func open(name
string) (*file
, error
) {
68 fd
, err
:= os
.Open(name
)
72 return &file
{fd
, make([]byte, 0, 64*1024), false}, nil
75 func stat(name
string) (mtime time
.Time
, size
int64, err error
) {
76 st
, err
:= os
.Stat(name
)
78 return time
.Time
{}, 0, err
80 return st
.ModTime(), st
.Size(), nil
83 // byteIndex is strings.IndexByte. It returns the index of the
84 // first instance of c in s, or -1 if c is not present in s.
85 // strings.IndexByte is implemented in runtime/asm_$GOARCH.s
86 //go:linkname byteIndex strings.IndexByte
87 //extern strings.IndexByte
88 func byteIndex(s
string, c
byte) int
90 // Count occurrences in s of any bytes in t.
91 func countAnyByte(s
string, t
string) int {
93 for i
:= 0; i
< len(s
); i
++ {
94 if byteIndex(t
, s
[i
]) >= 0 {
101 // Split s at any bytes in t.
102 func splitAtBytes(s
string, t
string) []string {
103 a
:= make([]string, 1+countAnyByte(s
, t
))
106 for i
:= 0; i
< len(s
); i
++ {
107 if byteIndex(t
, s
[i
]) >= 0 {
122 func getFields(s
string) []string { return splitAtBytes(s
, " \r\t\n") }
124 // Bigger than we need, not too big to worry about overflow
127 // Decimal to integer.
128 // Returns number, characters consumed, success.
129 func dtoi(s
string) (n
int, i
int, ok
bool) {
131 for i
= 0; i
< len(s
) && '0' <= s
[i
] && s
[i
] <= '9'; i
++ {
132 n
= n
*10 + int(s
[i
]-'0')
143 // Hexadecimal to integer.
144 // Returns number, characters consumed, success.
145 func xtoi(s
string) (n
int, i
int, ok
bool) {
147 for i
= 0; i
< len(s
); i
++ {
148 if '0' <= s
[i
] && s
[i
] <= '9' {
151 } else if 'a' <= s
[i
] && s
[i
] <= 'f' {
153 n
+= int(s
[i
]-'a') + 10
154 } else if 'A' <= s
[i
] && s
[i
] <= 'F' {
156 n
+= int(s
[i
]-'A') + 10
170 // xtoi2 converts the next two hex digits of s into a byte.
171 // If s is longer than 2 bytes then the third byte must be e.
172 // If the first two bytes of s are not hex digits or the third byte
173 // does not match e, false is returned.
174 func xtoi2(s
string, e
byte) (byte, bool) {
175 if len(s
) > 2 && s
[2] != e
{
178 n
, ei
, ok
:= xtoi(s
[:2])
179 return byte(n
), ok
&& ei
== 2
182 // Convert integer to decimal string.
183 func itoa(val
int) string {
185 return "-" + uitoa(uint(-val
))
187 return uitoa(uint(val
))
190 // Convert unsigned integer to decimal string.
191 func uitoa(val
uint) string {
192 if val
== 0 { // avoid string allocation
195 var buf
[20]byte // big enough for 64bit value base 10
199 buf
[i
] = byte('0' + val
- q
*10)
204 buf
[i
] = byte('0' + val
)
205 return string(buf
[i
:])
208 // Convert i to a hexadecimal string. Leading zeros are not printed.
209 func appendHex(dst
[]byte, i
uint32) []byte {
211 return append(dst
, '0')
213 for j
:= 7; j
>= 0; j
-- {
216 dst
= append(dst
, hexDigit
[v
&0xf])
222 // Number of occurrences of b in s.
223 func count(s
string, b
byte) int {
225 for i
:= 0; i
< len(s
); i
++ {
233 // Index of rightmost occurrence of b in s.
234 func last(s
string, b
byte) int {
236 for i
--; i
>= 0; i
-- {
244 // lowerASCIIBytes makes x ASCII lowercase in-place.
245 func lowerASCIIBytes(x
[]byte) {
246 for i
, b
:= range x
{
247 if 'A' <= b
&& b
<= 'Z' {
253 // lowerASCII returns the ASCII lowercase version of b.
254 func lowerASCII(b
byte) byte {
255 if 'A' <= b
&& b
<= 'Z' {
256 return b
+ ('a' - 'A')
261 // trimSpace returns x without any leading or trailing ASCII whitespace.
262 func trimSpace(x
[]byte) []byte {
263 for len(x
) > 0 && isSpace(x
[0]) {
266 for len(x
) > 0 && isSpace(x
[len(x
)-1]) {
272 // isSpace reports whether b is an ASCII space character.
273 func isSpace(b
byte) bool {
274 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r'
277 // removeComment returns line, removing any '#' byte and any following
279 func removeComment(line
[]byte) []byte {
280 if i
:= bytesIndexByte(line
, '#'); i
!= -1 {
286 // foreachLine runs fn on each line of x.
287 // Each line (except for possibly the last) ends in '\n'.
288 // It returns the first non-nil error returned by fn.
289 func foreachLine(x
[]byte, fn
func(line
[]byte) error
) error
{
291 nl
:= bytesIndexByte(x
, '\n')
297 if err
:= fn(line
); err
!= nil {
304 // foreachField runs fn on each non-empty run of non-space bytes in x.
305 // It returns the first non-nil error returned by fn.
306 func foreachField(x
[]byte, fn
func(field
[]byte) error
) error
{
309 sp
:= bytesIndexByte(x
, ' ')
313 if field
:= trimSpace(x
[:sp
]); len(field
) > 0 {
314 if err
:= fn(field
); err
!= nil {
318 x
= trimSpace(x
[sp
+1:])
323 // bytesIndexByte is bytes.IndexByte. It returns the index of the
324 // first instance of c in s, or -1 if c is not present in s.
325 // bytes.IndexByte is implemented in runtime/asm_$GOARCH.s
326 //go:linkname bytesIndexByte bytes.IndexByte
327 //extern bytes.IndexByte
328 func bytesIndexByte(s
[]byte, c
byte) int
330 // stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
332 func stringsHasSuffix(s
, suffix
string) bool {
333 return len(s
) >= len(suffix
) && s
[len(s
)-len(suffix
):] == suffix
336 // stringsHasSuffixFold reports whether s ends in suffix,
337 // ASCII-case-insensitively.
338 func stringsHasSuffixFold(s
, suffix
string) bool {
339 return len(s
) >= len(suffix
) && stringsEqualFold(s
[len(s
)-len(suffix
):], suffix
)
342 // stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
343 func stringsHasPrefix(s
, prefix
string) bool {
344 return len(s
) >= len(prefix
) && s
[:len(prefix
)] == prefix
347 // stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
348 // are equal, ASCII-case-insensitively.
349 func stringsEqualFold(s
, t
string) bool {
350 if len(s
) != len(t
) {
353 for i
:= 0; i
< len(s
); i
++ {
354 if lowerASCII(s
[i
]) != lowerASCII(t
[i
]) {
361 func readFull(r io
.Reader
) (all
[]byte, err error
) {
362 buf
:= make([]byte, 1024)
364 n
, err
:= r
.Read(buf
)
365 all
= append(all
, buf
[:n
]...)
375 // goDebugString returns the value of the named GODEBUG key.
376 // GODEBUG is of the form "key=val,key2=val2"
377 func goDebugString(key
string) string {
378 s
:= os
.Getenv("GODEBUG")
379 for i
:= 0; i
< len(s
)-len(key
)-1; i
++ {
380 if i
> 0 && s
[i
-1] != ',' {
383 afterKey
:= s
[i
+len(key
):]
384 if afterKey
[0] != '=' || s
[i
:i
+len(key
)] != key
{
388 for i
, b
:= range val
{