Blackfriday Markdown Processor Available at http://github.com/russross/blackfriday Copyright © 2011 Russ Ross <russ@russross.com>. Distributed under the Simplified BSD License. See README.md for details.
SmartyPants rendering

package blackfriday

import (
	
	
)
SPRenderer is a struct containing state of a Smartypants renderer.
type SPRenderer struct {
	inSingleQuote bool
	inDoubleQuote bool
	callbacks     [256]smartCallback
}

func ( byte) bool {
	return  == 0 || isspace() || ispunct()
}

func ( byte) byte {
	if  >= 'A' &&  <= 'Z' {
		return  - 'A' + 'a'
	}
	return 
}

func ( byte) bool {
	return  >= '0' &&  <= '9'
}

edge of the buffer is likely to be a tag that we don't get to see, so we treat it like text sometimes
enumerate all sixteen possibilities for (previousChar, nextChar) each can be one of {0, space, punct, other}
	switch {
context is not any help here, so toggle
		* = !*
[ "] might be [ "<code>foo...]
		* = true
[!"] hmm... could be [Run!"] or [("<code>...]
		* = false
[a"] is probably a close
		* = false
[" ] might be [...foo</code>" ]
		* = false
[ " ] context is not any help here, so toggle
		* = !*
[!" ] is probably a close
		* = false
[a" ] this is one of the easy cases
		* = false
["!] hmm... could be ["$1.95] or [</code>"!...]
		* = false
[ "!] looks more like [ "$1.95]
		* = true
[!"!] context is not any help here, so toggle
		* = !*
[a"!] is probably a close
		* = false
["a] is probably an open
		* = true
[ "a] this is one of the easy cases
		* = true
[!"a] is probably an open
		* = true
[a'b] maybe a contraction?
		* = false
	}
Note that with the limited lookahead, this non-breaking space will also be appended to single double quotes.
	if  && !* {
		.WriteString("&nbsp;")
	}

	.WriteByte('&')
	if * {
		.WriteByte('l')
	} else {
		.WriteByte('r')
	}
	.WriteByte()
	.WriteString("quo;")

	if  && * {
		.WriteString("&nbsp;")
	}

	return true
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 2 {
		 := tolower([1])

		if  == '\'' {
			 := byte(0)
			if len() >= 3 {
				 = [2]
			}
			if smartQuoteHelper(, , , 'd', &.inDoubleQuote, false) {
				return 1
			}
		}

		if ( == 's' ||  == 't' ||  == 'm' ||  == 'd') && (len() < 3 || wordBoundary([2])) {
			.WriteString("&rsquo;")
			return 0
		}

		if len() >= 3 {
			 := tolower([2])

			if (( == 'r' &&  == 'e') || ( == 'l' &&  == 'l') || ( == 'v' &&  == 'e')) &&
				(len() < 4 || wordBoundary([3])) {
				.WriteString("&rsquo;")
				return 0
			}
		}
	}

	 := byte(0)
	if len() > 1 {
		 = [1]
	}
	if smartQuoteHelper(, , , 's', &.inSingleQuote, false) {
		return 0
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 3 {
		 := tolower([1])
		 := tolower([2])

		if  == 'c' &&  == ')' {
			.WriteString("&copy;")
			return 2
		}

		if  == 'r' &&  == ')' {
			.WriteString("&reg;")
			return 2
		}

		if len() >= 4 &&  == 't' &&  == 'm' && [3] == ')' {
			.WriteString("&trade;")
			return 3
		}
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 2 {
		if [1] == '-' {
			.WriteString("&mdash;")
			return 1
		}

		if wordBoundary() && wordBoundary([1]) {
			.WriteString("&ndash;")
			return 0
		}
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 3 && [1] == '-' && [2] == '-' {
		.WriteString("&mdash;")
		return 2
	}
	if len() >= 2 && [1] == '-' {
		.WriteString("&ndash;")
		return 1
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte,  byte,  bool) int {
	if bytes.HasPrefix(, []byte("&quot;")) {
		 := byte(0)
		if len() >= 7 {
			 = [6]
		}
		if smartQuoteHelper(, , , , &.inDoubleQuote, ) {
			return 5
		}
	}

	if bytes.HasPrefix(, []byte("&#0;")) {
		return 3
	}

	.WriteByte('&')
	return 0
}

func ( *SPRenderer) (,  bool) func(*bytes.Buffer, byte, []byte) int {
	var  byte = 'd'
	if  {
		 = 'a'
	}

	return func( *bytes.Buffer,  byte,  []byte) int {
		return .smartAmpVariant(, , , , )
	}
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 3 && [1] == '.' && [2] == '.' {
		.WriteString("&hellip;")
		return 2
	}

	if len() >= 5 && [1] == ' ' && [2] == '.' && [3] == ' ' && [4] == '.' {
		.WriteString("&hellip;")
		return 4
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if len() >= 2 && [1] == '`' {
		 := byte(0)
		if len() >= 3 {
			 = [2]
		}
		if smartQuoteHelper(, , , 'd', &.inDoubleQuote, false) {
			return 1
		}
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) and avoid changing dates like 1/23/2005 into fractions.
		 := 0
		for len() >  && isdigit([]) {
			++
		}
		if  == 0 {
			.WriteByte([0])
			return 0
		}
		 :=  + 1
		if len() > +3 && [] == 0xe2 && [+1] == 0x81 && [+2] == 0x84 {
			 =  + 3
		} else if len() < +2 || [] != '/' {
			.WriteByte([0])
			return 0
		}
		 := 
		for len() >  && isdigit([]) {
			++
		}
		if  ==  {
			.WriteByte([0])
			return 0
		}
		if len() ==  || wordBoundary([]) && [] != '/' {
			.WriteString("<sup>")
			.Write([:])
			.WriteString("</sup>&frasl;<sub>")
			.Write([:])
			.WriteString("</sub>")
			return  - 1
		}
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	if wordBoundary() &&  != '/' && len() >= 3 {
		if [0] == '1' && [1] == '/' && [2] == '2' {
			if len() < 4 || wordBoundary([3]) && [3] != '/' {
				.WriteString("&frac12;")
				return 2
			}
		}

		if [0] == '1' && [1] == '/' && [2] == '4' {
			if len() < 4 || wordBoundary([3]) && [3] != '/' || (len() >= 5 && tolower([3]) == 't' && tolower([4]) == 'h') {
				.WriteString("&frac14;")
				return 2
			}
		}

		if [0] == '3' && [1] == '/' && [2] == '4' {
			if len() < 4 || wordBoundary([3]) && [3] != '/' || (len() >= 6 && tolower([3]) == 't' && tolower([4]) == 'h' && tolower([5]) == 's') {
				.WriteString("&frac34;")
				return 2
			}
		}
	}

	.WriteByte([0])
	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte,  byte) int {
	 := byte(0)
	if len() > 1 {
		 = [1]
	}
	if !smartQuoteHelper(, , , , &.inDoubleQuote, false) {
		.WriteString("&quot;")
	}

	return 0
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	return .smartDoubleQuoteVariant(, , , 'd')
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	return .smartDoubleQuoteVariant(, , , 'a')
}

func ( *SPRenderer) ( *bytes.Buffer,  byte,  []byte) int {
	 := 0

	for  < len() && [] != '>' {
		++
	}

	.Write([:+1])
	return 
}

type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
NewSmartypantsRenderer constructs a Smartypants renderer object.
func ( HTMLFlags) *SPRenderer {
	var (
		 SPRenderer

		      = .smartAmp(true, false)
		  = .smartAmp(true, true)
		     = .smartAmp(false, false)
		 = .smartAmp(false, true)

		 = &SmartypantsQuotesNBSP != 0
	)

	if &SmartypantsAngledQuotes == 0 {
		.callbacks['"'] = .smartDoubleQuote
		if ! {
			.callbacks['&'] = 
		} else {
			.callbacks['&'] = 
		}
	} else {
		.callbacks['"'] = .smartAngledDoubleQuote
		if ! {
			.callbacks['&'] = 
		} else {
			.callbacks['&'] = 
		}
	}
	.callbacks['\''] = .smartSingleQuote
	.callbacks['('] = .smartParens
	if &SmartypantsDashes != 0 {
		if &SmartypantsLatexDashes == 0 {
			.callbacks['-'] = .smartDash
		} else {
			.callbacks['-'] = .smartDashLatex
		}
	}
	.callbacks['.'] = .smartPeriod
	if &SmartypantsFractions == 0 {
		.callbacks['1'] = .smartNumber
		.callbacks['3'] = .smartNumber
	} else {
		for  := '1';  <= '9'; ++ {
			.callbacks[] = .smartNumberGeneric
		}
	}
	.callbacks['<'] = .smartLeftAngle
	.callbacks['`'] = .smartBacktick
	return &
}
Process is the entry point of the Smartypants renderer.
func ( *SPRenderer) ( io.Writer,  []byte) {
	 := 0
	for  := 0;  < len(); ++ {
		if  := .callbacks[[]];  != nil {
			if  >  {
				.Write([:])
			}
			 := byte(0)
			if  > 0 {
				 = [-1]
			}
			var  bytes.Buffer
			 += (&, , [:])
			.Write(.Bytes())
			 =  + 1
		}
	}
	if  < len() {
		.Write([:])
	}