diff options
Diffstat (limited to 'doc/htmlgen.go')
-rw-r--r-- | doc/htmlgen.go | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/doc/htmlgen.go b/doc/htmlgen.go deleted file mode 100644 index 5318a07dc..000000000 --- a/doc/htmlgen.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// If --html is set, process plain text into HTML. -// - h2's are made from lines followed by a line "----\n" -// - tab-indented blocks become <pre> blocks with the first tab deleted -// - blank lines become <p> marks (except inside <pre> tags) -// - "quoted strings" become <code>quoted strings</code> - -// Lines beginning !src define pieces of program source to be -// extracted from other files and injected as <pre> blocks. -// The syntax is simple: 1, 2, or 3 space-separated arguments: -// -// Whole file: -// !src foo.go -// One line (here the signature of main): -// !src foo.go /^func.main/ -// Block of text, determined by start and end (here the body of main): -// !src foo.go /^func.main/ /^}/ -// -// Patterns can be /regular.expression/, a decimal number, or $ -// to signify the end of the file. -// TODO: the regular expression cannot contain spaces; does this matter? - -package main - -import ( - "bufio" - "bytes" - "flag" - "fmt" - "io/ioutil" - "log" - "os" - "regexp" - "strconv" - "strings" - "template" -) - -var ( - html = flag.Bool("html", true, "process text into HTML") -) - -var ( - // lines holds the input and is reworked in place during processing. - lines = make([][]byte, 0, 20000) - - empty = []byte("") - newline = []byte("\n") - tab = []byte("\t") - quote = []byte(`"`) - indent = []byte(" ") - - sectionMarker = []byte("----\n") - preStart = []byte("<pre>") - preEnd = []byte("</pre>\n") - pp = []byte("<p>\n") - - srcPrefix = []byte("!src") -) - -func main() { - flag.Parse() - read() - programs() - if *html { - headings() - coalesce(preStart, foldPre) - coalesce(tab, foldTabs) - paragraphs() - quotes() - } - write() -} - -// read turns standard input into a slice of lines. -func read() { - b := bufio.NewReader(os.Stdin) - for { - line, err := b.ReadBytes('\n') - if err == os.EOF { - break - } - if err != nil { - log.Fatal(err) - } - lines = append(lines, line) - } -} - -// write puts the result on standard output. -func write() { - b := bufio.NewWriter(os.Stdout) - for _, line := range lines { - b.Write(expandTabs(line)) - } - b.Flush() -} - -// programs injects source code from !src invocations. -func programs() { - nlines := make([][]byte, 0, len(lines)*3/2) - for _, line := range lines { - if bytes.HasPrefix(line, srcPrefix) { - line = trim(line)[len(srcPrefix):] - prog := srcCommand(string(line)) - if *html { - nlines = append(nlines, []byte(fmt.Sprintf("<pre><!--%s\n-->", line))) - } - for _, l := range prog { - nlines = append(nlines, htmlEscape(l)) - } - if *html { - nlines = append(nlines, preEnd) - } - } else { - nlines = append(nlines, line) - } - } - lines = nlines -} - -// srcCommand processes one !src invocation. -func srcCommand(command string) [][]byte { - // TODO: quoted args so we can have 'a b'? - args := strings.Fields(command) - if len(args) == 0 || len(args) > 3 { - log.Fatal("bad syntax for src command: %s", command) - } - file := args[0] - lines := bytes.SplitAfter(readFile(file), newline) - // File plus zero args: whole file: - // !src file.go - if len(args) == 1 { - return lines - } - start := match(file, 0, lines, string(args[1])) - // File plus one arg: one line: - // !src file.go /foo/ - if len(args) == 2 { - return [][]byte{lines[start]} - } - // File plus two args: range: - // !src file.go /foo/ /^}/ - end := match(file, start, lines, string(args[2])) - return lines[start : end+1] // +1 to include matched line. -} - -// htmlEscape makes sure input is HTML clean, if necessary. -func htmlEscape(input []byte) []byte { - if !*html || bytes.IndexAny(input, `&"<>`) < 0 { - return input - } - var b bytes.Buffer - template.HTMLEscape(&b, input) - return b.Bytes() -} - -// readFile reads and returns a file as part of !src processing. -func readFile(name string) []byte { - file, err := ioutil.ReadFile(name) - if err != nil { - log.Fatal(err) - } - return file -} - -// match identifies the input line that matches the pattern in a !src invocation. -// If start>0, match lines starting there rather than at the beginning. -func match(file string, start int, lines [][]byte, pattern string) int { - // $ matches the end of the file. - if pattern == "$" { - return len(lines) - 1 - } - // Number matches the line. - if i, err := strconv.Atoi(pattern); err == nil { - return i - 1 // Lines are 1-indexed. - } - // /regexp/ matches the line that matches the regexp. - if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' { - re, err := regexp.Compile(pattern[1 : len(pattern)-1]) - if err != nil { - log.Fatal(err) - } - for i := start; i < len(lines); i++ { - if re.Match(lines[i]) { - return i - } - } - log.Fatalf("%s: no match for %s", file, pattern) - } - log.Fatalf("unrecognized pattern: %s", pattern) - return 0 -} - -// coalesce combines lines. Each time prefix is found on a line, -// it calls fold and replaces the line with return value from fold. -func coalesce(prefix []byte, fold func(i int) (n int, line []byte)) { - j := 0 // output line number goes up by one each loop - for i := 0; i < len(lines); { - if bytes.HasPrefix(lines[i], prefix) { - nlines, block := fold(i) - lines[j] = block - i += nlines - } else { - lines[j] = lines[i] - i++ - } - j++ - } - lines = lines[0:j] -} - -// foldPre returns the <pre> block as a single slice. -func foldPre(i int) (n int, line []byte) { - buf := new(bytes.Buffer) - for i < len(lines) { - buf.Write(lines[i]) - n++ - if bytes.Equal(lines[i], preEnd) { - break - } - i++ - } - return n, buf.Bytes() -} - -// foldTabs returns the tab-indented block as a single <pre>-bounded slice. -func foldTabs(i int) (n int, line []byte) { - buf := new(bytes.Buffer) - buf.WriteString("<pre>\n") - for i < len(lines) { - if !bytes.HasPrefix(lines[i], tab) { - break - } - buf.Write(lines[i][1:]) // delete leading tab. - n++ - i++ - } - buf.WriteString("</pre>\n") - return n, buf.Bytes() -} - -// headings turns sections into HTML sections. -func headings() { - b := bufio.NewWriter(os.Stdout) - for i, l := range lines { - if i > 0 && bytes.Equal(l, sectionMarker) { - lines[i-1] = []byte("<h2>" + string(trim(lines[i-1])) + "</h2>\n") - lines[i] = empty - } - } - b.Flush() -} - -// paragraphs turns blank lines into paragraph marks. -func paragraphs() { - for i, l := range lines { - if bytes.Equal(l, newline) { - lines[i] = pp - } - } -} - -// quotes turns "x" in the file into <code>x</code>. -func quotes() { - for i, l := range lines { - lines[i] = codeQuotes(l) - } -} - -// quotes turns "x" in the line into <code>x</code>. -func codeQuotes(l []byte) []byte { - if bytes.HasPrefix(l, preStart) { - return l - } - n := bytes.Index(l, quote) - if n < 0 { - return l - } - buf := new(bytes.Buffer) - inQuote := false - for _, c := range l { - if c == '"' { - if inQuote { - buf.WriteString("</code>") - } else { - buf.WriteString("<code>") - } - inQuote = !inQuote - } else { - buf.WriteByte(c) - } - } - return buf.Bytes() -} - -// trim drops the trailing newline, if present. -func trim(l []byte) []byte { - n := len(l) - if n > 0 && l[n-1] == '\n' { - return l[0 : n-1] - } - return l -} - -// expandTabs expands tabs to spaces. It doesn't worry about columns. -func expandTabs(l []byte) []byte { - return bytes.Replace(l, tab, indent, -1) -} |