github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/godoc/utils.go (about) 1 // Copyright 2010 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 // This file contains support functionality for godoc. 6 7 package main 8 9 import ( 10 pathpkg "path" 11 "sync" 12 "time" 13 "unicode/utf8" 14 ) 15 16 // An RWValue wraps a value and permits mutually exclusive 17 // access to it and records the time the value was last set. 18 // 19 type RWValue struct { 20 mutex sync.RWMutex 21 value interface{} 22 timestamp time.Time // time of last set() 23 } 24 25 func (v *RWValue) set(value interface{}) { 26 v.mutex.Lock() 27 v.value = value 28 v.timestamp = time.Now() 29 v.mutex.Unlock() 30 } 31 32 func (v *RWValue) get() (interface{}, time.Time) { 33 v.mutex.RLock() 34 defer v.mutex.RUnlock() 35 return v.value, v.timestamp 36 } 37 38 // isText returns true if a significant prefix of s looks like correct UTF-8; 39 // that is, if it is likely that s is human-readable text. 40 // 41 func isText(s []byte) bool { 42 const max = 1024 // at least utf8.UTFMax 43 if len(s) > max { 44 s = s[0:max] 45 } 46 for i, c := range string(s) { 47 if i+utf8.UTFMax > len(s) { 48 // last char may be incomplete - ignore 49 break 50 } 51 if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' { 52 // decoding error or control character - not a text file 53 return false 54 } 55 } 56 return true 57 } 58 59 // textExt[x] is true if the extension x indicates a text file, and false otherwise. 60 var textExt = map[string]bool{ 61 ".css": false, // must be served raw 62 ".js": false, // must be served raw 63 } 64 65 // isTextFile returns true if the file has a known extension indicating 66 // a text file, or if a significant chunk of the specified file looks like 67 // correct UTF-8; that is, if it is likely that the file contains human- 68 // readable text. 69 // 70 func isTextFile(filename string) bool { 71 // if the extension is known, use it for decision making 72 if isText, found := textExt[pathpkg.Ext(filename)]; found { 73 return isText 74 } 75 76 // the extension is not known; read an initial chunk 77 // of the file and check if it looks like text 78 f, err := fs.Open(filename) 79 if err != nil { 80 return false 81 } 82 defer f.Close() 83 84 var buf [1024]byte 85 n, err := f.Read(buf[0:]) 86 if err != nil { 87 return false 88 } 89 90 return isText(buf[0:n]) 91 }