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