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  }