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. 4 5// Simple file i/o and string manipulation, to avoid 6// depending on strconv and bufio and strings. 7 8package net 9 10import ( 11 "internal/bytealg" 12 "io" 13 "os" 14 "time" 15) 16 17type file struct { 18 file *os.File 19 data []byte 20 atEOF bool 21} 22 23func (f *file) close() { f.file.Close() } 24 25func (f *file) getLineFromData() (s string, ok bool) { 26 data := f.data 27 i := 0 28 for i = 0; i < len(data); i++ { 29 if data[i] == '\n' { 30 s = string(data[0:i]) 31 ok = true 32 // move data 33 i++ 34 n := len(data) - i 35 copy(data[0:], data[i:]) 36 f.data = data[0:n] 37 return 38 } 39 } 40 if f.atEOF && len(f.data) > 0 { 41 // EOF, return all we have 42 s = string(data) 43 f.data = f.data[0:0] 44 ok = true 45 } 46 return 47} 48 49func (f *file) readLine() (s string, ok bool) { 50 if s, ok = f.getLineFromData(); ok { 51 return 52 } 53 if len(f.data) < cap(f.data) { 54 ln := len(f.data) 55 n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)]) 56 if n >= 0 { 57 f.data = f.data[0 : ln+n] 58 } 59 if err == io.EOF || err == io.ErrUnexpectedEOF { 60 f.atEOF = true 61 } 62 } 63 s, ok = f.getLineFromData() 64 return 65} 66 67func open(name string) (*file, error) { 68 fd, err := os.Open(name) 69 if err != nil { 70 return nil, err 71 } 72 return &file{fd, make([]byte, 0, 64*1024), false}, nil 73} 74 75func stat(name string) (mtime time.Time, size int64, err error) { 76 st, err := os.Stat(name) 77 if err != nil { 78 return time.Time{}, 0, err 79 } 80 return st.ModTime(), st.Size(), nil 81} 82 83// Count occurrences in s of any bytes in t. 84func countAnyByte(s string, t string) int { 85 n := 0 86 for i := 0; i < len(s); i++ { 87 if bytealg.IndexByteString(t, s[i]) >= 0 { 88 n++ 89 } 90 } 91 return n 92} 93 94// Split s at any bytes in t. 95func splitAtBytes(s string, t string) []string { 96 a := make([]string, 1+countAnyByte(s, t)) 97 n := 0 98 last := 0 99 for i := 0; i < len(s); i++ { 100 if bytealg.IndexByteString(t, s[i]) >= 0 { 101 if last < i { 102 a[n] = s[last:i] 103 n++ 104 } 105 last = i + 1 106 } 107 } 108 if last < len(s) { 109 a[n] = s[last:] 110 n++ 111 } 112 return a[0:n] 113} 114 115func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } 116 117// Bigger than we need, not too big to worry about overflow 118const big = 0xFFFFFF 119 120// Decimal to integer. 121// Returns number, characters consumed, success. 122func dtoi(s string) (n int, i int, ok bool) { 123 n = 0 124 for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 125 n = n*10 + int(s[i]-'0') 126 if n >= big { 127 return big, i, false 128 } 129 } 130 if i == 0 { 131 return 0, 0, false 132 } 133 return n, i, true 134} 135 136// Hexadecimal to integer. 137// Returns number, characters consumed, success. 138func xtoi(s string) (n int, i int, ok bool) { 139 n = 0 140 for i = 0; i < len(s); i++ { 141 if '0' <= s[i] && s[i] <= '9' { 142 n *= 16 143 n += int(s[i] - '0') 144 } else if 'a' <= s[i] && s[i] <= 'f' { 145 n *= 16 146 n += int(s[i]-'a') + 10 147 } else if 'A' <= s[i] && s[i] <= 'F' { 148 n *= 16 149 n += int(s[i]-'A') + 10 150 } else { 151 break 152 } 153 if n >= big { 154 return 0, i, false 155 } 156 } 157 if i == 0 { 158 return 0, i, false 159 } 160 return n, i, true 161} 162 163// xtoi2 converts the next two hex digits of s into a byte. 164// If s is longer than 2 bytes then the third byte must be e. 165// If the first two bytes of s are not hex digits or the third byte 166// does not match e, false is returned. 167func xtoi2(s string, e byte) (byte, bool) { 168 if len(s) > 2 && s[2] != e { 169 return 0, false 170 } 171 n, ei, ok := xtoi(s[:2]) 172 return byte(n), ok && ei == 2 173} 174 175// Convert integer to decimal string. 176func itoa(val int) string { 177 if val < 0 { 178 return "-" + uitoa(uint(-val)) 179 } 180 return uitoa(uint(val)) 181} 182 183// Convert unsigned integer to decimal string. 184func uitoa(val uint) string { 185 if val == 0 { // avoid string allocation 186 return "0" 187 } 188 var buf [20]byte // big enough for 64bit value base 10 189 i := len(buf) - 1 190 for val >= 10 { 191 q := val / 10 192 buf[i] = byte('0' + val - q*10) 193 i-- 194 val = q 195 } 196 // val < 10 197 buf[i] = byte('0' + val) 198 return string(buf[i:]) 199} 200 201// Convert i to a hexadecimal string. Leading zeros are not printed. 202func appendHex(dst []byte, i uint32) []byte { 203 if i == 0 { 204 return append(dst, '0') 205 } 206 for j := 7; j >= 0; j-- { 207 v := i >> uint(j*4) 208 if v > 0 { 209 dst = append(dst, hexDigit[v&0xf]) 210 } 211 } 212 return dst 213} 214 215// Number of occurrences of b in s. 216func count(s string, b byte) int { 217 n := 0 218 for i := 0; i < len(s); i++ { 219 if s[i] == b { 220 n++ 221 } 222 } 223 return n 224} 225 226// Index of rightmost occurrence of b in s. 227func last(s string, b byte) int { 228 i := len(s) 229 for i--; i >= 0; i-- { 230 if s[i] == b { 231 break 232 } 233 } 234 return i 235} 236 237// lowerASCIIBytes makes x ASCII lowercase in-place. 238func lowerASCIIBytes(x []byte) { 239 for i, b := range x { 240 if 'A' <= b && b <= 'Z' { 241 x[i] += 'a' - 'A' 242 } 243 } 244} 245 246// lowerASCII returns the ASCII lowercase version of b. 247func lowerASCII(b byte) byte { 248 if 'A' <= b && b <= 'Z' { 249 return b + ('a' - 'A') 250 } 251 return b 252} 253 254// trimSpace returns x without any leading or trailing ASCII whitespace. 255func trimSpace(x []byte) []byte { 256 for len(x) > 0 && isSpace(x[0]) { 257 x = x[1:] 258 } 259 for len(x) > 0 && isSpace(x[len(x)-1]) { 260 x = x[:len(x)-1] 261 } 262 return x 263} 264 265// isSpace reports whether b is an ASCII space character. 266func isSpace(b byte) bool { 267 return b == ' ' || b == '\t' || b == '\n' || b == '\r' 268} 269 270// removeComment returns line, removing any '#' byte and any following 271// bytes. 272func removeComment(line []byte) []byte { 273 if i := bytealg.IndexByte(line, '#'); i != -1 { 274 return line[:i] 275 } 276 return line 277} 278 279// foreachLine runs fn on each line of x. 280// Each line (except for possibly the last) ends in '\n'. 281// It returns the first non-nil error returned by fn. 282func foreachLine(x []byte, fn func(line []byte) error) error { 283 for len(x) > 0 { 284 nl := bytealg.IndexByte(x, '\n') 285 if nl == -1 { 286 return fn(x) 287 } 288 line := x[:nl+1] 289 x = x[nl+1:] 290 if err := fn(line); err != nil { 291 return err 292 } 293 } 294 return nil 295} 296 297// foreachField runs fn on each non-empty run of non-space bytes in x. 298// It returns the first non-nil error returned by fn. 299func foreachField(x []byte, fn func(field []byte) error) error { 300 x = trimSpace(x) 301 for len(x) > 0 { 302 sp := bytealg.IndexByte(x, ' ') 303 if sp == -1 { 304 return fn(x) 305 } 306 if field := trimSpace(x[:sp]); len(field) > 0 { 307 if err := fn(field); err != nil { 308 return err 309 } 310 } 311 x = trimSpace(x[sp+1:]) 312 } 313 return nil 314} 315 316// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in 317// suffix. 318func stringsHasSuffix(s, suffix string) bool { 319 return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix 320} 321 322// stringsHasSuffixFold reports whether s ends in suffix, 323// ASCII-case-insensitively. 324func stringsHasSuffixFold(s, suffix string) bool { 325 return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) 326} 327 328// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix. 329func stringsHasPrefix(s, prefix string) bool { 330 return len(s) >= len(prefix) && s[:len(prefix)] == prefix 331} 332 333// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t 334// are equal, ASCII-case-insensitively. 335func stringsEqualFold(s, t string) bool { 336 if len(s) != len(t) { 337 return false 338 } 339 for i := 0; i < len(s); i++ { 340 if lowerASCII(s[i]) != lowerASCII(t[i]) { 341 return false 342 } 343 } 344 return true 345} 346 347func readFull(r io.Reader) (all []byte, err error) { 348 buf := make([]byte, 1024) 349 for { 350 n, err := r.Read(buf) 351 all = append(all, buf[:n]...) 352 if err == io.EOF { 353 return all, nil 354 } 355 if err != nil { 356 return nil, err 357 } 358 } 359} 360 361// goDebugString returns the value of the named GODEBUG key. 362// GODEBUG is of the form "key=val,key2=val2" 363func goDebugString(key string) string { 364 s := os.Getenv("GODEBUG") 365 for i := 0; i < len(s)-len(key)-1; i++ { 366 if i > 0 && s[i-1] != ',' { 367 continue 368 } 369 afterKey := s[i+len(key):] 370 if afterKey[0] != '=' || s[i:i+len(key)] != key { 371 continue 372 } 373 val := afterKey[1:] 374 for i, b := range val { 375 if b == ',' { 376 return val[:i] 377 } 378 } 379 return val 380 } 381 return "" 382} 383