mirror of
				https://github.com/golang/go.git
				synced 2025-11-04 10:40:57 +00:00 
			
		
		
		
	
		
			
	
	
		
			193 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			193 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// 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 <pre> blocks
							 | 
						||
| 
								 | 
							
								//	- blank lines become <p> marks
							 | 
						||
| 
								 | 
							
								//	- "quoted strings" become <code>quoted strings</code>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								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("<pre>");
							 | 
						||
| 
								 | 
							
									preEnd = strings.Bytes("</pre>\n");
							 | 
						||
| 
								 | 
							
									pp = strings.Bytes("<p>\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 <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();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// return 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]);
							 | 
						||
| 
								 | 
							
										n++;
							 | 
						||
| 
								 | 
							
										i++;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									buf.WriteString("</pre>\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("<h2>" + string(trim(lines[i-1])) + "</h2>\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("</code>")
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												buf.WriteString("<code>")
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											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];
							 | 
						||
| 
								 | 
							
								}
							 |