2 #// converts bbcode to html.
\r
5 #// Copyright (C) 2015 Balthasar SzczepaĆski
\r
7 #// This program is free software: you can redistribute it and/or modify
\r
8 #// it under the terms of the GNU Affero General Public License as
\r
9 #// published by the Free Software Foundation, either version 3 of the
\r
10 #// License, or (at your option) any later version.
\r
12 #// This program is distributed in the hope that it will be useful,
\r
13 #// but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 #// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 #// GNU Affero General Public License for more details.
\r
17 #// You should have received a copy of the GNU Affero General Public License
\r
18 #// along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
22 debug="debug=bb2html.awk:"
\r
26 argtab[substr($0,1,eq-1)]=substr($0,eq+1)
\r
29 if(argtab["disable_bbcode"]!="")
\r
31 debug=debug"###nl;BBcode disabled"
\r
32 print debug>>outfile
\r
37 print "HTML="html>>outfile
\r
38 print debug>>outfile
\r
41 function bb2html(text, depth,count,bbtree,html,tag,tagstart,taglength,elm,tagv,tagname,tagvalue,matchname)
\r
47 bbtree["0.t"]="post"
\r
48 bbtree["0.v"]=argtab["subject"]
\r
50 gsub(/=/,"=",text)
\r
51 debug = debug "###nl;###nl;Build BBcode tree:"
\r
52 while(length(text)!=0)
\r
54 tag=match(text, /\[\/?[a-z0-9\*]+(=(([^\[<>\"\]]*)|(\"[^\"<>]*\")))?\]/)
\r
56 # debug = debug "###nl;" RSTART " " RLENGTH
\r
59 debug = debug "###nl;text: " text
\r
60 bbtree[ind(count,depth)]=text
\r
61 bbtree[indt(count,depth)".n"]=count[depth]
\r
70 elm=substr(text,1,tagstart-1)
\r
71 debug = debug "###nl;text: " elm
\r
72 bbtree[ind(count,depth)]=elm
\r
73 bbtree[indt(count,depth)".n"]=count[depth]
\r
76 tag=substr(text,tagstart,taglength)
\r
77 text=substr(text,tagstart+taglength)
\r
78 debug = debug "###nl;tag: " tag
\r
84 tagname=substr(tag,2,length(tag)-2)
\r
89 tagname=substr(tag,2,tagv-2)
\r
90 tagvalue=substr(tag,tagv+1,length(tag)-tagv-1)
\r
92 if(tagname !~ /^((quote)|b|i|u|(code)|(img)|(url)|(size)|(color)|(center)|(right)|(sub)|(sup)|(s)|(spoiler)|(list)|(\*))$/)
\r
94 debug = debug "###nl;unknown tag"
\r
95 bbtree[ind(count,depth)]=tag
\r
96 bbtree[indt(count,depth)".n"]=count[depth]
\r
100 if((bbtree[indt(count,depth)".t"] == "code" && tagname!="code")||bbtree[indt(count,depth)".t"] == "img"||(bbtree[indt(count,depth)".t"] == "size" && tagname=="size"))
\r
102 debug = debug "###nl;this tag forbidden here"
\r
103 bbtree[ind(count,depth)]=tag
\r
104 bbtree[indt(count,depth)".n"]=count[depth]
\r
110 if(bbtree[indt(count,depth)".t"]==tagname)
\r
112 debug = debug "###nl;implied tag: [/"tagname"]"
\r
113 debug = debug "###nl;matched"
\r
114 bbtree[ind(count,depth)]="[/"tagname"]"
\r
115 bbtree[ind(count,depth)".k"]="e"
\r
116 bbtree[ind(count,depth)".m"]=1
\r
117 bbtree[ind(count,depth)".t"]=tagname
\r
118 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
\r
119 bbtree[indt(count,depth)".n"]=count[depth]
\r
120 bbtree[indt(count,depth)".m"]=1
\r
125 else if(bbtree[indt(count,depth)".t"]!="list")
\r
127 debug = debug "###nl;this tag forbidden here"
\r
128 bbtree[ind(count,depth)]=tag
\r
129 bbtree[indt(count,depth)".n"]=count[depth]
\r
134 debug = debug "###nl;name: " tagname " value: " tagvalue
\r
135 bbtree[ind(count,depth)]=tagname" "tagvalue
\r
136 bbtree[ind(count,depth)".k"]="s"
\r
137 bbtree[indt(count,depth)".n"]=count[depth]
\r
140 bbtree[indt(count,depth)]=tag
\r
141 bbtree[indt(count,depth)".n"]=0
\r
142 bbtree[indt(count,depth)".t"]=tagname
\r
143 bbtree[indt(count,depth)".v"]=tagvalue
\r
149 debug = debug "###nl;""unmatched"
\r
150 bbtree[ind(count,depth)]=tag
\r
151 bbtree[indt(count,depth)".n"]=count[depth]
\r
155 tagname=substr(tag,3,length(tag)-3)
\r
156 if(tagname=="list"&&bbtree[indt(count,depth)".t"]=="*")
\r
158 debug = debug "###nl;implied tag: [/*]"
\r
159 debug = debug "###nl;matched"
\r
160 bbtree[ind(count,depth)]="[/*]"
\r
161 bbtree[ind(count,depth)".k"]="e"
\r
162 bbtree[ind(count,depth)".m"]=1
\r
163 bbtree[ind(count,depth)".t"]="*"
\r
164 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
\r
165 bbtree[indt(count,depth)".n"]=count[depth]
\r
166 bbtree[indt(count,depth)".m"]=1
\r
171 debug = debug "###nl;name: " tagname
\r
172 matchname=bbtree[indt(count,depth)".t"]
\r
173 if((bbtree[indt(count,depth)".t"] == "code" && tagname!="code")||(bbtree[indt(count,depth)".t"] == "img" && tagname != "img"))
\r
175 debug = debug "###nl;this tag forbidden here"
\r
176 bbtree[ind(count,depth)]=tag
\r
177 bbtree[indt(count,depth)".n"]=count[depth]
\r
181 if(tagname!=matchname)
\r
183 debug = debug "###nl;mismatched: " matchname
\r
184 # bbtree[ind(count,depth)]=tag
\r
185 # bbtree[indt(count,depth)".n"]=count[depth]
\r
188 bbtree[ind(count,depth)]=tag
\r
189 bbtree[ind(count,depth)".k"]="e"
\r
190 bbtree[ind(count,depth)".t"]=bbtree[indt(count,depth)".t"]
\r
191 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
\r
192 bbtree[indt(count,depth)".n"]=count[depth]
\r
198 debug = debug "###nl;matched"
\r
199 bbtree[ind(count,depth)]=tag
\r
200 bbtree[ind(count,depth)".k"]="e"
\r
201 bbtree[ind(count,depth)".m"]=1
\r
202 bbtree[ind(count,depth)".t"]=tagname
\r
203 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
\r
204 bbtree[indt(count,depth)".n"]=count[depth]
\r
205 bbtree[indt(count,depth)".m"]=1
\r
212 debug = debug "###nl;unclosed tags: " depth
\r
214 debug = debug "###nl;###nl;""generate HTML:"
\r
217 while(count[0]<=bbtree["0.n"]&&depth>=0)
\r
219 if(count[depth]==0)
\r
221 tag=bbtree[indt(count,depth)]
\r
222 tagname=bbtree[indt(count,depth)".t"]
\r
223 tagvalue=bbtree[indt(count,depth)".v"]
\r
224 debug = debug "###nl;name: "tagname" value: "tagvalue" elements: "bbtree[indt(count,depth)".n"]
\r
225 if(tagname == "post")
\r
228 else if(bbtree[indt(count,depth)".m"]=="")
\r
230 debug = debug "###nl;unmatched"
\r
233 else if(tagname == "quote")
\r
237 html = html "<blockquote class=\"pq\"><div>"
\r
241 if(tagvalue !~ /^\".*\"$/)
\r
243 tagvalue="You forgot about the quote marks, "tagvalue
\r
245 tagvalue=bb2html(substr(tagvalue,2,length(tagvalue)-2))
\r
246 html = html "<blockquote class=\"pq\"><div><cite class=\"pq\"><b class=\"br\">"tagvalue"</b> wrote:</cite><br>"
\r
249 else if (tagname == "b")
\r
251 html = html"<span style=\"font-weight: bold\">"
\r
253 html=html"This tag shouldn't have any value. "
\r
255 else if (tagname == "i")
\r
257 html = html"<span style=\"font-style: italic\">"
\r
259 html=html"This tag shouldn't have any value. "
\r
261 else if (tagname == "u")
\r
263 html = html"<span style=\"text-decoration: underline\">"
\r
265 html=html"This tag shouldn't have any value. "
\r
267 else if (tagname == "code")
\r
269 if(bbtree[indtu(count,depth)".t"] == "code")
\r
272 debug = debug "###nl;not a tag, actually"
\r
276 html=html"<dl class=\"pq\"><dt class=\"pq\">Code: <a href=\"#\" onclick=\"selectCode(this); return false;\">Select all</a></dt><dd><code class=\"pq\">"
\r
278 html=html"This tag shouldn't have any value. "
\r
281 else if (tagname == "img")
\r
282 html=html"<img src=\""
\r
283 else if (tagname == "url")
\r
288 tagvalue=bbtree[ind(count,depth)]
\r
290 debug = debug "###nl;implied value: " tagvalue
\r
292 html=html"<a href=\""tagvalue"\" class=\"postlink\">"
\r
294 else if (tagname == "size")
\r
296 if (tagvalue==""||(tagvalue !~ /^[0-9]+$/)||(tagvalue+0)>200)
\r
297 html=html"<span style=\"font-size: 130%; line-height: 116%;\"> This tag should have a correct value. "
\r
299 html=html"<span style=\"font-size: "tagvalue"%; line-height: 116%;\">"
\r
301 else if (tagname == "color")
\r
303 if (tagvalue==""||tagvalue !~ /^#[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/) #for some reason /^([0-9A-F]{6})$/ doesn't work.
\r
304 html=html"<span style=\"color: #EE0000\"> This tag should have a correct value. "
\r
306 html=html"<span style=\"color: "tagvalue"\">"
\r
308 else if (tagname ~ /^((center)|(right))$/)
\r
310 html=html"<div align=\""tagname"\">"
\r
312 html=html"This tag shouldn't have any value. "
\r
314 else if (tagname =="s")
\r
316 html=html"<strike>"
\r
318 html=html"This tag shouldn't have any value. "
\r
320 else if (tagname =="sub")
\r
324 html=html"This tag shouldn't have any value. "
\r
326 else if (tagname =="sup")
\r
330 html=html"This tag shouldn't have any value. "
\r
332 else if (tagname=="spoiler")
\r
334 html=html"<div style=\"margin:20px; margin-top:5px\"><div class=\"quotetitle\"><b>Spoiler:</b> <input type=\"button\" class=\"pk\" value=\"Show\" style=\"width:45px;font-size:10px;margin:0px;padding:0px;\" onclick=\"if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = 'Hide'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = 'Show'; }\" /></div><div class=\"quotecontent\"><div style=\"display: none;\">"
\r
336 html=html"This tag shouldn't have any value. "
\r
338 else if (tagname=="list")
\r
346 else if (tagvalue=="i")
\r
347 tagvalue="lower-roman"
\r
348 else if (tagvalue=="I")
\r
349 tagvalue="upper-roman"
\r
350 else if (tagvalue=="a")
\r
351 tagvalue="lower-alpha"
\r
352 else if (tagvalue=="A")
\r
353 tagvalue="upper-alpha"
\r
356 html=html"This tag should have a correct value. "
\r
359 html=html"<ol style=\"list-style-type: "tagvalue"\">"
\r
362 else if (tagname=="*")
\r
366 html=html"This tag shouldn't have any value. "
\r
370 debug = debug "###nl;unknown tag"
\r
375 else if(bbtree[ind(count,depth)".k"]=="s")
\r
377 debug = debug "###nl;entering tag:"
\r
381 else if(bbtree[ind(count,depth)".k"]=="e")
\r
383 debug = debug "###nl;leaving tag:"
\r
384 tag=bbtree[ind(count,depth)]
\r
385 tagname=bbtree[ind(count,depth)".t"]
\r
386 tagvalue=bbtree[ind(count,depth)".v"]
\r
387 debug = debug "###nl;name: "tagname" value: "tagvalue
\r
388 if (tagname == "post")
\r
391 else if(bbtree[ind(count,depth)".m"]=="")
\r
393 debug = debug "###nl;unmatched"
\r
396 else if(tagname == "quote")
\r
397 html = html "</div></blockquote>"
\r
398 else if (tagname ~/^(b|i|u|(size)|(color))$/)
\r
399 html = html"</span>"
\r
400 else if (tagname == "code")
\r
402 if(bbtree[indtu(count,depth)".t"] == "code")
\r
405 debug = debug "###nl;not a tag, actually"
\r
408 html = html"</code></dd></dl>"
\r
410 else if (tagname == "img")
\r
412 html = html"\" alt=\"Image\" />"
\r
414 html=html"This tag shouldn't have any value. "
\r
416 else if(tagname=="url")
\r
418 else if (tagname ~ /^((center)|(right))$/)
\r
420 else if (tagname =="s")
\r
421 html=html"</strike>"
\r
422 else if (tagname =="sub")
\r
424 else if (tagname =="sup")
\r
426 else if (tagname=="spoiler")
\r
427 html=html"</div></div></div>"
\r
428 else if (tagname=="list")
\r
435 else if (tagname=="*")
\r
439 debug = debug "###nl;unknown tag"
\r
446 else if(count[depth]>bbtree[indt(count,depth)".n"])
\r
448 debug = debug "###nl;run out of elements in this tag; leaving"
\r
455 tag=bbtree[ind(count,depth)]
\r
456 debug = debug "###nl;text: "tag
\r
457 if(bbtree[indt(count,depth)".t"] == "code")
\r
459 # gsub(/ ?<br> ?/,"<br>",tag)
\r
460 gsub(/ /,"\\ ",tag)
\r
461 gsub(/\t/,"\\ \\ ",tag)
\r
463 if(argtab["disable_magic_url"]==""&& bbtree[indt(count,depth)".t"] !~ /^((code)|(img)|(url))$/)
\r
464 gsub(/https?:\/\/[^\n\r\t<> ]+/,"<a href=\"&\" class=\"postlink\">&</a>",tag)
\r
465 if(argtab["disable_smilies"]=="" && bbtree[indt(count,depth)".t"] !~ /^((code)|(img))$/)
\r
467 gsub(/(^|[\n\r\t ]):D($|[\n\r\t ])/," <img title=\"Very Happy\" alt=\":D\" src=\"/ott/prosilver/smilies/icon_biggrin.gif\" /> ",tag)
\r
468 gsub(/(^|[\n\r\t ]):\)($|[\n\r\t ])/," <img title=\"Smile\" alt=\":)\" src=\"/ott/prosilver/smilies/icon_smile.gif\" /> ",tag)
\r
469 gsub(/(^|[\n\r\t ]):\(($|[\n\r\t ])/," <img title=\"Sad\" alt=\":(\" src=\"/ott/prosilver/smilies/icon_sad.gif\" /> ",tag)
\r
470 gsub(/(^|[\n\r\t ]):o($|[\n\r\t ])/," <img title=\"Surprised\" alt=\":o\" src=\"/ott/prosilver/smilies/icon_surprised.gif\" /> ",tag)
\r
471 gsub(/(^|[\n\r\t ]):shock:($|[\n\r\t ])/," <img title=\"Shocked\" alt=\":shock:\" src=\"/ott/prosilver/smilies/icon_eek.gif\" /> ",tag)
\r
472 gsub(/(^|[\n\r\t ]):\?($|[\n\r\t ])/," <img title=\"Confused\" alt=\":?\" src=\"/ott/prosilver/smilies/icon_confused.gif\" /> ",tag)
\r
473 gsub(/(^|[\n\r\t ])8-\)($|[\n\r\t ])/," <img title=\"Cool\" alt=\"8-)\" src=\"/ott/prosilver/smilies/icon_cool.gif\" /> ",tag)
\r
474 gsub(/(^|[\n\r\t ]):lol:($|[\n\r\t ])/," <img title=\"Laughing\" alt=\":lol:\" src=\"/ott/prosilver/smilies/icon_lol.gif\" /> ",tag)
\r
475 gsub(/(^|[\n\r\t ]):x($|[\n\r\t ])/," <img title=\"Mad\" alt=\":x\" src=\"/ott/prosilver/smilies/icon_mad.gif\" /> ",tag)
\r
476 gsub(/(^|[\n\r\t ]):P($|[\n\r\t ])/," <img title=\"Razz\" alt=\":P\" src=\"/ott/prosilver/smilies/icon_razz.gif\" /> ",tag)
\r
477 gsub(/(^|[\n\r\t ]):oops:($|[\n\r\t ])/," <img title=\"Embarassed\" alt=\":oops:\" src=\"/ott/prosilver/smilies/icon_redface.gif\" /> ",tag)
\r
478 gsub(/(^|[\n\r\t ]):cry:($|[\n\r\t ])/," <img title=\"Crying or Very Sad\" alt=\":cry:\" src=\"/ott/prosilver/smilies/icon_cry.gif\" /> ",tag)
\r
479 gsub(/(^|[\n\r\t ]):evil:($|[\n\r\t ])/," <img title=\"Evil or Very Mad\" alt=\":evil:\" src=\"/ott/prosilver/smilies/icon_evil.gif\" /> ",tag)
\r
480 gsub(/(^|[\n\r\t ]):twisted:($|[\n\r\t ])/," <img title=\"Twisted Evil\" alt=\":twisted:\" src=\"/ott/prosilver/smilies/icon_twisted.gif\" /> ",tag)
\r
481 gsub(/(^|[\n\r\t ]):roll:($|[\n\r\t ])/," <img title=\"Rolling Eyes\" alt=\":roll:\" src=\"/ott/prosilver/smilies/icon_rolleyes.gif\" /> ",tag)
\r
482 gsub(/(^|[\n\r\t ]):wink:($|[\n\r\t ])/," <img title=\"Wink\" alt=\":wink:\" src=\"/ott/prosilver/smilies/icon_wink.gif\" /> ",tag)
\r
483 gsub(/(^|[\n\r\t ]);\)($|[\n\r\t ])/," <img title=\"Wink\" alt=\":wink:\" src=\"/ott/prosilver/smilies/icon_wink.gif\" /> ",tag)
\r
484 gsub(/(^|[\n\r\t ]):!:($|[\n\r\t ])/," <img title=\"Exclamation\" alt=\":!:\" src=\"/ott/prosilver/smilies/icon_exclaim.gif\" /> ",tag)
\r
485 gsub(/(^|[\n\r\t ]):\?:($|[\n\r\t ])/," <img title=\"Question\" alt=\":?:\" src=\"/ott/prosilver/smilies/icon_question.gif\" /> ",tag)
\r
486 gsub(/(^|[\n\r\t ]):idea:($|[\n\r\t ])/," <img title=\"Idea\" alt=\":idea:\" src=\"/ott/prosilver/smilies/icon_idea.gif\" /> ",tag)
\r
487 gsub(/(^|[\n\r\t ]):arrow:($|[\n\r\t ])/," <img title=\"Arrow\" alt=\":arrow:\" src=\"/ott/prosilver/smilies/icon_arrow.gif\" /> ",tag)
\r
488 gsub(/(^|[\n\r\t ]):\|($|[\n\r\t ])/," <img title=\"Neutral\" alt=\":|\" src=\"/ott/prosilver/smilies/icon_neutral.gif\" /> ",tag)
\r
489 gsub(/(^|[\n\r\t ]):mrgreen:($|[\n\r\t ])/," <img title=\"Mr. Green\" alt=\":mrgreen:\" src=\"/ott/prosilver/smilies/icon_mrgreen.gif\" /> ",tag)
\r
496 debug = debug "###nl;done"
\r
500 function ind(count,depth, ii,iindex)
\r
503 for(ii=0;ii<=depth;++ii)
\r
506 iindex = iindex "."
\r
507 iindex = iindex count[ii]
\r
509 # debug = debug "###nl;" iindex
\r
512 function indt(count,depth, ii,iindex)
\r
515 for(ii=0;ii<depth;++ii)
\r
518 iindex = iindex "."
\r
519 iindex = iindex count[ii]
\r
523 iindex = iindex "0"
\r
524 # debug = debug "###nl;" iindex
\r
527 function indtu(count,depth, ii,iindex)
\r
530 for(ii=0;ii<depth-1;++ii)
\r
533 iindex = iindex "."
\r
534 iindex = iindex count[ii]
\r
538 iindex = iindex "0"
\r
539 # debug = debug "###nl;" iindex
\r