github.com/v2fly/tools@v0.100.0/godoc/util/util.go (about) 1 // Copyright 2013 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 // Package util contains utility types and functions for godoc. 6 package util // import "github.com/v2fly/tools/godoc/util" 7 8 import ( 9 pathpkg "path" 10 "sync" 11 "time" 12 "unicode/utf8" 13 14 "github.com/v2fly/tools/godoc/vfs" 15 ) 16 17 // An RWValue wraps a value and permits mutually exclusive 18 // access to it and records the time the value was last set. 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 reports whether a significant prefix of s looks like correct UTF-8; 39 // that is, if it is likely that s is human-readable text. 40 func IsText(s []byte) bool { 41 const max = 1024 // at least utf8.UTFMax 42 if len(s) > max { 43 s = s[0:max] 44 } 45 for i, c := range string(s) { 46 if i+utf8.UTFMax > len(s) { 47 // last char may be incomplete - ignore 48 break 49 } 50 if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' { 51 // decoding error or control character - not a text file 52 return false 53 } 54 } 55 return true 56 } 57 58 // textExt[x] is true if the extension x indicates a text file, and false otherwise. 59 var textExt = map[string]bool{ 60 ".css": false, // must be served raw 61 ".js": false, // must be served raw 62 ".svg": false, // must be served raw 63 } 64 65 // IsTextFile reports whether 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 func IsTextFile(fs vfs.Opener, filename string) bool { 70 // if the extension is known, use it for decision making 71 if isText, found := textExt[pathpkg.Ext(filename)]; found { 72 return isText 73 } 74 75 // the extension is not known; read an initial chunk 76 // of the file and check if it looks like text 77 f, err := fs.Open(filename) 78 if err != nil { 79 return false 80 } 81 defer f.Close() 82 83 var buf [1024]byte 84 n, err := f.Read(buf[0:]) 85 if err != nil { 86 return false 87 } 88 89 return IsText(buf[0:n]) 90 }