1 // Package bbcode implements a bbcode parser and converter 2 package bbcode // import "vimagination.zapto.org/bbcode" 3 4 import ( 5 "io" 6 7 "vimagination.zapto.org/parser" 8 ) 9 10 // Config changes how the syntax of the interpreted bbCode. 11 type Config struct { 12 // TagOpen is the character used to open the tags. 13 // In the default configuration this is the open bracket '['. 14 TagOpen rune 15 16 // TagClose is the character used to close the tags. 17 // In the default configuration this is the close bracket ']'. 18 TagClose rune 19 20 // ClosingTag is the character used to define a closing tag, as opposed 21 // to an opening tag. 22 // In the default configuration, this is the slash '/'. 23 ClosingTag rune 24 25 // AttributeSep is the character used to separate the tag name from the 26 // attribute. 27 // In the default configuration this is the equals sign '='. 28 AttributeSep rune 29 30 // ValidTagName lists the characters that are allowed in the tag names. 31 // Neither of the TagClose or AttributeSep characters should be in this 32 // list. 33 // In the default configuration this is A-Z a-z 0-9 and the asterisk. 34 ValidTagName string 35 } 36 37 var defaultConfig = Config{ 38 TagOpen: '[', 39 TagClose: ']', 40 ClosingTag: '/', 41 AttributeSep: '=', 42 ValidTagName: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*", 43 } 44 45 // BBCode is a fully configured parser. 46 type BBCode struct { 47 tks tokeniser 48 text Handler 49 tags []Handler 50 } 51 52 // NewWithConfig creates a bbCode parser with a custom bbCode configuration. 53 // The tags are a list of Handlers that will be used to process the tag tokens 54 // that are generated by the parser. 55 // The first Handler with an empty string for a name with be used to process 56 // the text. By default, this is the HTMLText handler. 57 func NewWithConfig(c Config, tags ...Handler) *BBCode { 58 var text Handler = HTMLText 59 60 for _, tag := range tags { 61 if tag.Name() == "" { 62 text = tag 63 64 break 65 } 66 } 67 68 return &BBCode{ 69 tks: getTokeniser(c), 70 text: text, 71 tags: tags, 72 } 73 } 74 75 // New create a new bbCode parser with the default configuration. 76 // See NewWithConfig for more information. 77 func New(tags ...Handler) *BBCode { 78 return NewWithConfig(defaultConfig, tags...) 79 } 80 81 // Convert parses the byte slice and writes the output to the writer. 82 // Any error will be from the writing process and not from the parser. 83 func (b *BBCode) Convert(w io.Writer, input []byte) error { 84 return b.convert(w, parser.NewByteTokeniser(input)) 85 } 86 87 // ConvertString functions like Convert, but takes a string. 88 func (b *BBCode) ConvertString(w io.Writer, input string) error { 89 return b.convert(w, parser.NewStringTokeniser(input)) 90 } 91 92 // ConvertReader functions like Convert, but takes a io.Reader. 93 func (b *BBCode) ConvertReader(w io.Writer, input io.Reader) error { 94 return b.convert(w, parser.NewReaderTokeniser(input)) 95 } 96 97 func (b *BBCode) convert(w io.Writer, t parser.Tokeniser) error { 98 p := Processor{ 99 w: w, 100 p: b.tks.getParser(t), 101 bbCode: b, 102 } 103 104 p.Process("") 105 106 return p.err 107 } 108