summaryrefslogtreecommitdiff
path: root/src/cmd/godoc/utils.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/godoc/utils.go')
-rw-r--r--src/cmd/godoc/utils.go62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 55cf87841..a032bd331 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -15,11 +15,13 @@ import (
"strings"
"sync"
"time"
+ "utf8"
)
// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
+//
type RWValue struct {
mutex sync.RWMutex
value interface{}
@@ -107,3 +109,63 @@ func writeFileAtomically(filename string, data []byte) os.Error {
}
return os.Rename(f.Name(), filename)
}
+
+
+// isText returns true if a significant prefix of s looks like correct UTF-8;
+// that is, if it is likely that s is human-readable text.
+//
+func isText(s []byte) bool {
+ const max = 1024 // at least utf8.UTFMax
+ if len(s) > max {
+ s = s[0:max]
+ }
+ for i, c := range string(s) {
+ if i+utf8.UTFMax > len(s) {
+ // last char may be incomplete - ignore
+ break
+ }
+ if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
+ // decoding error or control character - not a text file
+ return false
+ }
+ }
+ return true
+}
+
+
+// TODO(gri): Should have a mapping from extension to handler, eventually.
+
+// textExt[x] is true if the extension x indicates a text file, and false otherwise.
+var textExt = map[string]bool{
+ ".css": false, // must be served raw
+ ".js": false, // must be served raw
+}
+
+
+// isTextFile returns true if the file has a known extension indicating
+// a text file, or if a significant chunk of the specified file looks like
+// correct UTF-8; that is, if it is likely that the file contains human-
+// readable text.
+//
+func isTextFile(filename string) bool {
+ // if the extension is known, use it for decision making
+ if isText, found := textExt[pathutil.Ext(filename)]; found {
+ return isText
+ }
+
+ // the extension is not known; read an initial chunk
+ // of the file and check if it looks like text
+ f, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+
+ var buf [1024]byte
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return false
+ }
+
+ return isText(buf[0:n])
+}