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 (f *file) stat() (mtime time.Time, size int64, err error) { 68 st, err := f.file.Stat() 69 if err != nil { 70 return time.Time{}, 0, err 71 } 72 return st.ModTime(), st.Size(), nil 73} 74 75func open(name string) (*file, error) { 76 fd, err := os.Open(name) 77 if err != nil { 78 return nil, err 79 } 80 return &file{fd, make([]byte, 0, 64*1024), false}, nil 81} 82 83func stat(name string) (mtime time.Time, size int64, err error) { 84 st, err := os.Stat(name) 85 if err != nil { 86 return time.Time{}, 0, err 87 } 88 return st.ModTime(), st.Size(), nil 89} 90 91// Count occurrences in s of any bytes in t. 92func countAnyByte(s string, t string) int { 93 n := 0 94 for i := 0; i < len(s); i++ { 95 if bytealg.IndexByteString(t, s[i]) >= 0 { 96 n++ 97 } 98 } 99 return n 100} 101 102// Split s at any bytes in t. 103func splitAtBytes(s string, t string) []string { 104 a := make([]string, 1+countAnyByte(s, t)) 105 n := 0 106 last := 0 107 for i := 0; i < len(s); i++ { 108 if bytealg.IndexByteString(t, s[i]) >= 0 { 109 if last < i { 110 a[n] = s[last:i] 111 n++ 112 } 113 last = i + 1 114 } 115 } 116 if last < len(s) { 117 a[n] = s[last:] 118 n++ 119 } 120 return a[0:n] 121} 122 123func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } 124 125// Bigger than we need, not too big to worry about overflow 126const big = 0xFFFFFF 127 128// Decimal to integer. 129// Returns number, characters consumed, success. 130func dtoi(s string) (n int, i int, ok bool) { 131 n = 0 132 for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 133 n = n*10 + int(s[i]-'0') 134 if n >= big { 135 return big, i, false 136 } 137 } 138 if i == 0 { 139 return 0, 0, false 140 } 141 return n, i, true 142} 143 144// Hexadecimal to integer. 145// Returns number, characters consumed, success. 146func xtoi(s string) (n int, i int, ok bool) { 147 n = 0 148 for i = 0; i < len(s); i++ { 149 if '0' <= s[i] && s[i] <= '9' { 150 n *= 16 151 n += int(s[i] - '0') 152 } else if 'a' <= s[i] && s[i] <= 'f' { 153 n *= 16 154 n += int(s[i]-'a') + 10 155 } else if 'A' <= s[i] && s[i] <= 'F' { 156 n *= 16 157 n += int(s[i]-'A') + 10 158 } else { 159 break 160 } 161 if n >= big { 162 return 0, i, false 163 } 164 } 165 if i == 0 { 166 return 0, i, false 167 } 168 return n, i, true 169} 170 171// xtoi2 converts the next two hex digits of s into a byte. 172// If s is longer than 2 bytes then the third byte must be e. 173// If the first two bytes of s are not hex digits or the third byte 174// does not match e, false is returned. 175func xtoi2(s string, e byte) (byte, bool) { 176 if len(s) > 2 && s[2] != e { 177 return 0, false 178 } 179 n, ei, ok := xtoi(s[:2]) 180 return byte(n), ok && ei == 2 181} 182 183// hasUpperCase tells whether the given string contains at least one upper-case. 184func hasUpperCase(s string) bool { 185 for i := range s { 186 if 'A' <= s[i] && s[i] <= 'Z' { 187 return true 188 } 189 } 190 return false 191} 192 193// lowerASCIIBytes makes x ASCII lowercase in-place. 194func lowerASCIIBytes(x []byte) { 195 for i, b := range x { 196 if 'A' <= b && b <= 'Z' { 197 x[i] += 'a' - 'A' 198 } 199 } 200} 201 202// lowerASCII returns the ASCII lowercase version of b. 203func lowerASCII(b byte) byte { 204 if 'A' <= b && b <= 'Z' { 205 return b + ('a' - 'A') 206 } 207 return b 208} 209 210// trimSpace returns x without any leading or trailing ASCII whitespace. 211func trimSpace(x string) string { 212 for len(x) > 0 && isSpace(x[0]) { 213 x = x[1:] 214 } 215 for len(x) > 0 && isSpace(x[len(x)-1]) { 216 x = x[:len(x)-1] 217 } 218 return x 219} 220 221// isSpace reports whether b is an ASCII space character. 222func isSpace(b byte) bool { 223 return b == ' ' || b == '\t' || b == '\n' || b == '\r' 224} 225 226// removeComment returns line, removing any '#' byte and any following 227// bytes. 228func removeComment(line string) string { 229 if i := bytealg.IndexByteString(line, '#'); i != -1 { 230 return line[:i] 231 } 232 return line 233} 234 235// foreachField runs fn on each non-empty run of non-space bytes in x. 236// It returns the first non-nil error returned by fn. 237func foreachField(x string, fn func(field string) error) error { 238 x = trimSpace(x) 239 for len(x) > 0 { 240 sp := bytealg.IndexByteString(x, ' ') 241 if sp == -1 { 242 return fn(x) 243 } 244 if field := trimSpace(x[:sp]); len(field) > 0 { 245 if err := fn(field); err != nil { 246 return err 247 } 248 } 249 x = trimSpace(x[sp+1:]) 250 } 251 return nil 252} 253 254// stringsHasSuffixFold reports whether s ends in suffix, 255// ASCII-case-insensitively. 256func stringsHasSuffixFold(s, suffix string) bool { 257 return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) 258} 259 260// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t 261// are equal, ASCII-case-insensitively. 262func stringsEqualFold(s, t string) bool { 263 if len(s) != len(t) { 264 return false 265 } 266 for i := 0; i < len(s); i++ { 267 if lowerASCII(s[i]) != lowerASCII(t[i]) { 268 return false 269 } 270 } 271 return true 272} 273