2011-05-29 11:17:53 +08:00
|
|
|
//
|
2011-06-28 10:11:32 +08:00
|
|
|
// Blackfriday Markdown Processor
|
|
|
|
// Available at http://github.com/russross/blackfriday
|
|
|
|
//
|
|
|
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
|
|
|
// Licensed under the Simplified BSD License.
|
|
|
|
// See README.md for details.
|
2011-05-29 11:17:53 +08:00
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Example front-end for command-line use
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2011-06-29 00:58:37 +08:00
|
|
|
"bytes"
|
2011-06-25 01:50:03 +08:00
|
|
|
"flag"
|
2011-05-29 11:17:53 +08:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2011-05-29 12:50:33 +08:00
|
|
|
"github.com/russross/blackfriday"
|
2011-05-29 11:17:53 +08:00
|
|
|
"os"
|
2011-06-25 07:13:42 +08:00
|
|
|
"runtime/pprof"
|
2011-05-29 11:17:53 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2011-06-25 01:50:03 +08:00
|
|
|
// parse command-line options
|
|
|
|
var page, xhtml, latex, smartypants bool
|
2011-06-25 07:13:42 +08:00
|
|
|
var css, cpuprofile string
|
2011-06-25 01:50:03 +08:00
|
|
|
var repeat int
|
|
|
|
flag.BoolVar(&page, "page", false,
|
|
|
|
"Generate a standalone HTML page (implies -latex=false)")
|
|
|
|
flag.BoolVar(&xhtml, "xhtml", true,
|
|
|
|
"Use XHTML-style tags in HTML output")
|
|
|
|
flag.BoolVar(&latex, "latex", false,
|
|
|
|
"Generate LaTeX output instead of HTML")
|
|
|
|
flag.BoolVar(&smartypants, "smartypants", false,
|
|
|
|
"Apply smartypants-style substitutions")
|
|
|
|
flag.StringVar(&css, "css", "",
|
|
|
|
"Link to a CSS stylesheet (implies -page)")
|
2011-06-25 07:13:42 +08:00
|
|
|
flag.StringVar(&cpuprofile, "cpuprofile", "",
|
|
|
|
"Write cpu profile to a file")
|
2011-06-25 01:50:03 +08:00
|
|
|
flag.IntVar(&repeat, "repeat", 1,
|
|
|
|
"Process the input multiple times (for benchmarking)")
|
|
|
|
flag.Usage = func() {
|
|
|
|
fmt.Fprintf(os.Stderr, "Usage:\n"+
|
|
|
|
" %s [options] [inputfile [outputfile]]\n\n"+
|
2011-06-29 00:58:37 +08:00
|
|
|
"Options:\n",os.Args[0])
|
2011-06-25 01:50:03 +08:00
|
|
|
flag.PrintDefaults()
|
|
|
|
}
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
// enforce implied options
|
|
|
|
if css != "" {
|
|
|
|
page = true
|
|
|
|
}
|
|
|
|
if page {
|
|
|
|
latex = false
|
|
|
|
}
|
|
|
|
|
2011-06-25 07:13:42 +08:00
|
|
|
// turn on profiling?
|
|
|
|
if cpuprofile != "" {
|
|
|
|
f, err := os.Create(cpuprofile)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
|
|
|
|
2011-05-29 11:17:53 +08:00
|
|
|
// read the input
|
|
|
|
var input []byte
|
|
|
|
var err os.Error
|
2011-06-25 01:50:03 +08:00
|
|
|
args := flag.Args()
|
|
|
|
switch len(args) {
|
|
|
|
case 0:
|
2011-05-29 11:17:53 +08:00
|
|
|
if input, err = ioutil.ReadAll(os.Stdin); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, "Error reading from Stdin:", err)
|
|
|
|
os.Exit(-1)
|
|
|
|
}
|
2011-06-25 01:50:03 +08:00
|
|
|
case 1, 2:
|
|
|
|
if input, err = ioutil.ReadFile(args[0]); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, "Error reading from", args[0], ":", err)
|
2011-05-29 11:17:53 +08:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
default:
|
2011-06-25 01:50:03 +08:00
|
|
|
flag.Usage()
|
2011-05-29 11:17:53 +08:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// set up options
|
|
|
|
var extensions uint32
|
|
|
|
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
|
|
|
|
extensions |= blackfriday.EXTENSION_TABLES
|
|
|
|
extensions |= blackfriday.EXTENSION_FENCED_CODE
|
|
|
|
extensions |= blackfriday.EXTENSION_AUTOLINK
|
|
|
|
extensions |= blackfriday.EXTENSION_STRIKETHROUGH
|
|
|
|
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
|
|
|
|
|
2011-06-25 01:50:03 +08:00
|
|
|
var renderer *blackfriday.Renderer
|
|
|
|
if latex {
|
|
|
|
// render the data into LaTeX
|
|
|
|
renderer = blackfriday.LatexRenderer(0)
|
|
|
|
} else {
|
|
|
|
// render the data into HTML
|
|
|
|
html_flags := 0
|
|
|
|
if xhtml {
|
|
|
|
html_flags |= blackfriday.HTML_USE_XHTML
|
|
|
|
}
|
|
|
|
if smartypants {
|
|
|
|
html_flags |= blackfriday.HTML_USE_SMARTYPANTS
|
|
|
|
html_flags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
|
|
|
|
html_flags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
|
|
|
|
}
|
|
|
|
renderer = blackfriday.HtmlRenderer(html_flags)
|
|
|
|
}
|
2011-05-31 01:06:20 +08:00
|
|
|
|
2011-06-25 01:50:03 +08:00
|
|
|
// parse and render
|
|
|
|
var output []byte
|
|
|
|
for i := 0; i < repeat; i++ {
|
|
|
|
output = blackfriday.Markdown(input, renderer, extensions)
|
|
|
|
}
|
2011-05-29 11:17:53 +08:00
|
|
|
|
|
|
|
// output the result
|
2011-06-25 01:50:03 +08:00
|
|
|
var out *os.File
|
|
|
|
if len(args) == 2 {
|
|
|
|
if out, err = os.Create(args[1]); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "Error creating %s: %v", args[1], err)
|
2011-05-29 11:17:53 +08:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
2011-06-25 01:50:03 +08:00
|
|
|
defer out.Close()
|
2011-05-29 11:17:53 +08:00
|
|
|
} else {
|
2011-06-25 01:50:03 +08:00
|
|
|
out = os.Stdout
|
|
|
|
}
|
|
|
|
|
|
|
|
if page {
|
2011-06-29 00:58:37 +08:00
|
|
|
// if it starts with an <h1>, make that the title
|
|
|
|
title := ""
|
|
|
|
if bytes.HasPrefix(output, []byte("<h1>")) {
|
|
|
|
end := 0
|
|
|
|
// we know the buffer ends with a newline, so no need to check bounds
|
|
|
|
for output[end] != '\n' {
|
|
|
|
end++
|
|
|
|
}
|
|
|
|
if bytes.HasSuffix(output[:end], []byte("</h1>")) {
|
|
|
|
title = string(output[len("<h1>") : end-len("</h1>")])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-25 01:50:03 +08:00
|
|
|
ending := ""
|
|
|
|
if xhtml {
|
|
|
|
fmt.Fprint(out, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
|
|
|
|
fmt.Fprintln(out, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
|
|
|
|
fmt.Fprintln(out, "<html xmlns=\"http://www.w3.org/1999/xhtml\">")
|
|
|
|
ending = " /"
|
|
|
|
} else {
|
|
|
|
fmt.Fprint(out, "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" ")
|
|
|
|
fmt.Fprintln(out, "\"http://www.w3.org/TR/html4/strict.dtd\">")
|
|
|
|
fmt.Fprintln(out, "<html>")
|
2011-05-29 11:17:53 +08:00
|
|
|
}
|
2011-06-25 01:50:03 +08:00
|
|
|
fmt.Fprintln(out, "<head>")
|
2011-06-29 00:58:37 +08:00
|
|
|
fmt.Fprintf(out, " <title>%s</title>\n", title)
|
2011-06-25 01:50:03 +08:00
|
|
|
fmt.Fprintf(out, " <meta name=\"GENERATOR\" content=\"Blackfriday markdown processor\"%s>\n", ending)
|
|
|
|
fmt.Fprintf(out, " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"%s>\n", ending)
|
|
|
|
if css != "" {
|
|
|
|
fmt.Fprintf(out, " <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n", css)
|
|
|
|
}
|
|
|
|
fmt.Fprintln(out, "</head>")
|
|
|
|
fmt.Fprintln(out, "<body>")
|
|
|
|
}
|
|
|
|
if _, err = out.Write(output); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, "Error writing output:", err)
|
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
if page {
|
|
|
|
fmt.Fprintln(out, "</body>")
|
|
|
|
fmt.Fprintln(out, "</html>")
|
2011-05-29 11:17:53 +08:00
|
|
|
}
|
|
|
|
}
|