// 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. // Process plain text into HTML. // - h2's are made from lines followed by a line "----\n" // - tab-indented blocks become
 blocks
//	- blank lines become 

marks // - "quoted strings" become quoted strings package main import ( "bufio"; "bytes"; "log"; "os"; "strings"; ) var ( lines = make([][]byte, 0, 10000); // assume big enough linebuf = make([]byte, 10000); // assume big enough empty = strings.Bytes(""); newline = strings.Bytes("\n"); tab = strings.Bytes("\t"); quote = strings.Bytes(`"`); sectionMarker = strings.Bytes("----\n"); preStart = strings.Bytes("

");
	preEnd = strings.Bytes("
\n"); pp = strings.Bytes("

\n"); ); func main() { read(); headings(); paragraphs(); coalesce(preStart, foldPre); coalesce(tab, foldTabs); quotes(); write(); } func read() { b := bufio.NewReader(os.Stdin); for { line, err := b.ReadBytes('\n'); if err == os.EOF { break; } if err != nil { log.Exit(err) } n := len(lines); lines = lines[0:n+1]; lines[n] = line; } } func write() { b := bufio.NewWriter(os.Stdout); for _, line := range lines { b.Write(expandTabs(line)); } b.Flush(); } // each time prefix is found on a line, call fold and replace // 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]; } // return the

 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();
}

// return the tab-indented block as a single 
-bounded slice
func foldTabs(i int) (n int, line []byte) {
	buf := new(bytes.Buffer);
	buf.WriteString("
\n");
	for i < len(lines) {
		if !bytes.HasPrefix(lines[i], tab) {
			break;
		}
		buf.Write(lines[i]);
		n++;
		i++;
	}
	buf.WriteString("
\n"); return n, buf.Bytes(); } func headings() { b := bufio.NewWriter(os.Stdout); for i, l := range lines { if i > 0 && bytes.Equal(l, sectionMarker) { lines[i-1] = strings.Bytes("

" + string(trim(lines[i-1])) + "

\n"); lines[i] = empty; } } b.Flush(); } func paragraphs() { for i, l := range lines { if bytes.Equal(l, newline) { lines[i] = pp; } } } func quotes() { for i, l := range lines { lines[i] = codeQuotes(l); } } 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("") } else { buf.WriteString("") } inQuote = !inQuote } else { buf.WriteByte(c) } } return buf.Bytes(); } // drop trailing newline func trim(l []byte) []byte { n := len(l); if n > 0 && l[n-1] == '\n' { return l[0:n-1] } return l } // expand tabs to 4 spaces. don't worry about columns. func expandTabs(l []byte) []byte { j := 0; // position in linebuf. for _, c := range l { if c == '\t' { for k := 0; k < 4; k++ { linebuf[j] = ' '; j++; } } else { linebuf[j] = c; j++; } } return linebuf[0:j]; }